Common Lisp Interface Manager Release 2.0 Specification

Scott McKay (SWM@Riverside.SCRC.Symbolics.COM)
       William York (York@Fuji.ILA.COM)

with contributions by

 John Aspinall (JGA@Riverside.SCRC.Symbolics.COM)
      Dennis Doughty (Doughty@Fuji.ILA.COM)
Charles Hornig (Hornig@Riverside.SCRC.Symbolics.COM)
        Richard Lamson (RSL@Fuji.ILA.COM)
        David Linden (DCPL@Fuji.ILA.COM)
     David Moon (Moon@Cambridge.Apple.COM)
        Ramana Rao (rao@PARC.Xerox.COM)

March 18, 1992

Contents

I Overview and Conventions 1

1 Overview of CLIM 2

2 Conventions 5 2.1 Audience, Goals, and Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2 Package Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.3 “Spread” Point Arguments to Functions . . . . . . . . . . . . . . . . . . . . . . . 6 2.4 Immutability of Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 2.5 Behavior of Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.6 Protocol Classes and Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.7 Specialized Arguments to Generic Functions . . . . . . . . . . . . . . . . . . . . . 9 2.8 Sheet, Stream, or Medium Arguments to Macros . . . . . . . . . . . . . . . . . . 9 2.9 Macros that Expand into Calls to Advertised Functions . . . . . . . . . . . . . . 9 2.10 Terminology Pertaining to Error Conditions . . . . . . . . . . . . . . . . . . . . . 10

II Geometry Substrate 11

3 Geometry 12 3.1 General Regions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 CONTENTS ii

3.1.1 The Region Predicate Protocol . . . . . . . . . . . . . . . . . . . . . . . . 14 3.1.2 Region Composition Protocol . . . . . . . . . . . . . . . . . . . . . . . . . 14

3.2 Other Region Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.2.1 Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.2.2 Polygons and Polylines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2.3 Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.2.4 Rectangles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.2.5 Ellipses and Elliptical Arcs . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 Bounding Rectangles 28

4.1 Bounding Rectangles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 4.1.1 The Bounding Rectangle Protocol . . . . . . . . . . . . . . . . . . . . . . 30 4.1.2 Bounding Rectangle Convenience Functions . . . . . . . . . . . . . . . . . 31

5 Affine Transformations 33

5.1 Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

5.1.1 Transformation Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . 34 5.2 Transformation Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 5.3 The Transformation Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

5.3.1 Transformation Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 5.3.2 Composition of Transformations . . . . . . . . . . . . . . . . . . . . . . . 37 5.3.3 Applying Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

III Windowing Substrate 41

6 Overview of Window Facilities 42 6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 CONTENTS iii

6.2 Properties of Sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 6.3 Sheet Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 6.4 Sample Silica Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

7 Properties of Sheets 45

7.1 Relationships Between Sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 7.1.1 Sheet Relationship Functions . . . . . . . . . . . . . . . . . . . . . . . . . 46 7.1.2 Sheet Genealogy Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

7.2 Sheet Geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 7.2.1 Sheet Geometry Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 7.2.2 Sheet Geometry Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

7.3 Creating Sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

8 Sheet Protocols 52

8.1 Input Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 8.1.1 Input Protocol Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 8.1.2 Input Protocol Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

8.2 Standard Device Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 8.3 Output Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

8.3.1 Output Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 8.3.2 Output Protocol Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 63 8.3.3 Output Protocol Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 8.3.4 Associating a Medium with a Sheet . . . . . . . . . . . . . . . . . . . . . 63

8.4 Repaint Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 8.4.1 Repaint Protocol Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 64 8.4.2 Repaint Protocol Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 CONTENTS iv

8.5 Sheet Notification Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 8.5.1 Relationship to Window System Change Notifications . . . . . . . . . . . 66 8.5.2 Geometry Notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

9 Ports, Grafts, and Mirrored Sheets 67 9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 9.2 Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 9.3 Grafts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 9.4 Mirrors and Mirrored Sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

9.4.1 Mirror Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 9.4.2 Internal Interfaces for Native Coordinates . . . . . . . . . . . . . . . . . . 72

IV Sheet and Medium Output Facilities 74

10 Drawing Options 75 10.1 Medium Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 10.2 Drawing Option Binding Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

10.2.1 Transformation “Convenience” Forms . . . . . . . . . . . . . . . . . . . . 80 10.2.2 Establishing Local Coordinate Systems . . . . . . . . . . . . . . . . . . . 81

10.3 Line Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 10.3.1 Line Style Protocol and Line Style Suboptions . . . . . . . . . . . . . . . 82 10.3.2 Contrasting Dash Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . 84

11 Text Styles 85

11.1 Text Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85

11.1.1 Text Style Protocol and Text Style Suboptions . . . . . . . . . . . . . . . 86 11.2 Text Style Binding Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 CONTENTS v

11.3 Controlling Text Style Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

12 Graphics 91 12.1 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 12.2 Drawing is Approximate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 12.3 Rendering Conventions for Geometric Shapes . . . . . . . . . . . . . . . . . . . . 94

12.3.1 Permissible Alternatives During Rendering . . . . . . . . . . . . . . . . . 97 12.4 Drawing Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 12.5 Pixmaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 12.6 Graphics Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

12.6.1 General Behavior of Drawing Functions . . . . . . . . . . . . . . . . . . . 106 12.6.2 Medium-specific Drawing Functions . . . . . . . . . . . . . . . . . . . . . 106 12.6.3 Port-specific Drawing Functions . . . . . . . . . . . . . . . . . . . . . . . 107

13 Drawing in Color 110 13.1 The :ink Drawing Option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 13.2 Designs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 13.3 Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112

13.3.1 Standard Color Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 13.3.2 Contrasting Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

13.4 Opacity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 13.5 Color Blending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 13.6 Indirect Inks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 13.7 Flipping Ink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 13.8 Examples of Simple Drawing Effects . . . . . . . . . . . . . . . . . . . . . . . . . 118

14 Patterned Designs 119 CONTENTS vi

14.1 The Compositing Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 14.2 Patterns and Stencils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 14.3 Tiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 14.4 Regions as Designs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 14.5 Arbitrary Designs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 14.6 Examples of More Complex Drawing Effects . . . . . . . . . . . . . . . . . . . . . 125 14.7 Design Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

V Extended Stream Output Facilities 127

15 Extended Stream Output 128 15.1 Basic Output Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 15.2 Extended Output Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 15.3 The Text Cursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

15.3.1 Text Cursor Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 15.3.2 Stream Text Cursor Protocol . . . . . . . . . . . . . . . . . . . . . . . . . 134

15.4 Text Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 15.4.1 Mixing Text and Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 15.4.2 Wrapping of Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

15.5 Attracting the User’s Attention . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 15.6 Buffering of Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

16 Output Recording 139

16.1 Output Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 16.1.1 The Basic Output Record Protocol . . . . . . . . . . . . . . . . . . . . . . 141 16.1.2 The Output Record “Database” Protocol . . . . . . . . . . . . . . . . . . 143 CONTENTS vii

16.1.3 Output Record Change Notification Protocol . . . . . . . . . . . . . . . . 144 16.2 Types of Output Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

16.2.1 Standard Output Record Classes . . . . . . . . . . . . . . . . . . . . . . . 145 16.2.2 Graphics Displayed Output Records . . . . . . . . . . . . . . . . . . . . . 146 16.2.3 Text Displayed Output Record . . . . . . . . . . . . . . . . . . . . . . . . 146 16.2.4 Top-Level Output Records . . . . . . . . . . . . . . . . . . . . . . . . . . 148

16.3 Output Recording Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 16.3.1 The Output Recording Stream Protocol . . . . . . . . . . . . . . . . . . . 149 16.3.2 Graphics Output Recording . . . . . . . . . . . . . . . . . . . . . . . . . . 150 16.3.3 Text Output Recording . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 16.3.4 Output Recording Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . 151

17 Table Formatting 155 17.1 Overview of Table Formatting Facilities . . . . . . . . . . . . . . . . . . . . . . . 155 17.2 Table Formatting Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 17.3 The Table and Item List Formatting Protocols . . . . . . . . . . . . . . . . . . . 161

17.3.1 Table Formatting Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . 161 17.3.2 Row and Column Formatting Protocol . . . . . . . . . . . . . . . . . . . . 163 17.3.3 Cell Formatting Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 17.3.4 Item List Formatting Protocol . . . . . . . . . . . . . . . . . . . . . . . . 164

18 Graph Formatting 166 18.1 Graph Formatting Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 18.2 The Graph Formatting Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

19 Bordered Output 172 CONTENTS viii

20 Text Formatting 174 20.1 Textual List Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 20.2 Indented Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 20.3 Filled Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

21 Incremental Redisplay 176 21.1 Examples of Incremental Redisplay . . . . . . . . . . . . . . . . . . . . . . . . . . 177 21.2 Standard Programmer Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 21.3 Incremental Redisplay Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 21.4 Incremental Redisplay Stream Protocol . . . . . . . . . . . . . . . . . . . . . . . 184 21.5 Random Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

VI Extended Stream Input Facilities 186

22 Extended Stream Input 187 22.1 Basic Input Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 22.2 Extended Input Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

22.2.1 The Extended Input Stream Protocol . . . . . . . . . . . . . . . . . . . . 189 22.3 Gestures and Gesture Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

22.3.1 Standard Gesture Names . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 22.4 The Pointer Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 22.5 Pointer Tracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 22.6 Gesture Preprocessing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

23 Presentation Types 200

23.1 Presentations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 23.1.1 The Presentation Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 CONTENTS ix

23.2 Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 23.2.1 Defining Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . 203 23.2.2 Presentation Type Abbreviations . . . . . . . . . . . . . . . . . . . . . . . 205 23.2.3 Presentation Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 23.2.4 Presentation Type Functions . . . . . . . . . . . . . . . . . . . . . . . . . 211

23.3 Typed Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 23.4 Typed Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 23.5 Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 23.6 Presentation Translators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221

23.6.1 Defining Presentation Translators . . . . . . . . . . . . . . . . . . . . . . . 222 23.6.2 Presentation Translator Functions . . . . . . . . . . . . . . . . . . . . . . 225 23.6.3 Finding Applicable Presentations . . . . . . . . . . . . . . . . . . . . . . . 227 23.6.4 Translator Applicability . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

23.7 Standard Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 23.7.1 Basic Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 23.7.2 Numeric Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . 231 23.7.3 Character and String Presentation Types . . . . . . . . . . . . . . . . . . 231 23.7.4 Pathname Presentation Type . . . . . . . . . . . . . . . . . . . . . . . . . 232 23.7.5 “One-of” and “Some-of” Presentation Types . . . . . . . . . . . . . . . . 232 23.7.6 Sequence Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.7.7 “Meta” Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.7.8 Compound Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . 235 23.7.9 Lisp Expression Presentation Types . . . . . . . . . . . . . . . . . . . . . 235

24 Input Editing and Completion Facilities 236 24.1 The Input Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236 CONTENTS x

24.1.1 The Input Editing Stream Protocol . . . . . . . . . . . . . . . . . . . . . . 239 24.1.2 Suggestions for Input Editing Commands . . . . . . . . . . . . . . . . . . 241

24.2 Activation and Blip Gestures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 24.3 Signalling Errors Inside present Methods . . . . . . . . . . . . . . . . . . . . . . 244 24.4 Reading and Writing of Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 24.5 Completion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

25 Menu Facilities 250

26 Dialog Facilities 254

VII Building Applications 257

27 Command Processing 258 27.1 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 27.2 Command Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 27.3 Command Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 27.4 Keystroke Accelerators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 27.5 Presentation Translator Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 27.6 The Command Processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271

27.6.1 Command Presentation Types . . . . . . . . . . . . . . . . . . . . . . . . 274

28 Application Frames 275 28.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 28.2 Defining and Creating Application Frames . . . . . . . . . . . . . . . . . . . . . . 277 28.3 The Application Frame Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . 280

28.3.1 Interface with Presentation Types . . . . . . . . . . . . . . . . . . . . . . 284 CONTENTS xi

28.3.2 The Generic Command Loop . . . . . . . . . . . . . . . . . . . . . . . . . 285 28.4 Window Viewport Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 28.5 Frame Managers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288

28.5.1 Finding Frame Managers . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 28.5.2 Frame Manager Operations . . . . . . . . . . . . . . . . . . . . . . . . . . 290 28.5.3 Frame Manager Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292

28.6 Examples of Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293

29 Panes 295 29.1 Abstract Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295 29.2 Pane Construction and Uses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296

29.2.1 Pane Initialization Options . . . . . . . . . . . . . . . . . . . . . . . . . . 297 29.2.2 Pane Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297

29.3 Layout and Layout Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 29.3.1 The Basics of the Layout Protocol . . . . . . . . . . . . . . . . . . . . . . 298 29.3.2 Layout Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 29.3.3 Layout Pane Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302

29.4 Application Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 29.4.1 Making Application Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 29.4.2 CLIM Stream Pane Options . . . . . . . . . . . . . . . . . . . . . . . . . . 303

29.5 Pane Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 29.6 Abstract Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304

30 Gadget Panes 306 30.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 30.2 Interacting with Gadget Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 CONTENTS xii

30.3 Abstract Gadgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307

30.3.1 Implementation Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 30.4 Adaptive Gadget Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310

30.4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 30.4.2 Predefined Gadgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310

31 Defining New Pane Types 319 31.1 Defining Leaf Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 31.2 Defining Composite Panes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320

31.2.1 Details of the Layout Protocol . . . . . . . . . . . . . . . . . . . . . . . . 320

VIII Appendices 322

A Glossary 323

B The CLIM-SYS Package 330 B.1 Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 B.2 Multi-processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 B.3 Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332

C Common Lisp Streams 334 C.1 Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 C.2 Basic Stream Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 C.3 Character Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 C.4 Character Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 C.5 Binary Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339

D Encapsulating Streams 340 CONTENTS xiii

D.1 Encapsulating Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340 D.1.1 Encapsulating Stream Protocol . . . . . . . . . . . . . . . . . . . . . . . . 341 D.1.2 The “Delegation Problem” . . . . . . . . . . . . . . . . . . . . . . . . . . 341

E Changes from CLIM 1.0 343

Acknowledgments

The process of designing and implementing CLIM and writing the CLIM specification has been a long and sometimes bumpy one. The first thanks have to go to the people and organizations who allowed the people working on CLIM to continue to do so, despite the obstacles. In particular, Mark Son-Bell of ILA; Bob Laddaga and Saiid Zarrabian at Symbolics (and before or with them, Ken Sinclair, Rick Karash, and Mark Graffam); and Jim Vietch and Hanoch Eiron of Franz, Inc. have struggled with various and sometimes conflicting business interests through the whole process.

The attendees of the CLIM coalition meetings and those who contributed to CLIM along the way include all of those listed on the title page, but also include Bob Kerns, Chris Richardson, Paul Weineke and JonL White, and Kevin Males. Other contributors include Mike McMahon, Paul Robertson, John Hotchkiss, David Lowry, Mike Greenwald, Dave Schatsky, and Glenn Adams.

Sonya Keene, Ann Hathaway, and Ellen Golden all deserve credit for improving the quality of this specification (in part by authoring the original CLIM documentation), as does Mark Nahabedian.

Kent Pitman provided much useful advice on the mechanics of writing a specification, and this document has much improved because of that.

Last but not least are the people who have continued to use CLIM for the duration of this lengthy process. The people at BBN (Bruce Roberts and his group) have been a continuing source of valuable information and suggestions. Also, Markus Fischer of Symbolics GmbH had to deal with more than his fair share of problems, the result of using CLIM in novel ways.

Part I

Chapter 1

Overview and Conventions Overview of CLIM

The Common Lisp Interface Manager (CLIM) is a powerful Lisp-based user interface programming interface that provides a layered set of portable facilities. These include basic windowing, input, and output services provided by Silica (which is a portable layer for constructing windows and toolkit objects); stream-oriented input and output extended with facilities such as output recording, presentations, and context sensitive input; and a compositional toolkit similar to those found in the X world that supports look and feel independence.

CLIM provides an API (applications programmer interface) to user interface facilities for the Lisp application programmer. CLIM does not compete with the window system or toolkits of the host machine (such as X/Motif or NEWS/OpenLook), but rather uses their services (to the extent that it makes sense) to integrate Lisp applications into the host’s window environment. For example, CLIM “windows” are mapped onto one or more host windows, and input and output operations performed on the CLIM window are ultimately carried out by the host window system. CLIM will support a large number of host environments including Genera, X/Motif, X/OpenLook, the Macintosh, CLOE-386/486, and the Next machine.

The CLIM programmer is insulated from the complexities of portability, since the Lisp-based application need only deal with CLIM objects and functions regardless of their operating platform (that is, the combination of Lisp system, host computer, and host window environment). CLIM abstracts out many of the concepts common to all window environments. The programmer is encouraged to think in terms of these abstractions, rather than in the specific capabilities of a particular host system. For example, using CLIM, the application can specify the appearance of output in high-level terms and those high-level descriptions are turned into the appropriate appearance for the given host. Thus, the application has the same fundamental interface across multiple environments, although the details will differ from system to system.

Another important goal in the design and organization of CLIM is to provide a spectrum of user interface building options, all the way from detailed, low-level specification of “what goes where”, to high-level user interface specification where the programmer leaves all of the details up to CLIM. This allows CLIM to balance the ease of use on one hand, and versatility on the other. The idea is that by using high level facilities, a programmer can build portable user interfaces quickly, whereas by recombining lower level facilities he can build his own programming and user interfaces according to his specific needs or requirements. For example, CLIM supports the development of applications independent of look and feel (also dubbed “chameleon look and feel”) as well as the portable development of toolkit libraries that define and implement a particular look and feel.

In addition, CLIM’s modular design allows application programs to exclude facilities that they do not use, and reimplement any or all of the substrate. To these ends, CLIM is specified and implemented in a layered, modular fashion. Each facility documented in this specification has several layers of interface, and each facility is independently specified and has a documented external interface.

The facilities provided by CLIM include:

Geometry CLIM provides provides geometric objects like point, rectangle, and transformations and functions for manipulating them.

Graphics CLIM provides a rich set of drawing functions, including ones for drawing complex geometric shapes, a wide variety of drawing options (such as line thickness), a sophisticated inking model, and color. CLIM provides full affine transforms, so that a drawing may be arbitrarily translated, rotated, and scaled (to the extent that the underlying window system supports the rendering of such objects).

Windowing CLIM provides a portable layer for implementing sheet classes (types of windowlike objects) that are suited to support particular high level facilities or interfaces. The Silica module of CLIM defines a uniform interface for creating and managing hierarchies of these objects regardless of their sheet class. In addition, Silica defines standard sheet classes that define a straightforward window that is more or less equivalent in functionality to an X window.

Output Recording CLIM provides a facility for capturing all output done to a window. This facility provides the support for arbitrarily scrollable windows. In addition, this facility serves as the root for a variety of interesting high-level tools.

Formatted Output CLIM provides a set of high-level macros that enable programs to produce neatly formatted tabular and graphical displays with little or no effort.

Context Sensitive Input The presentation type facility of CLIM provides the ability to associate semantics with output, such that objects may be retrieved later via clicks on their displayed representation. This sensitivity comes along automatically and is integrated with the Common Lisp type system. A mechanism for type coercion is also included, providing the basis for powerful user interfaces.

Application Building CLIM provides a set of tools for organizing an application’s top-level user interface and command processing loops centered on objects called frames. CLIM provides functionality for laying out frames under arbitrary constraints, managing command menus and/or menu bars, and linking user interface gestures with application commands. Using these tools, application writers can easily and quickly construct user interfaces that can grow flexibly from prototype to delivery.

Adaptive Toolkit CLIM provides a uniform interface to the standard compositional toolkits available in many environments. CLIM defines abstract panes that are analogous to the gadgets or widgets of a toolkit like InterViews or the X toolkit. CLIM fosters look and feel independence by specifying the interface of these abstract panes in terms of their function and not in terms of the details of their appearance or operation. If an application uses these interfaces, its user interface will adapt to use whatever toolkit is available in the host environment. By using this facility, application programmers can easily construct applications that will automatically conform to a variety of user interface standards. In addition, a portable lisp-based implementation of the abstract panes is provided.

Conventions

This chapter describes the conventions used in this specification and in the CLIM software itself.

2.1 Audience, Goals, and Purpose

This document, the CLIM Release 2 Specification, is intended for vendors. While it does define the Application Programmer’s Interface (API), that is, the functionality that a customer/consumer would use to write an application, it also defines the names and functionality of some internal parts of CLIM. These “portals” in implementation space allow one vendor to extend, for example, the output record mechanism and have it work with another vendor’s implementation of incremental redisplay. We have attempted to carefully identify the appropriate “portals” so that the API can be implemented efficiently, but we have also tried not to overconstrain the specification so that it restricts creativity of implementation or the possibility for extension. This also affects the more sophisticated application writers who want to go a little below the published API but still want portable applications. This document defines which functionality is part of the advertised API, and which is part of the internal protocols.

In this document, we refer to three different audiences. A CLIM user is a person who uses an application program that was written using CLIM. A CLIM programmer is a person who writes application programs using CLIM. A CLIM implementor is a programmer who implements CLIM or extends it in some non-trivial way.

2.2 Package Structure

CLIM defines a variety of packages in order to provide its functionality. In general, no symbols except for the symbols in this specification should be added to those packages.

The clim-lisp package is intended to emulate ANSI-90 Common Lisp as much as possible, independent of the conformance of individual vendors. clim-lisp is the version of Common Lisp in which CLIM is implemented and which the clim-user package uses instead of commonlisp. clim-lisp contains only exported symbols, and is locked in those implementations that allow package locking.

clim is the package where the symbols specified in this specification live. It contains only exported symbols and is locked in those implementations that allow package locking.

clim-sys is the package where useful “system-like” functionality lives, including such things as resources and multi-processing primitives. It contains concepts that are not part of Common Lisp, but which are not conceptually the province of CLIM itself. It contains only exported symbols and is locked in those implementations that allow package locking.

No code is written in any of the above packages, but rather code is written for symbols in the above packages. None of the above use any other packages (in the sense of the :use option to defpackage). A CLIM implementation might define a clim-internals package that uses each of the above packages, thus getting the definition of Lisp from clim-lisp. It would then implement the functionality of the symbols in clim and clim-sys in the clim-internals package.

clim-user is the package for programmers to use if they don’t wish to create their own package. It is the CLIM analog of common-lisp-user.

2.3 “Spread” Point Arguments to Functions

Many functions that take point arguments come in two forms: structured and spread. Functions that take structured point arguments take the argument as a single point object. Functions that take spread point arguments take a pair of arguments that correspond to the x and y coordinates of the point.

Functions that take spread point arguments, or return spread point values have an asterisk in their name, for example, draw-line*.

2.4 Immutability of Objects

Most CLIM objects are immutable, that is, at the protocol level none of their components can be modified once the object is created. Examples of immutable objects include all of the members of the region classes, colors and opacities, text styles, and line styles. Since immutable objects by definition never change, functions in the CLIM API can safely capture immutable objects without first copying them. This also allows CLIM to cache immutable objects. Constructor functions that return immutable objects are free to either create and return a new object, or return an already existing object.

A few CLIM objects are mutable. Examples of mutable objects include streams and output records. Some components of mutable objects can be modified once the object has been created, usually via setf accessors.

In CLIM, object immutability is maintained at the class level. Throughout this specification, the immutability or mutability of a class will be explicitly specified.

Some immutable classes also allow interning. A class is said to be interning if it guarantees that two instances that are equivalent will always be eq. For example, if the class color were interning, calling make-rgb-color twice with the same arguments would return eq values. CLIM does not specify that any class is interning, however all immutable classes are allowed to be interning at the discretion of the implementation.

In some rare cases, CLIM will modify objects that are members of immutable classes. Such objects are referred to as being volatile. Extreme care must be take with volatile objects. This specification will note whenever some object that is part of the API is volatile.

2.5 Behavior of Interfaces

In this specification, any interfaces that take or return mutable objects can be classified in a few different ways.

Most functions do not capture their mutable input objects, that is, these functions will either not store the objects at all, or will copy any mutable objects before storing them, or perhaps store only some of the components of the objects. Later modifications to those objects will not affect the internal state of CLIM.

Some functions may capture their mutable input objects. That is, it is unspecified as to whether a CLIM implementation will or will not capture the mutable inputs to some function. For such functions, programmers should assume that these objects will be captured and should not modify these objects capriciously. Furthermore, it is unspecifed what will happen if these objects are later modified.

Some programmers might choose to create a mutable subclass of an immutable class. If CLIM captures an object that is a member of such a class, it is unspecified what will happen if the programmer later modifies that object. If a programmer passes such an object to a CLIM function that may capture its inputs, he is responsible for either first copying the object or ensuring that the object does not change later.

Some functions that return mutable objects are guaranteed to create fresh outputs. These objects can be modified without affecting the internal state of CLIM.

Functions that return mutable objects that are not fresh objects fall into two categories: those that return read-only state, and those that return read/write state. If a function returns readonly state, programmers must not modify that object; doing so might corrupt the state of CLIM. If a function returns read/write state, the modification of that object is part of CLIM’s interface, and programmers are free to modify the object in ways that “make sense”.

2.6 Protocol Classes and Predicates

CLIM supplies a set of predicates that can be called on an object to determine whether or not that object satisfies a certain protocol. These predicates can be implemented in one of two ways.

The first way is that a class implementing a particular protocol will inherit from a protocol class that corresponds to that protocol. A protocol class is an “abstract” class with no slots and no methods (except perhaps for some default methods), and exists only to indicate that some subclass obeys the protocol. In the case when a class inherits from a protocol class, the predicate could be implemented using typep. All of the CLIM geometry, region, sheet, and output record classes use this convention. For example, the presentation protocol class and predicate could be implemented in this way:

(defclass presentation () ())
(defun presentationp (object)
  (typep object 'presentation))

Note that in some implementations, it may be more efficient not to use typep, and instead use a generic function for the predicate. However, simply implementing a method for the predicate that returns true is not necessarily enough to assert that a class supports that protocol; the class must include the protocol class as a superclass.

CLIM always provides at least one “standard” instantiable class that implements each protocol.

The second way is that a class implementing a particular protocol must simply implement a method for a predicate generic function that returns true if and only if that class supports the protocol (otherwise, it returns false). Most of the CLIM stream classes use this convention. Protocol classes are not used in these cases because, as in the case of some of the stream classes, the underlying Lisp implementation may not be arranged so as to permit it. For example, the extended input stream protocol might be implemented in this way:

(defgeneric extended-input-stream-p (object))
(defmethod extended-input-stream-p ((object t)) nil)
(defmethod extended-input-stream-p ((object basic-extended-input-protocol)) t)
(defmethod extended-input-stream-p
           ((encapsulating-stream encapsulating-stream-mixin))
  (with-slots (stream) encapsulating-stream
    (extended-input-stream-p stream)))

Whenever a class inherits from a protocol class or returns true from the protocol predicate, the class must implement methods for all of the generic functions that make up the protocol.

2.7 Specialized Arguments to Generic Functions

Unless otherwise stated, this specification uses the following convention for specifying which arguments to generic functions are specialized:

• If the generic function is a setf function, the second argument is the one that is intended to be specialized.

• If the generic function is a “mapping” function (such as map-over-region-set-regions), the second argument (the object that specifies what is being mapped over) is the one that is specialized. The first argument (the functional argument) is not intended to be specialized.

• Otherwise, the first argument is the one that is intended to be specialized.

2.8 Sheet, Stream, or Medium Arguments to Macros

There are many macros that take a sheet, stream, or medium as one of the arguments, for

example, with-new-output-record and formatting-table. In CLIM, this argument must be

a variable bound to a sheet, stream, or medium; it may not be an arbitrary form that evaluates to a sheet, stream, or medium. t and sometimes nil are usually allowed as special cases; this causes the variable to be interpreted as a reference to another stream variable (usually *standard-output* for output macros, or *query-io* for input macros). Note that, while the variable outside the macro form and the variable inside the body share the same name, they cannot be assumed to be the same reference. That is, the macro is free to create a new binding for the variable. Thus, the following code fragment will not necessarily affect the value of stream

outside the formatting-table form:

(formatting-table (stream)
  (setq stream some-other-stream)
  ...)

Furthermore, for the macros that take a sheet, stream, or medium argument, the position of that variable is always before any forms or other “inputs”.

2.9 Macros that Expand into Calls to Advertised Functions

Some macros that take a “body” argument expand into a call to an advertised function that takes a functional argument. This functional argument will execute the suppled body. For a macro named “with-environment”, the function is generally named “invoke-with-environment”. For example, with-drawing-options might be defined as follows:

(defgeneric invoke-with-drawing-options (medium function &key)
  (declare (dynamic-extent function)))
(defmacro with-drawing-options ((medium &rest drawing-options) &body body)
  `(flet ((with-drawing-options-body (,medium) ,@body))
     (declare (dynamic-extent #'with-drawing-options-body))
     (invoke-with-drawing-options
       ,medium #'with-drawing-options-body ,@drawing-options)))
(defmethod invoke-with-drawing-options
           ((medium clx-display-medium) function &rest drawing-options)
  (with-drawing-options-merged-into-medium (medium drawing-options)
    (funcall function medium)))

2.10 Terminology Pertaining to Error Conditions

When this specification specifies that it “is an error” for some situation to occur, this means that:

• No valid CLIM program should cause this situation to occur.

• If this situation does occur, the effects and results are undefined as far as adherence to the CLIM specification is concerned.

• CLIM implementations are not required to detect such an error, although implementations are encouraged to provide such error detection whenever it is reasonable to do so.

When this specification specifies that some argument “must be a type” or uses the phrase “the type argument”, this means that it is an error if the argument is not of the specified type. CLIM implementations are encouraged, but not required, to generate an argument type error for these situations.

When this specification says that “an error is signalled” in some situation, this means that:

• If the situation occurs, an error will be signalled using either error or cerror.

• Valid CLIM programs may rely on the fact that an error will be signalled.

• Every CLIM implementation is required to detect such an error.

When this specification says that “a condition is signalled” in some situation, this is just like “an error is signalled” with the exception that the condition will be signalled using signal instead

of error.

Part II

Geometry Substrate Geometry

CLIM provides definitions for a variety of geometric objects, including points, lines, elliptical arcs, regions, and transformations. Both the graphics and windowing modules use the same set of geometric objects and functions. In this section, we describe regions, points, and the basic region classes. Transformations will be described in Chapter 5.

Most of these objects are described as if they are implemented using standard classes. However, this need not be the case. In particular, they may be implemented using structure classes, and some classes may exist only to name a place in the hierarchy—all members of such a class will be instances of that class’s subclasses. The most important concern is that these classes must allow specializing generic functions.

The coordinate system in which the geometric objects reside is an abstract, continuous coordinate system. This abstract coordinate system is converted into “real world” coordinates only during operations such as rendering one of the objects on a display device.

Angles are measured in radians. Following standard conventions, when an angle is measured relative to a given line, a positive angle indicates an angle counter-clockwise from the line in the plane. When the angle from the positive x axis to the positive y axis is positive (that is, the positive y axis is counter-clockwise from the positive x axis), the coordinate system is said to be right-handed. When this angle is negative, the coordinate system is said to be left-handed. Thus, the cartesian coordinate system with x increasing to the right and y increasing upward is right-handed. A coordinate system with y increasing down is left-handed. (By default, CLIM streams are left handed, but no such default exists for sheets in general.)

3.1 General Regions

A region is an object that denotes a set of mathematical points in the plane. Regions include their boundaries, that is, they are closed. Regions have infinite resolution.

A bounded region is a region that contains at least one point and for which there exists a number, d, called the region’s diameter, such that if p1 and p2 are points in the region, the distance between p1 and p2 is always less than or equal to d.

An unbounded region either contains no points or contains points arbitrarily far apart.

Another way to describe a region is that it maps every (x, y) pair into either true or false (meaning member or not a member, respectively, of the region). Later, in Chapter 14, we will generalize a region to something called a design that maps every point (x, y) into color and opacity values.

⇒ region [Protocol Class]

The protocol class that corresponds to a set of points. This includes both bounded and unbounded regions. If you want to create a new class that behaves like a region, it should be a subclass of region. Subclasses of region must obey the region protocol.

There is no general constructor called make-region because of the impossibility of a uniform way to specify the arguments to such a function.

⇒ regionp object [Function]

Returns true if object is a region, otherwise returns false.

⇒ path [Protocol Class]

The protocol class path denotes bounded regions that have dimensionality 1 (that is, have length). It is a subclass of region and bounding-rectangle. If you want to create a new class that behaves like a path, it should be a subclass of path. Subclasses of path must obey the path protocol.

Constructing a path object with no length (via make-line*, for example) canonicalizes it to

+nowhere+.

Some rendering models support the constructing of areas by filling a closed path. In this case, the path needs a direction associated with it. Since CLIM does not currently support the path-filling model, paths are directionless.

⇒ pathp object [Function]

Returns true if object is a path, otherwise returns false.

⇒ area [Protocol Class]

The protocol class area denotes bounded regions that have dimensionality 2 (that is, have area). It is a subclass of region and bounding-rectangle. If you want to create a new class that behaves like an area, it should be a subclass of area. Subclasses of area must obey the area protocol.

Constructing an area object with no area (via make-rectangle*, for example) canonicalizes it

to +nowhere+.

⇒ areap object [Function]

Returns true if object is an area, otherwise returns false.

⇒ +everywhere+  [Constant]

⇒ +nowhere+ [Constant]

+everywhere+ is the region that includes all the points on the two-dimensional infinite drawing plane. +nowhere+ is the empty region, the opposite of +everywhere+.

3.1.1 The Region Predicate Protocol

The following generic functions comprise the region predicate protocol. All classes that are subclasses of region must either inherit or implement methods for these generic functions.

The methods for region-equal, region-contains-region-p, and region-intersects-region-

p will typically specialize both the region1 and region2 arguments.

⇒ region-equal region1 region2 [Generic Function]

Returns true if the two regions region1 and region2 contain exactly the same set of points, otherwise returns false.

⇒ region-contains-region-p region1 region2 [Generic Function]

Returns true if all points in the region region2 are members of the region region1, otherwise returns false.

⇒ region-contains-point*-p region x y [Generic Function]

Returns true if the point at (x, y) is contained in the region region, otherwise returns false. Since regions in CLIM are closed, this must return true if the point at (x, y) is on the region’s boundary. CLIM implementations are permitted to return different non-nil values depending on whether the point is completely inside the region or is on the border.

region-contains-point*-p is a special case of region-contains-region-p in which the region

is the point (x, y).

⇒ region-intersects-region-p region1 region2 [Generic Function]

Returns false if region-intersection of the two regions region1 and region2 would be +nowhere+, otherwise returns true.

3.1.2 Region Composition Protocol

Region composition is not always equivalent to simple set operations. Instead, composition attempts to return an object that has the same dimensionality as one of its arguments. If this is not possible, then the result is defined to be an empty region, which is canonicalized to +nowhere+. (The exact details of this are specified with each function.)

Sometimes, composition of regions can produce a result that is not a simple contiguous region. For example, region-union of two rectangular regions might not be a single rectangle. In order to support cases like this, CLIM has the concept of a region set, which is an object that represents one or more region objects related by some region operation, usually a union. CLIM provides standard classes to cover the cases of region union, intersection, and difference.

Some CLIM implementations might only implement a subset of full region composition. Because of the importance of rectangular regions and region sets that are the union of rectangular regions, every CLIM implementation is required to fully support all functions that use regions for those cases. (For example, CLIM implementations must be able do clipping and repainting on region sets composed entirely of axis-aligned rectangles.) If a CLIM implementation does not support some functions on non-rectangular region sets (for example, clipping), it must signal an error when an unsupported case is encountered; the exact details of this depend on the particular CLIM implementation.

⇒ region-set [Protocol Class]

The protocol class that represents a region set; a subclass of region and bounding-rectangle.

In addition to the three classes below, there may be other instantiable subclasses of regionset that represent special cases, for instance, some implementations might have a standardrectangle-set class that represents the union of several axis-aligned rectangles.

Members of this class are immutable.

⇒ region-set-p object [Function]

Returns true if object is a region set, otherwise returns false.

⇒ standard-region-union  [Class]
⇒ standard-region-intersection  [Class]
⇒ standard-region-difference  [Class]

These three instantiable classes respectively implement the union, intersection, and differences of regions. Implementations may, but are not required to, take advantage of the commutativity and associativity of union and intersection in order to “collapse” complicated region sets into simpler ones.

Region sets that are composed entirely of axis-aligned rectangles must be canonicalized into either a single rectangle or a union of rectangles. Furthermore, the rectangles in the union must not overlap each other.

The following generic functions comprise the region composition protocol. All classes that are subclasses of region must implement methods for these generic functions.

The methods for region-union, region-intersection, and region-difference will typically

specialize both the region1 and region2 arguments.

Figure 3.1: Normalization of rectangular region sets.

⇒ region-set-regions region &key normalize [Generic Function]

Returns a sequence of the regions in the region set region. region can be either a region set or a “simple” region, in which case the result is simply a sequence of one element: region. This function returns objects that reveal CLIM’s internal state; do not modify those objects.

For the case of region sets that are unions of axis-aligned rectangles, the rectangles returned by region-set-regions are guaranteed not to overlap.

If normalize is supplied, it must be either :x-banding or :y-banding. If it is :x-banding and all the regions in region are axis-aligned rectangles, the result is normalized by merging adjacent rectangles with banding done in the x direction. If it is :y-banding and all the regions in region are rectangles, the result is normalized with banding done in the y direction. Normalizing a region set that is not composed entirely of axis-aligned rectangles using x- or y-banding causes

CLIM to signal the region-set-not-rectangular error.

⇒ map-over-region-set-regions function region &key normalize [Generic Function]

Calls function on each region in the region set region. This is often more efficient than calling region-set-regions. function is a function of one argument, a region; it has dynamic extent. region can be either a region set or a “simple” region, in which case function is called once on region itself. normalize is as for region-set-regions.

⇒ region-union region1 region2 [Generic Function]

Returns a region that contains all points that are in either of the regions region1 or region2 (possibly with some points removed in order to satisfy the dimensionality rule). The result of region-union always has dimensionality that is the maximum dimensionality of region1 and region2. For example, the union of a path and an area produces an area; the union of two paths is a path.

region-union will return either a simple region or a member of the class standard-region-

union.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

⇒ region-intersection region1 region2 [Generic Function]

Returns a region that contains all points that are in both of the regions region1 and region2 (possibly with some points removed in order to satisfy the dimensionality rule). The result of region-intersection has dimensionality that is the minimum dimensionality of region1 and region2, or is +nowhere+. For example, the intersection of two areas is either another area or +nowhere+; the intersection of two paths is either another path or +nowhere+; the intersection of a path and an area produces the path clipped to stay inside of the area.

region-intersection will return either a simple region or a member of the class standard-

region-intersection.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

⇒ region-difference region1 region2 [Generic Function]

Returns a region that contains all points in the region region1 that are not in the region region2 (possibly plus additional boundary points to make the result closed). The result of regiondifference has the same dimensionality as region1, or is +nowhere+. For example, the difference of an area and a path produces the same area; the difference of a path and an area produces the path clipped to stay outside of the area.

region-difference will return either a simple region or a member of the class standard-

region-difference.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

3.2 Other Region Types

The other types of regions are points, polylines, polygons, elliptical arcs, and ellipses. All of these region types are closed under affine transformations.

Issue: A reasonable way to address the perceived “bloating” caused by all of the following region types is to specify that CLIM must not internally use any region types except for points, rectangles, and region sets composed of rectangular regions. This allows CLIM implementations Figure 3.2: Examples of region union, intersection, and difference.

Figure 3.3: The class structure for all regions.

to omit support for the other region types from the “core” of CLIM, and include that support as a layered module. — SWM

3.2.1 Points

A point is a mathematical point in the plane, designated by its coordinates, which are a pair of real numbers (where a real number is defined as either an integer, a ratio, or a floating point number). Points have neither area nor length (that is, they have dimensionality 0).

Note well that a point is not a pixel; CLIM models a drawing plane with continuous coordinates. This is discussed in more detail in Chapter 12.

⇒ point [Protocol Class]

The protocol class that corresponds to a mathematical point. This is a subclass of region and bounding-rectangle. If you want to create a new class that behaves like a point, it should be a subclass of point. Subclasses of point must obey the point protocol.

⇒ pointp object [Function]

Returns true if object is a point, otherwise returns false.

⇒ standard-point  [Class]

An instantiable class that implements a point. This is a subclass of point. This is the class that make-point instantiates. Members of this class are immutable.

⇒ make-point x y [Function]

Returns an object of class standard-point whose coordinates are x and y. x and y must be real numbers.

The Point Protocol

The following generic functions comprise the point API. Only point-position* is in the point protocol, that is, all classes that are subclasses of point must implement methods for pointposition*, but need not implement methods for point-x and point-y.

⇒ point-position* point [Generic Function]

Returns both the x and y coordinates of the point point as two values.

⇒ point-x point [Generic Function] ⇒ point-y point [Generic Function]

Returns the x or y coordinate of the point point, respectively. CLIM will supply default methods for point-x and point-y on the protocol class point that are implemented by calling point-

position*.

3.2.2 Polygons and Polylines

A polyline is a path that consists of one or more line segments joined consecutively at their end-points.

Polylines that have the end-point of their last line segment coincident with the start-point of their first line segment are called closed; this use of the term “closed” should not be confused with closed sets of points.

A polygon is an area bounded by a closed polyline.

If the boundary of a polygon intersects itself, the odd-even winding-rule defines the polygon: a point is inside the polygon if a ray from the point to infinity crosses the boundary an odd number of times.

⇒ polyline [Protocol Class] The protocol class that corresponds to a polyline. This is a subclass of path. If you want to create a new class that behaves like a polyline, it should be a subclass of polyline. Subclasses of polyline must obey the polyline protocol.

⇒ polylinep object [Function]

Returns true if object is a polyline, otherwise returns false.

⇒ standard-polyline  [Class]

An instantiable class that implements a polyline. This is a subclass of polyline. This is the class that make-polyline and make-polyline* instantiate. Members of this class are immutable.

⇒ make-polyline point-seq &key closed [Function] ⇒ make-polyline* coord-seq &key closed [Function]

Returns an object of class standard-polyline consisting of the segments connecting each of the points in point-seq (or the points represented by the coordinate pairs in coord-seq). point-seq is a sequence of points; coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements.

If closed is true, then the segment connecting the first point and the last point is included in the polyline. The default for closed is false.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

⇒ polygon [Protocol Class]

The protocol class that corresponds to a mathematical polygon. This is a subclass of area. If you want to create a new class that behaves like a polygon, it should be a subclass of polygon. Subclasses of polygon must obey the polygon protocol.

⇒ polygonp object [Function]

Returns true if object is a polygon, otherwise returns false.

⇒ standard-polygon  [Class]

An instantiable class that implements a polygon. This is a subclass of polygon. This is the class that make-polygon and make-polygon* instantiate. Members of this class are immutable.

⇒ make-polygon point-seq [Function] ⇒ make-polygon* coord-seq [Function]

Returns an object of class standard-polygon consisting of the area contained in the boundary that is specified by the segments connecting each of the points in point-seq (or the points represented by the coordinate pairs in coord-seq). point-seq is a sequence of points; coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

The Polygon and Polyline Protocol

The following generic functions comprise the polygon and polyline protocol. All classes that are subclasses of either polygon or polyline must implement methods for these generic functions. Some of the functions below take an argument named polygon-or-polyline; this argument may be either a polygon or a polyline.

⇒ polygon-points polygon-or-polyline [Generic Function]

Returns a sequence of points that specify the segments in polygon-or-polyline. This function returns objects that reveal CLIM’s internal state; do not modify those objects.

⇒ map-over-polygon-coordinates function polygon-or-polyline [Generic Function]

Applies function to all of the coordinates of the vertices of polygon-or-polyline. function is a function of two arguments, the x and y coordinates of the vertex; it has dynamic extent.

⇒ map-over-polygon-segments function polygon-or-polyline [Generic Function]

Applies function to the segments that compose polygon-or-polyline. function is a function of four arguments, the x and y coordinates of the start of the segment, and the x and y coordinates of the end of the segment; it has dynamic extent. When map-over-polygon-segments is called on a closed polyline, it will call function on the segment that connects the last point back to the first point.

⇒ polyline-closed polyline [Generic Function]

Returns true if the polyline polyline is closed, otherwise returns false. This function need be implemented only for polylines, not for polygons.

3.2.3 Lines

A line is a polyline consisting of a single segment.

⇒ line [Protocol Class]

The protocol class that corresponds to a mathematical line segment, that is, a polyline with only a single segment. This is a subclass of polyline. If you want to create a new class that behaves like a line, it should be a subclass of line. Subclasses of line must obey the line protocol.

⇒ linep object [Function]

Returns true if object is a line, otherwise returns false.

⇒ standard-line  [Class]

An instantiable class that implements a line segment. This is a subclass of line. This is the class that make-line and make-line* instantiate. Members of this class are immutable.

⇒ make-line start-point end-point [Function] ⇒ make-line* start-x start-y end-x end-y [Function]

Returns an object of class standard-line that connects the two points start-point and end-point (or the positions (start-x,start-y) and (end-x,end-y)).

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

The Line Protocol

The following generic functions comprise the line API. Only line-start-point* and line-end-point* are in the line protocol, that is, all classes that are subclasses of line must implement methods for line-start-point* and line-end-point*, but need not implement methods for

line-start-point and line-end-point.

⇒ line-start-point* line [Generic Function] ⇒ line-end-point* line [Generic Function]

Returns the starting or ending point, respectively, of the line line as two real numbers representing the coordinates of the point.

⇒ line-start-point line [Generic Function] ⇒ line-end-point line [Generic Function]

Returns the starting or ending point of the line line, respectively.

CLIM will supply default methods for line-start-point and line-end-point on the protocol

class line that are implemented by calling line-start-point* and line-end-point*.

3.2.4 Rectangles

Rectangles whose edges are parallel to the coordinate axes are a special case of polygon that can be specified completely by four real numbers (x1,y1,x2,y2). They are not closed under general affine transformations (although they are closed under rectilinear transformations).

⇒ rectangle [Protocol Class]

The protocol class that corresponds to a mathematical rectangle, that is, rectangular polygons whose sides are parallel to the coordinate axes. This is a subclass of polygon. If you want to create a new class that behaves like a rectangle, it should be a subclass of rectangle. Subclasses of rectangle must obey the rectangle protocol.

⇒ rectanglep object [Function]

Returns true if object is a rectangle, otherwise returns false.

⇒ standard-rectangle  [Class]

An instantiable class that implements an axis-aligned rectangle. This is a subclass of rectangle. This is the class that make-rectangle and make-rectangle* instantiate. Members of this class are immutable.

⇒ make-rectangle point1 point2 [Function] ⇒ make-rectangle* x1 y1 x2 y2 [Function]

Returns an object of class standard-rectangle whose edges are parallel to the coordinate axes. One corner is at the point point1 (or the position (x1,y1)) and the opposite corner is at the point point2 (or the position (x2,y2)). There are no ordering constraints among point1 and point2 (or x1 and x2, and y1 and y2).

Most CLIM implementations will choose to represent rectangles in the most efficient way, such as by storing the coordinates of two opposing corners of the rectangle. Because this representation is not sufficient to represent the result of arbitrary transformations of arbitrary rectangles, CLIM is allowed to return a polygon as the result of such a transformation. (The most general class of transformations that is guaranteed to always turn a rectangle into another rectangle is the class of transformations that satisfy rectilinear-transformation-p.)

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

The Rectangle Protocol

The following generic functions comprise the rectangle API. Only rectangle-edges* is in the rectangle protocol, that is, all classes that are subclasses of rectangle must implement methods for rectangle-edges*, but need not implement methods for the remaining functions.

⇒ rectangle-edges* rectangle [Generic Function]

Returns the coordinates of the minimum x and y and maximum x and y of the rectangle rectangle as four values, min-x, min-y, max-x, and max-y.

⇒ rectangle-min-point rectangle [Generic Function] ⇒ rectangle-max-point rectangle [Generic Function]

Returns the min point and max point of the rectangle rectangle, respectively. The position of a rectangle is specified by its min point.

CLIM will supply default methods for rectangle-min-point and rectangle-max-point on the protocol class rectangle that are implemented by calling rectangle-edges*.

⇒ rectangle-min-x rectangle [Generic Function] ⇒ rectangle-min-y rectangle [Generic Function] ⇒ rectangle-max-x rectangle [Generic Function] ⇒ rectangle-max-y rectangle [Generic Function]

Returns (respectively) the minimum x and y coordinate and maximum x and y coordinate of the rectangle rectangle.

CLIM will supply default methods for these four generic functions on the protocol class rectangle that are implemented by calling rectangle-edges*.

⇒ rectangle-width rectangle [Generic Function] ⇒ rectangle-height rectangle [Generic Function] ⇒ rectangle-size rectangle [Generic Function]

rectangle-width returns the width of the rectangle rectangle, which is the difference between the maximum x and its minimum x. rectangle-height returns the height, which is the difference between the maximum y and its minimum y. rectangle-size returns two values, the width and the height.

CLIM will supply default methods for these four generic functions on the protocol class rectangle that are implemented by calling rectangle-edges*.

3.2.5 Ellipses and Elliptical Arcs

An ellipse is an area that is the outline and interior of an ellipse. Circles are special cases of ellipses.

An elliptical arc is a path consisting of all or a portion of the outline of an ellipse. Circular arcs are special cases of elliptical arcs.

An ellipse is specified in a manner that is easy to transform, and treats all ellipses on an equal basis. An ellipse is specified by its center point and two vectors that describe a bounding parallelogram of the ellipse. The bounding parallelogram is made by adding and subtracting the vectors from the the center point in the following manner:

x coordinate  y coordinate
Center of Ellipse  x_{c}  y_{c}
Vectors  dx_{1}  dy_{1}
dx_{2}  dy_{2}
Corners of Parallelogram x_{c} + dx_{1} + dx_{2} y_{c} + dy_{1} + dy_{2}
x_{c} + dx_{1} − dx_{2} y_{c} + dy_{1} − dy_{2}
x_{c} − dx_{1} − dx_{2} y_{c} − dy_{1} − dy_{2}
x_{c} − dx_{1} + dx_{2} y_{c} − dy_{1} + dy_{2}

Note that several different parallelograms specify the same ellipse. One parallelogram is bound to be a rectangle—the vectors will be perpendicular and correspond to the semi-axes of the ellipse.

Figure 3.4: Different vectors may specify the same ellipse.

The special case of an ellipse with its axes aligned with the coordinate axes can be obtained by setting dx_{2} = dy_{1} = 0 or dx_{1} = dy_{2} = 0.

⇒ ellipse [Protocol Class]

The protocol class that corresponds to a mathematical ellipse. This is a subclass of area. If you want to create a new class that behaves like an ellipse, it should be a subclass of ellipse. Subclasses of ellipse must obey the ellipse protocol.

⇒ ellipsep object [Function]

Returns true if object is an ellipse, otherwise returns false.

⇒ standard-ellipse  [Class]

An instantiable class that implements an ellipse. This is a subclass of ellipse. This is the class that make-ellipse and make-ellipse* instantiate. Members of this class are immutable.

⇒ make-ellipse center-point radius-1-dx radius-1-dy radius-2-dx radius-2-dy &key start-angle end-

angle [Function] ⇒ make-ellipse* center-x center-y radius-1-dx radius-1-dy radius-2-dx radius-2-dy &key start-

angle end-angle [Function]

Returns an object of class standard-ellipse. The center of the ellipse is at the point centerpoint (or the position (center-x,center-y)).

Two vectors, (radius-1-dx,radius-1-dy) and (radius-2-dx,radius-2-dy) specify the bounding parallelogram of the ellipse as explained above. All of the radii are real numbers. If the two vectors are collinear, the ellipse is not well-defined and the ellipse-not-well-defined error will be signalled. The special case of an ellipse with its axes aligned with the coordinate axes can be obtained by setting both radius-1-dy and radius-2-dx to 0.

If start-angle or end-angle are supplied, the ellipse is the “pie slice” area swept out by a line from the center of the ellipse to a point on the boundary as the boundary point moves from the angle start-angle to end-angle. Angles are measured counter-clockwise with respect to the positive x axis. If end-angle is supplied, the default for start-angle is 0; if start-angle is supplied, the default for end-angle is 2π; if neither is supplied then the region is a full ellipse and the angles are meaningless.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

⇒ elliptical-arc [Protocol Class]

The protocol class that corresponds to a mathematical elliptical arc. This is a subclass of path. If you want to create a new class that behaves like an elliptical arc, it should be a subclass of elliptical-arc. Subclasses of elliptical-arc must obey the elliptical arc protocol.

⇒ elliptical-arc-p object [Function]

Returns true if object is an elliptical arc, otherwise returns false.

⇒ standard-elliptical-arc  [Class]

An instantiable class that implements an elliptical arc. This is a subclass of elliptical-arc. This is the class that make-elliptical-arc and make-elliptical-arc* instantiate. Members of this class are immutable.

⇒ make-elliptical-arc center-point radius-1-dx radius-1-dy radius-2-dx radius-2-dy &key start-

angle end-angle [Function] ⇒ make-elliptical-arc* center-x center-y radius-1-dx radius-1-dy radius-2-dx radius-2-dy &key

start-angle end-angle [Function]

Returns an object of class standard-elliptical-arc. The center of the ellipse is at the point center-point (or the position (center-x,center-y)).

Two vectors, (radius-1-dx,radius-1-dy) and (radius-2-dx,radius-2-dy), specify the bounding parallelogram of the ellipse as explained above. All of the radii are real numbers. If the two vectors are collinear, the ellipse is not well-defined and the ellipse-not-well-defined error will be signalled. The special case of an elliptical arc with its axes aligned with the coordinate axes can be obtained by setting both radius-1-dy and radius-2-dx to 0.

If start-angle and start-angle are supplied, the arc is swept from start-angle to end-angle. Angles are measured counter-clockwise with respect to the positive x axis. If end-angle is supplied, the default for start-angle is 0; if start-angle is supplied, the default for end-angle is 2π; if neither is supplied then the region is a closed elliptical path and the angles are meaningless.

This function is permitted to capture its mutable inputs; the consequences of modifying those objects are unspecified.

The Ellipse and Elliptical Arc Protocol

The following functions apply to both ellipses and elliptical arcs. In all cases, the name ellipticalobject means that the argument may be an ellipse or an elliptical arc. These generic functions comprise the ellipse protocol. All classes that are subclasses of either ellipse or ellipticalarc must implement methods for these functions.

⇒ ellipse-center-point* elliptical-object [Generic Function]

Returns the center point of elliptical-object as two values representing the coordinate pair.

⇒ ellipse-center-point elliptical-object [Generic Function]

Returns the center point of elliptical-object.

ellipse-center-point is part of the ellipse API, but not part of the ellipse protocol. CLIM will supply default methods for ellipse-center-point on the protocol classes ellipse and

elliptical-arc that are implemented by calling ellipse-center-point*.

⇒ ellipse-radii elliptical-object [Generic Function]

Returns four values corresponding to the two radius vectors of elliptical-arc. These values may be canonicalized in some way, and so may not be the same as the values passed to the constructor function.

⇒ ellipse-start-angle elliptical-object [Generic Function]

Returns the start angle of elliptical-object. If elliptical-object is a full ellipse or closed path then ellipse-start-angle will return nil; otherwise the value will be a number greater than or equal to zero, and less than 2π.

⇒ ellipse-end-angle elliptical-object [Generic Function]

Returns the end angle of elliptical-object. If elliptical-object is a full ellipse or closed path then ellipse-end-angle will return nil; otherwise the value will be a number greater than zero, and less than or equal to 2π.

Bounding Rectangles

4.1 Bounding Rectangles

Every bounded region has a derived bounding rectangle, which is a rectangular region whose sides are parallel to the coordinate axes. Therefore, every bounded region participates in the bounding rectangle protocol. The bounding rectangle for a region is the smallest rectangle that contains every point in the region. However, the bounding rectangle may contain additional points as well. Unbounded regions do not have a bounding rectangle and do not participate in the bounding rectangle protocol. Other objects besides bounded regions participate in the bounding rectangle protocol, such as sheets and output records.

The coordinate system in which the bounding rectangle is maintained depends on the context. For example, the coordinates of the bounding rectangle of a sheet are expressed in the sheet’s parent’s coordinate system. For output records, the coordinates of the bounding rectangle are maintained in the coordinate system of the stream with which the output record is associated.

Note that the bounding rectangle of a transformed region is not in general the same as the result of transforming the bounding rectangle of a region, as shown in Figure 4.1. For transformations that satisfy rectilinear-transformation-p, the following equality holds. For all other transformations, it does not hold.

(region-equal
  (transform-region transformation (bounding-rectangle region))
  (bounding-rectangle (transform-region transformation region)))

CLIM uses bounding rectangles for a variety of purposes. For example, repainting of windows is driven from the bounding rectangle of the window’s viewport, intersected with a “damage” region. The formatting engines used by formatting-table and formatting-graph operate on the bounding rectangles of the output records in the output. Bounding rectangles are also used internally by CLIM to achieve greater efficiency. For instance, when performing hit detection to

Figure 4.1: The bounding rectangle of an output record.

see if the pointer is within the region of an output record, CLIM first checks to see if the pointer is within the bounding rectangle of the output record.

Note that the bounding rectangle for an output record may have a different size depending on the medium on which the output record is rendered. Consider the case of rendering text on different output devices; the font chosen for a particular text style may vary considerably in size from one device to another.

⇒ bounding-rectangle  [Protocol Class]

The protocol class that represents a bounding rectangle. If you want to create a new class that behaves like a bounding rectangle, it should be a subclass of bounding-rectangle. Subclasses of bounding-rectangle must obey the bounding rectangle protocol.

Note that bounding rectangles are not a subclass of rectangle, nor even a subclass of region. This is because, in general, bounding rectangles do not obey the region protocols. However, all bounded regions and sheets that obey the bounding rectangle protocol are subclasses of

bounding-rectangle.

Bounding rectangles are immutable, but since they reflect the live state of such mutable objects as sheets and output records, bounding rectangles are volatile. Therefore, programmers must not depend on the bounding rectangle associated with a mutable object remaining constant.

⇒ bounding-rectangle-p object  [Function]

Returns true if object is a bounding rectangle (that is, supports the bounding rectangle protocol), otherwise returns false.

⇒ standard-bounding-rectangle  [Class]

An instantiable class that implements a bounding rectangle. This is a subclass of both boundingrectangle and rectangle, that is, standard bounding rectangles obey the rectangle protocol.

make-bounding-rectangle returns an object of this class.

The representation of bounding rectangles in CLIM is chosen to be efficient. CLIM will probably represent such rectangles by storing the coordinates of two opposing corners of the rectangle, namely, the “min point” and the “max point”. Because this representation is not sufficient to represent the result of arbitrary transformations of arbitrary rectangles, CLIM is allowed to return a polygon as the result of such a transformation. (The most general class of transformations that is guaranteed to always turn a rectangle into another rectangle is the class of

transformations that satisfy rectilinear-transformation-p.)
⇒ make-bounding-rectangle x1 y1 x2 y2  [Function]

Returns an object of the class standard-bounding-rectangle with the edges specified by x1, y1, x2, and y2, which must be real numbers.

x1, y1, x2, and y2 are “canonicalized” in the following way. The min point of the rectangle has an x coordinate that is the smaller of x1 and x2 and a y coordinate that is the smaller of y1 and y2. The max point of the rectangle has an x coordinate that is the larger of x1 and x2 and a y coordinate that is the larger of y1 and y2. (Therefore, in a right-handed coordinate system the canonicalized values of x1, y1, x2, and y2 correspond to the left, top, right, and bottom edges of the rectangle, respectively.)

This function returns fresh objects that may be modified.

4.1.1 The Bounding Rectangle Protocol

The following generic function comprises the bounding rectangle protocol. All classes that participate in this protocol (including all subclasses of region that are bounded regions) must implement a method for bounding-rectangle*.

⇒ bounding-rectangle* region [Generic Function]

Returns the bounding rectangle of region as four real numbers specifying the x and y coordinates of the min point and the x and y coordinates of the max point of the rectangle. The argument region must be either a bounded region (such as a line or an ellipse) or some other object that obeys the bounding rectangle protocol, such as a sheet or an output record.

The four returned values min-x, min-y, max-x, and max-y will satisfy the inequalities

minx ≤ maxx
miny ≤ maxy

⇒ bounding-rectangle region [Generic Function]

Returns the bounding rectangle of region as an object that is a subclass of rectangle (described in Section 3.2.4). The argument region must be either a bounded region (such as a line or an ellipse) or some other object that obeys the bounding rectangle protocol, such as a sheet or an output record.

It is unspecified whether bounding-rectangle will or will not create a new object each time it is called. Many CLIM implementations will cache the bounding rectangle for sheets and output records. The implication of this is that, since bounding rectangles are volatile, programmers should depend on the object returned by bounding-rectangle remaining constant.

bounding-rectangle is part of the bounding rectangle API, but not part of the bounding rectangle protocol. CLIM will supply a default method for bounding-rectangle on the protocol

class bounding-rectangle that is implemented by calling bounding-rectangle*.

4.1.2 Bounding Rectangle Convenience Functions

The functions described below are part of the bounding rectangle API, but are not part of the bounding rectangle protocol. They are provided as a convenience to programmers who wish to specialize classes that participate in the bounding rectangle protocol, but do not complicate the task of those programmers who define their own types (such as sheet classes) that participate in this protocol.

CLIM will supply default methods for all of these generic functions on the protocol class

bounding-rectangle that are implemented by calling bounding-rectangle*.

⇒ with-bounding-rectangle* (min-x min-y max-x max-y) region &body body [Macro]

Binds min-x, min-y, max-x, and max-y to the edges of the bounding rectangle of region, and then executes body in that context. The argument region must be either a bounded region (such as a line or an ellipse) or some other object that obeys the bounding rectangle protocol, such as a sheet or an output record.

The arguments min-x, min-y, max-x, and max-y are not evaluated. body may have zero or more declarations as its first forms.

with-bounding-rectangle* must be implemented by calling bounding-rectangle*.
⇒ bounding-rectangle-position* region  [Generic Function]

Returns the position of the bounding rectangle of region. The position of a bounding rectangle is specified by its min point.

⇒ bounding-rectangle-min-x region  [Generic Function]
⇒ bounding-rectangle-min-y region  [Generic Function]
⇒ bounding-rectangle-max-x region  [Generic Function]
⇒ bounding-rectangle-max-y region  [Generic Function]

Returns (respectively) the x and y coordinates of the min point and the x and y coordinate of the max point of the bounding rectangle of region. The argument region must be either a bounded region or some other object that obeys the bounding rectangle protocol.

⇒ bounding-rectangle-width region  [Generic Function]
⇒ bounding-rectangle-height region  [Generic Function]

⇒ bounding-rectangle-size region [Generic Function]

Returns the width, height, or size (as two values, the width and height) of the bounding rectangle of region, respectively. The argument region must be either a bounded region or some other object that obeys the bounding rectangle protocol.

The width of a bounding rectangle is the difference between its maximum x coordinate and its minimum x coordinate. The height is the difference between the maximum y coordinate and its minimum y coordinate.

Affine Transformations

An affine transformation is a mapping from one coordinate system onto another that preserves straight lines. In other words, if you take a number of points that fall on a straight line and apply an affine transformation to their coordinates, the transformed coordinates will describe a straight line in the new coordinate system. General affine transformations include all the sorts of transformations that CLIM uses, namely, translations, scaling, rotations, and reflections.

5.1 Transformations

⇒ transformation [Protocol Class]

The protocol class of all transformations. There are one or more subclasses of transformation with implementation-dependent names that implement transformations. The exact names of these classes is explicitly unspecified. If you want to create a new class that behaves like a transformation, it should be a subclass of transformation. Subclasses of transformation must obey the transformation protocol.

All of the instantiable transformation classes provided by CLIM are immutable.

⇒ transformationp object [Function]

Returns true if object is a transformation, otherwise returns false.

⇒ +identity-transformation+  [Constant]

An instance of a transformation that is guaranteed to be an identity transformation, that is, the transformation that “does nothing”.

5.1.1 Transformation Conditions

⇒ transformation-error  [Condition]

The class that is the superclass of the following three conditions. This class is a subclass of

error.
⇒ transformation-underspecified  [Condition]

The error that is signalled when make-3-point-transformation is given three collinear image points.

⇒ reflection-underspecified  [Condition]

The error that is signalled when make-reflection-transformation is given two coincident points.

⇒ singular-transformation  [Condition]

The error that is signalled when invert-transformation is called on a singular transformation, that is, a transformation that has no inverse.

5.2 Transformation Constructors

The following transformation constructors do not capture any of their inputs. The constructors all create objects that are subclasses of transformation.

⇒ make-translation-transformation translation-x translation-y [Function]

A translation is a transformation that preserves length, angle, and orientation of all geometric entities.

make-translation-transformation returns a transformation that translates all points by translationx in the x direction and translation-y in the y direction. translation-x and translation-y must be real numbers.

⇒ make-rotation-transformation angle &optional origin  [Function]
⇒ make-rotation-transformation* angle &optional origin-x origin-y  [Function]

A rotation is a transformation that preserves length and angles of all geometric entities. Rotations also preserve one point (the origin) and the distance of all entities from that point.

make-rotation-transformation returns a transformation that rotates all points by angle (which is a real number indicating an angle in radians) around the point origin. If origin is supplied it must be a point; if not supplied it defaults to (0, 0). origin-x and origin-y must be real numbers.

⇒ make-scaling-transformation scale-x scale-y &optional origin  [Function]

⇒ make-scaling-transformation* scale-x scale-y &optional origin-x origin-y [Function] There is no single definition of a scaling transformation. Transformations that preserve all angles and multiply all lengths by the same factor (preserving the “shape” of all entities) are certainly scaling transformations. However, scaling is also used to refer to transformations that scale distances in the x direction by one amount and distances in the y direction by another amount.

make-scaling-transformation returns a transformation that multiplies the x-coordinate distance of every point from origin by scale-x and the y-coordinate distance of every point from origin by scale-y. scale-x and scale-y must be real numbers. If origin is supplied it must be a point; if not supplied it defaults to (0, 0). origin-x and origin-y must be real numbers.

⇒ make-reflection-transformation point1 point2  [Function]
⇒ make-reflection-transformation* x1 y1 x2 y2  [Function]

A reflection is a transformation that preserves lengths and magnitudes of angles, but changes the sign (or “handedness”) of angles. If you think of the drawing plane on a transparent sheet of paper, a reflection is a transformation that “turns the paper over”.

make-reflection-transformation returns a transformation that reflects every point through the line passing through the points point1 and point2 (or through the positions (x1, y1) and (x2, y2) in the case of the spread version).

⇒ make-transformation mxx mxy myx myy tx ty [Function]

Returns a general transformation whose effect is:

x′ = m_{xx}x + m_{xy}y + t_{x}
y′ = m_{yx}x + m_{yy}y + t_{y}

where x and y are the coordinates of a point before the transformation and x′ and y′ are the coordinates of the corresponding point after.

All of the arguments to make-transformation must be real numbers.

⇒ make-3-point-transformation point-1 point-2 point-3 point-1-image point-2-image point-3-image [Function]

Returns a transformation that takes points point-1 into point-1-image, point-2 into point-2-image and point-3 into point-3-image. Three non-collinear points and their images under the transformation are enough to specify any affine transformation.

If point-1, point-2 and point-3 are collinear, the transformation-underspecified error will be signalled. If point-1-image, point-2-image and point-3-image are collinear, the resulting transformation will be singular (that is, will have no inverse) but this is not an error.

⇒ make-3-point-transformation* x1 y1 x2 y2 x3 y3 x1-image y1-image x2-image y2-image x3image y3-image [Function]

Returns a transformation that takes the points at the positions (x1,y1) into (x1-image,y1-image), (x2,y2) into (x2-image,y2-image) and (x3,y3) into (x3-image,y3-image). Three non-collinear points and their images under the transformation are enough to specify any affine transformation.

If the positions (x1, y1), (x2, y2) and (x3, y3) are collinear, the transformation-underspecified error will be signalled. If (x1-image,y1-image), (x2-image,y2-image), and (x3-image,y3-image) are collinear, the resulting transformation will be singular but this is not an error.

This is the spread version of make-3-point-transformation.

5.3 The Transformation Protocol

The following subsections describe the transformation protocol. All classes that are subclasses of transformation must implement methods for all of the generic functions in the following subsections.

5.3.1 Transformation Predicates

In all of the functions below, the argument named transformation must be a transformation.

⇒ transformation-equal transformation1 transformation2 [Generic Function]

Returns true if the two transformations transformation1 and transformation2 have equivalent effects (that is, are mathematically equal), otherwise returns false.

Implementations are encouraged to allow transformations that are not numerically equal due to floating-point roundoff errors to be transformation-equal. An appropriate level of “fuzziness”

is single-float-epsilon, or some small multiple of single-float-epsilon.

⇒ identity-transformation-p transformation [Generic Function]

Returns true if the transformation transformation is equal (in the sense of transformationequal) to the identity transformation, otherwise returns false.

⇒ invertible-transformation-p transformation [Generic Function]

Returns true if the transformation transformation has an inverse, otherwise returns false.

⇒ translation-transformation-p transformation [Generic Function]

Returns true if the transformation transformation is a pure translation, that is, a transformation such that there are two distance components dx and dy and every point (x, y) is moved to (x + dx, y + dy). Otherwise, translation-transformation-p returns false.

⇒ reflection-transformation-p transformation [Generic Function]

Returns true if the transformation transformation inverts the “handedness” of the coordinate

Figure 5.1: The predicates for analyzing the mathematical properties of a transformation.

system, otherwise returns false. Note that this is a very inclusive category—transformations are considered reflections even if they distort, scale, or skew the coordinate system, as long as they invert the handedness.

⇒ rigid-transformation-p transformation [Generic Function]

Returns true if the transformation transformation transforms the coordinate system as a rigid object, that is, as a combination of translations, rotations, and pure reflections. Otherwise, it returns false.

Rigid transformations are the most general category of transformations that preserve magnitudes of all lengths and angles.

⇒ even-scaling-transformation-p transformation [Generic Function]

Returns true if the transformation transformation multiplies all x lengths and y lengths by the same magnitude, otherwise returns false. It does include pure reflections through vertical and horizontal lines.

⇒ scaling-transformation-p transformation [Generic Function]

Returns true if the transformation transformation multiplies all x lengths by one magnitude and all y lengths by another magnitude, otherwise returns false. This category includes even scalings as a subset.

⇒ rectilinear-transformation-p transformation [Generic Function]

Returns true if the transformation transformation will always transform any axis-aligned rectangle into another axis-aligned rectangle, otherwise returns false. This category includes scalings as a subset, and also includes 90 degree rotations.

Rectilinear transformations are the most general category of transformations for which the bounding rectangle of a transformed object can be found by transforming the bounding rectangle of the original object.

5.3.2 Composition of Transformations

If we transform from one coordinate system to another, then from the second to a third coordinate system, we can regard the resulting transformation as a single transformation resulting from composing the two component transformations. It is an important and useful property of affine transformations that they are closed under composition. Note that composition is not commutative; in general, the result of applying transformation A and then applying transformation B is not the same as applying B first, then A.

Any arbitrary transformation can be built up by composing a number of simpler transformations,

but that composition is not unique.

⇒ compose-transformations transformation1 transformation2 [Generic Function]

Returns a transformation that is the mathematical composition of its arguments. Composition is in right-to-left order, that is, the resulting transformation represents the effects of applying the transformation transformation2 followed by the transformation transformation1.

⇒ invert-transformation transformation [Generic Function]

Returns a transformation that is the inverse of the transformation transformation. The result of composing a transformation with its inverse is equal to the identity transformation.

If transformation is singular, invert-transformation will signal the singular-transformation

error, with a named restart that is invoked with a transformation and makes invert-transformation return that transformation. This is to allow a drawing application, for example, to use a generalized inverse to transform a region through a singular transformation.

Note that with finite-precision arithmetic there are several low-level conditions that might occur during the attempt to invert a singular or “almost singular” transformation. (These include computation of a zero determinant, floating-point underflow during computation of the determinant, or floating-point overflow during subsequent multiplication.) invert-transformation must signal the singular-transformation error for all of these cases.

⇒ compose-translation-with-transformation transformation dx dy  [Function]
⇒ compose-scaling-with-transformation transformation sx sy &optional origin [Function]
⇒ compose-rotation-with-transformation transformation angle &optional origin [Function]

These functions create a new transformation by composing the transformation transformation with a given translation, scaling, or rotation, respectively. The order of composition is that the translation, scaling, or rotation “transformation” is first, followed by transformation.

dx and dy are as for make-translation-transformation. sx and sy are as for make-scaling-
transformation. angle and origin are as for make-rotation-transformation.

Note that these functions could be implemented by using the various constructors and composetransformations. They are provided, because it is common to build up a transformation as a series of simple transformations.

⇒ compose-transformation-with-translation transformation dx dy  [Function]
⇒ compose-transformation-with-scaling transformation sx sy &optional origin [Function]
⇒ compose-transformation-with-rotation transformation angle &optional origin [Function]

These functions create a new transformation by composing a given translation, scaling, or rotation, respectively, with the transformation transformation. The order of composition is transformation is first, followed by the translation, scaling, or rotation “transformation”.

dx and dy are as for make-translation-transformation. sx and sy are as for make-scaling-

transformation. angle and origin are as for make-rotation-transformation.

Note that these functions could be implemented by using the various constructors and composetransformations. They are provided, because it is common to build up a transformation as a series of simple transformations.

5.3.3 Applying Transformations

Transforming a region applies a coordinate transformation to that region, thus moving its position on the drawing plane, rotating it, or scaling it. Note that transforming a region does not side-effect the region argument; it is free to either create a new region or return an existing (cached) region.

These generic functions must be implemented for all classes of transformations. Furthermore, all subclasses of region and design must implement methods for transform-region and untransform-region. That is, methods for the following generic functions will typically specialize both the transformation and region arguments.

⇒ transform-region transformation region [Generic Function]

Applies transformation to the region region, and returns the transformed region.

⇒ untransform-region transformation region [Generic Function]

This is exactly equivalent to

(transform-region (invert-transformation transformation) region) .

CLIM provides a default method for untransform-region on the transformation protocol class that does exactly this.

⇒ transform-point* transformation x y [Generic Function]

Applies the transformation transformation to the point whose coordinates are the real numbers x and y, and returns two values, the transformed x coordinate and the transformed y coordinate.

transform-point* is the spread version of transform-region in the case where the region is a point.

⇒ untransform-point* transformation x y [Generic Function]

This is exactly equivalent to

(transform-point* (invert-transformation transformation) x y) .

CLIM provides a default method for untransform-point* on the transformation protocol class that does exactly this.

⇒ transform-distance transformation dx dy [Generic Function]

Applies the transformation transformation to the distance represented by the real numbers dx CHAPTER 5. AFFINE TRANSFORMATIONS 40

and dy, and returns two values, the transformed dx and the transformed dy. A distance represents the difference between two points. It does not transform like a point.

⇒ untransform-distance transformation dx dy [Generic Function] This is exactly equivalent to

(transform-distance (invert-transformation transformation) dx dy) .

CLIM provides a default method for untransform-distance on the transformation protocol class that does exactly this.

⇒ transform-rectangle* transformation x1 y1 x2 y2 [Generic Function] Applies the transformation transformation to the rectangle specified by the four coordinate arguments, which are real numbers. The arguments x1, y1, x2, and y1 are canonicalized in the same way as for make-bounding-rectangle. Returns four values that specify the minimum and maximum points of the transformed rectangle in the order min-x, min-y, max-x, and max-y. It is an error is transformation does not satisfy rectilinear-transformation-p. transform-rectangle* is the spread version of transform-region in the case where the transformation is rectilinear and the region is a rectangle.

⇒ untransform-rectangle* transformation x1 y1 x2 y2 [Generic Function] This is exactly equivalent to

(transform-rectangle* (invert-transformation transformation) x1 y1 x2 y2) .

CLIM provides a default method for untransform-rectangle* on the transformation protocol class that does exactly this.

Part III

Windowing Substrate Overview of Window Facilities

6.1 Introduction

A central notion in organizing graphical user interfaces is allocating screen regions to particular tasks and recursively subdividing these regions into subregions. The layer of CLIM known as Silica defines an extensible framework for constructing, using, and managing such hierarchies of interactive regions. This framework allows uniform treatment of the following things:

• Window objects like those in X or NeWS.

• Lightweight gadgets typical of toolkit layers.

• Structured graphics like output records and an application’s presentation objects.

• Objects that act as Lisp handles for windows or gadgets implemented in a different language (such as OpenLook gadgets implemented in C).

From the perspective of most CLIM users, Silica plays the role of a window system. However Silica will usually utilize the services of a window system platform to provide efficient windowing, input, and output facilities. In this specification, such window system platforms will be referred to as host window or display servers.

The fundamental abstraction defined by Silica is called a sheet. A sheet can participate in a relationship called a windowing relationship. This relationship is one in which one sheet called the parent provides space to a number of other sheets called children. Support for establishing and maintaining this kind of relationship is the essence of what window systems provide. At any point in time, Silica allows a sheet to be a child in one relationship called its youth windowing relationship and a parent in another relationship called its adult windowing relationship.

Programmers can manipulate unrooted hierarchies of sheets (those without a connection to any particular display server). However, a sheet hierarchy must be attached to a display server to make it visible. Ports and grafts provide the functionality for managing this capability. A port is an abstract connection to a display service that is responsible for managing host display server resources and for processing input events received from the host display server. A graft is a special kind of sheet that represents a host window, typically a root window (that is, a screenlevel window). A sheet is attached to a display by making it a child of a graft, which represents an appropriate host window. The sheet will then appear to be a child of that host window. So, a sheet is put onto a particular screen by making it a child of an appropriate graft and enabling it. Ports and grafts are described in detail in Chapter 9.

Issue: An open issue in Silica’s design is allowing a sheet to participate in multiple youth relationships. — RSL

Issue: Allowing a sheet to have multiple parents at different times is necessary for allowing the same pane to appear in multiple layouts of a frame. We need to resolve this. — SWM

6.2 Properties of Sheets

Sheets have the following properties:

A coordinate system Provides the ability to refer to locations in a sheet’s abstract plane.

A region Defines an area within a sheet’s coordinate system that indicates the area of interest within the plane, that is, a clipping region for output and input. This typically corresponds to the visible region of the sheet on the display.

A parent A sheet that is the parent in a windowing relationship in which this sheet is a child.

Children An ordered set of sheets that are each a child in a windowing relationship in which this sheet is a parent. The ordering of the set corresponds to the stacking order of the sheets. Not all sheets have children.

A transformation Determines how points in this sheet’s coordinate system are mapped into points in its parents.

An enabled flag Indicates whether the sheet is currently actively participating in the windowing relationship with its parent and siblings.

An event handler A procedure invoked when the display server wishes to inform CLIM of external events.

Output state A set of values used when CLIM causes graphical or textual output to appear on the display. This state is often represented by a medium.

6.3 Sheet Protocols

A sheet is a participant in a number of protocols. Every sheet must provide methods for the generic functions that make up these protocols. These protocols are:

The windowing protocol Describes the relationships between the sheet and its parent and children (and, by extension, all of its ancestors and descendants).

The input protocol Provides the event handler for a sheet. Events may be handled synchronously, asynchronously, or not at all.

The output protocol Provides graphical and textual output, and manages descriptive output state such as color, transformation, and clipping.

The repaint protocol Invoked by the event handler and by user programs to ensure that the output appearing on the display device appears as the program expects it to appear.

The notification protocol Invoked by the event handler and user programs to ensure that CLIM’s representation of window system information is equivalent to the display server’s.

These protocols may be handled directly by a sheet, queued for later processing by some other agent, or passed on to a delegate sheet for further processing.

6.4 Sample Silica Program

(defun test-silica ()
(let* ((sheet
      (make-standard-sheet :parent (find-graft)
                           :transformation (make-translation 100 100)
                           :region (make-rectangle 0 0 200 200 )))
     (w (bounding-rectangle-width sheet))
     (h (bounding-rectangle-height sheet))
     (x1 (/ w 4))
     (y1 (/ h 4))
     (x2 (* 3 (/ w 4)))
     (y2 (* 3 (/ h 4))))
(enable-sheet sheet t)
(draw-line sheet (make-point x1 y1) (make-point x1 y2))
(draw-line sheet (make-point x1 y2) (make-point x2 y2))
(draw-line sheet (make-point x2 y2) (make-point x2 y1))
(draw-line sheet (make-point x2 y1) (make-point x1 y1))
(draw-line* sheet x1 y1 x2 y2)
(draw-line* sheet x1 y2 x2 y1)
(output-finish sheet)
(sleep 1)
(disable-sheet sheet)
(sheet-disown-child (sheet-parent sheet) sheet)))

Issue: This needs to be a set of more compelling examples. — York

Properties of Sheets

⇒ sheet [Protocol Class]

The protocol class that corresponds to a sheet, a subclass of bounding-rectangle. This and the next chapter describe all of the sheet protocols. If you want to create a new class that behaves like a sheet, it should be a subclass of sheet. Subclasses of sheet must obey the sheet protocol.

All of the subclasses of sheet are mutable.

⇒ sheetp object [Function]

Returns true if object is a sheet, otherwise returns false.

7.1 Relationships Between Sheets

Sheets are arranged in a tree-structured, acyclic, top-down hierarchy. Thus, in general, a sheet has one parent (or no parent) and zero or more children. A sheet may have zero or more siblings (that is, other sheets that share the same parent). In order to describe the relationships between sheets, we need to define some terms.

Adopted A sheet is said to be adopted if it has a parent. A sheet becomes the parent of another sheet by adopting that sheet.

Disowned A sheet is said to be disowned if it does not have a parent. A sheet ceases to be a child of another sheet by being disowned.

Grafted A sheet is said to be grafted when it is part of a sheet hierarchy whose highest ancestor is a graft. In this case, the sheet may be visible on a particular window server.

Degrafted A sheet is said to be degrafted when it is part of a sheet hierarchy that cannot possibly be visible on a server, that is, the highest ancestor is not a graft.

Enabled A sheet is said to be enabled when it is actively participating in the windowing relationship with its parent. If a sheet is enabled and grafted, and all its ancestors are enabled (they are grafted by definition), then the sheet will be visible if it occupies a portion of the graft region that isn’t clipped by its ancestors or ancestor’s siblings.

Disabled The opposite of enabled is disabled.

7.1.1 Sheet Relationship Functions

The generic functions in this section comprise the sheet protocol. All sheet objects must implement methods for each of these generic functions.

Issue: Is the above statement accurate? — SWM

⇒ sheet-parent sheet [Generic Function]

Returns the parent of the sheet sheet, or nil if the sheet has no parent.

⇒ sheet-children sheet [Generic Function]

Returns a list of sheets that are the children of the sheet sheet. Some sheet classes support only a single child; in this case, the result of sheet-children will be a list of one element. This function returns objects that reveal CLIM’s internal state; do not modify those objects.

⇒ sheet-adopt-child sheet child [Generic Function]

Adds the child sheet child to the set of children of the sheet sheet, and makes the sheet the child’s parent. If child already has a parent, the sheet-already-has-parent error will be signalled.

Some sheet classes support only a single child. For such sheets, attempting to adopt more than a single child will cause the sheet-supports-only-one-child error to be signalled.

⇒ sheet-disown-child sheet child [Generic Function]

Removes the child sheet child from the set of children of the sheet sheet, and makes the parent of the child be nil. If child is not actually a child of sheet, the sheet-is-not-child error will be signalled.

⇒ sheet-siblings sheet [Generic Function]

Returns a list of all of the siblings of the sheet sheet. The sibling are all of the children of sheet’s parent excluding sheet itself. This function returns fresh objects that may be modified.

⇒ sheet-enabled-children sheet [Generic Function]

Returns a list of those children of the sheet sheet that are enabled. This function returns fresh objects that may be modified.

⇒ sheet-ancestor-p sheet putative-ancestor [Generic Function] Returns true if the the sheet putative-ancestor is in fact an ancestor of the sheet sheet, otherwise returns false.

⇒ raise-sheet sheet [Generic Function] ⇒ bury-sheet sheet [Generic Function]

These functions reorder the children of a sheet by raising the sheet sheet to the top or burying it at the bottom. Raising a sheet puts it at the beginning of the ordering; burying it puts it at the end. If sheets overlap, the one that appears “on top” on the display device is earlier in the ordering than the one underneath.

This may change which parts of which sheets are visible on the display device.

⇒ reorder-sheets sheet new-ordering [Generic Function]

Reorders the children of the sheet sheet to have the new ordering specified by new-ordering. new-ordering is an ordered list of the child sheets; elements at the front of new-ordering are “on top” of elements at the rear.

If new-ordering does not contain all of the children of sheet, the sheet-ordering-underspecified error will be signalled. If new-ordering contains a sheet that is not a child of sheet, the sheetis-not-child error will be signalled.

⇒ sheet-enabled-p sheet [Generic Function]

Returns true if the the sheet sheet is enabled by its parent, otherwise returns false. Note that all of a sheet’s ancestors must be enabled before the sheet is viewable.

⇒ (setf sheet-enabled-p) enabled-p sheet [Generic Function]

When enabled-p is true, this enables the the sheet sheet. When enabled-p is false, this disables the sheet.

Note that a sheet is not visible unless it and all of its ancestors are enabled.

⇒ sheet-viewable-p sheet [Generic Function]

Returns true if the sheet sheet and all its ancestors are enabled, and if one of its ancestors is a graft. See Chapter 9 for further information.

⇒ sheet-occluding-sheets sheet child [Generic Function]

Returns a list of the sheet child’s siblings that occlude part or all of the region of the child. In general, these are the siblings that are enabled and appear earlier in the sheet sheet’s children. If sheet does not permit overlapping among its children, sheet-occluding-sheets will return

nil.

This function returns fresh objects that may be modified.

7.1.2 Sheet Genealogy Classes

Different “mixin” classes are provided that implement the relationship protocol.

⇒ sheet-leaf-mixin  [Class]

This class is mixed into sheet classes that will never have children.

⇒ sheet-single-child-mixin  [Class]

This class is mixed into sheet classes that have at most a single child.

⇒ sheet-multiple-child-mixin  [Class]

This class is mixed into sheet classes that may have zero or more children.

7.2 Sheet Geometry

Every sheet has a region and a coordinate system. A sheet’s region refers to its position and extent on the display device, and is represented by some sort of a region object, frequently a rectangle. A sheet’s coordinate system is represented by a coordinate transformation that converts coordinates in its coordinate system to coordinates in its parent’s coordinate system.

7.2.1 Sheet Geometry Functions

⇒ sheet-transformation sheet [Generic Function] ⇒ (setf sheet-transformation) transformation sheet [Generic Function]

Returns a transformation that converts coordinates in the sheet sheet’s coordinate system into coordinates in its parent’s coordinate system. Using setf on this accessor will modify the sheet’s coordinate system, including moving its region in its parent’s coordinate system.

⇒ sheet-region sheet [Generic Function] ⇒ (setf sheet-region) region sheet [Generic Function]

Returns a region object that represents the set of points to which the sheet sheet refers. The region is in the sheet’s coordinate system. Using setf on this accessor modifies the sheet’s region.

Issue: Aren’t there some notification functions that get called when the sheet’s region and transformation are changed? — SWM

Issue: I’m not convinced I like this business of requesting a change by modifying an accessor. It would actually be better to have a request- function, so it would be clear that there might be some delay before the region or transformation was modified. — RSL Issue: To reshape and move a region, you generally have to manipulate both of the above. Maybe there should be a single function that takes either or both of a new transformation or region? Maybe region coordinates should be expressed in parents’ coordinates, since that’s easier to set only one? — RSL

Issue: Using setf on mirrored sheets actually requests that the server move/resize the sheet; the accessor will continue to return the old value until the notification comes in saying that the mirror has been moved. — RSL

⇒ map-sheet-point*-to-parent sheet x y  [Generic Function]

Applies the sheet sheet’s transformation to the point (x, y), returning the coordinates of that point in sheet’s parent’s coordinate system.

⇒ map-sheet-point*-to-child sheet x y  [Generic Function]

Applies the inverse of the sheet sheet’s transformation to the point (x, y) (represented in sheet’s parent’s coordinate system), returning the coordinates of that same point in sheet coordinate system.

⇒ map-sheet-bounding-rectangle*-to-parent sheet x1 y1 x2 y2  [Generic Function]

Applies the sheet sheet’s transformation to the bounding rectangle specified by the corner points (x1, y1) and (x2, y2), returning the bounding rectangle of the transformed region as four values, min-x, min-y, max-x, and max-y. The arguments x1, y1, x2, and y1 are canonicalized in the

same way as for make-bounding-rectangle.
⇒ map-sheet-bounding-rectangle*-to-child sheet x1 y1 x2 y2  [Generic Function]

Applies the inverse of the sheet sheet’s transformation to the bounding rectangle delimited by the corner points (x1, y1) and (x2, y2) (represented in sheet’s parent’s coordinate system), returning the bounding rectangle of the transformed region as four values, min-x, min-y, max-x, and maxy. The arguments x1, y1, x2, and y1 are canonicalized in the same way as for make-bounding-

rectangle.

⇒ child-containing-point sheet point [Generic Function] ⇒ child-containing-point* sheet x y [Generic Function]

Returns the topmost (earliest) enabled child of the sheet sheet whose region contains the point point (or the position (x, y)). The point is expressed in sheet’s coordinate system.

Issue: What does “earliest” mean exactly in this context? And does it return the earliest child, or the earliest descendant? And does it return an enabled sheet, or any sheet? — SWM

⇒ children-overlapping-region sheet region [Generic Function]

⇒ children-overlapping-rectangle* sheet x1 y1 x2 y2  [Generic Function]

Returns the list of enabled children of the sheet sheet whose region overlaps the region re-

gion. children-overlapping-rectangle* is a special case of children-overlapping-region

in which the region is a bounding rectangle whose corner points are (x1, y1) and (x2, y2). The region is expressed in sheet’s coordinate system. This function returns fresh objects that may

be modified.

⇒ sheet-delta-transformation sheet ancestor [Generic Function]

Returns a transformation that is the composition of all of the sheet transformations between the sheets sheet and ancestor. If ancestor is nil, sheet-delta-transformation will return the transformation to the root of the sheet hierarchy. If ancestor is not an ancestor of sheet, the

sheet-is-not-ancestor error will be signalled.

The computation of the delta transformation is likely to be cached.

Issue: This used to be called fetch-delta-transformation, right? — SWM

⇒ sheet-allocated-region sheet child [Generic Function]

Returns the visible region of the sheet child in the sheet sheet’s coordinate system. If child is occluded by any of its siblings, those siblings’ regions are subtracted (using region-difference) from child’s actual region.

7.2.2 Sheet Geometry Classes

Each of the following implements the sheet geometry protocol in a different manner, according to the sheet’s requirements.

⇒ sheet-identity-transformation-mixin  [Class]

This class is mixed into sheet classes whose coordinate system is identical to that of its parent.

⇒ sheet-translation-mixin  [Class]

This class is mixed into sheet classes whose coordinate system is related to that of its parent by a simple translation.

⇒ sheet-y-inverting-transformation-mixin  [Class]

This class is mixed into sheet classes whose coordinate system is related to that of its parent by inverting the y coordinate system, and optionally translating by some amount in x and y.

⇒ sheet-transformation-mixin  [Class]

This class is mixed into sheet classes whose coordinate system is related to that of its parent by an arbitrary affine transformation.

7.3 Creating Sheets

Issue: Still needs fleshing out. I’m trying to eliminate contracts from this entire chapter, so I need to figure out how much we want to say here. It may be sufficient to have a function make-sheet that takes a class object and some initialization keywords, and perhaps some interface to the runtime dynamic class stuff. — RSL

⇒ make-sheet ??? [Function]

⇒ make-standard-sheet ???  [Function]

Sheet Protocols

8.1 Input Protocol

CLIM’s windowing substrate provides an input architecture and standard functionality for notifying clients of input that is distributed to their sheets. Input includes such events as the pointer entering and exiting sheets, pointer motion (whose granularity is defined by performance limitations), and pointer button and keyboard events. At this level, input is represented as event objects.

Sheets either participate fully in the input protocol or are mute for input. If any functions in the input protocol are called on a sheet that is mute for input, the sheet-is-mute-for-input error will be signalled.

Input is processed on a per-port basis by the function process-next-event. In multiprocessing environments, a process that calls process-next-event in a loop is created for each port. In single-process Lisps, process-next-event is called whenever the user would go blocked for input.

process-next-event has three main tasks when it receives an event. First, it must determine to which client the event is addressed. Typically, the client is a sheet, but there are other specialpurpose clients to which events can also be dispatched. Next, process-next-event formats the event into a standard format, and finally it distributes the event to the client. A client may then either handle the event synchronously, or it may queue it for later handling by another process.

Input events can be broadly categorized into pointer events and keyboard events. By default, pointer events are dispatched to the lowest sheet in the hierarchy whose region contains the location of the pointer. Keyboard events are dispatched to the port’s keyboard input focus; the accessor port-keyboard-input-focus contains the event client that receives the port’s keyboard events.

Issue: Can someone explain to me the exact distinction between dispatching, distributing, and processing? — SWM

8.1.1 Input Protocol Functions

Issue: Do we want to advertise sheet-event-queue? Probably not. — SWM

⇒ process-next-event port &key wait-function timeout [Generic Function]

This function provides a standard interface for one pass through a port’s event processing loop. wait-function is either nil or a function of no arguments that acts as a predicate; it has dynamic extent. The predicate should wait until one of three conditions occurs:

• If an event if received and processed, the predicate should return true.

• If a timeout occurs, the predicate should return false.

• If the wait function returns true, the predicate should return the two values false and

     :timeout.

A port implementation must provide a method for this function that reads the next window server-specific device event, blocking if necessary, and then invokes the event distributor.

⇒ port-keyboard-input-focus port  [Generic Function]
⇒ (setf port-keyboard-input-focus) focus port  [Generic Function]

Returns the client to which keyboard events are to be dispatched.

Issue: Name of this accessor? Maybe it should just be keyboard-input-focus. We might like to have this object be a frame, which in turn might also want to have a per-frame focus sheet or pane or mosaic or whatever. — RSL

⇒ distribute-event port event [Generic Function]

The event is distributed to the port’s proper client. In general, this will be the keyboard input focus for keyboard events, and the lowest sheet under the pointer for pointer events.

Issue: Do we just want to call this function dispatch-event and have it called on the port first?

— RSL

⇒ dispatch-event client event [Generic Function]

This function is called by process-next-event to inform a client about an event of interest. It is invoked synchronously by whatever process called process-next-event, so many methods for this function will simply queue the event for later handling. Certain classes of clients and events may cause this function immediately to call either queue-event or handle-event, or to ignore the event entirely.

Issue: What exactly is a “client”? It says above that it can be something other than a sheet, but what are those other things? — SWM ⇒ queue-event client event [Generic Function]

Places the event event into the queue of events for the client client.

⇒ handle-event client event [Generic Function]

Implements the client’s policy with respect to the event. For example, if the programmer wishes to highlight a sheet in response to an event that informs it that the pointer has entered its territory, there would be a method to carry out the policy that specializes the appropriate sheet and event classes.

In addition to queue-event, the queued input protocol handles the following generic functions:

Issue: These names are subject to change. — RSL

⇒ event-read client [Generic Function]

Takes the next event out of the queue of events for this client.

⇒ event-read-no-hang client [Generic Function]

Takes the next event out of the queue of events for this client. It returns nil if there are no events in the queue.

⇒ event-peek client &optional event-type [Generic Function]

Returns the next event in the queue without removing it from the queue. If event-type is supplied, events that are not of that type are first removed and discarded.

⇒ event-unread client event [Generic Function]

Places the event at the head of the client’s event queue, so as to be the next event read.

⇒ event-listen client [Generic Function]

Returns true if there are any events queued for client, otherwise returns false.

8.1.2 Input Protocol Classes

Issue: Maybe these names should be -client- and not -sheet-? For example, standard-input-client

instead of standard-sheet-input-mixin? — RSL

Most classes of sheets will have one of the following input protocol classes mixed in. Of course, a sheet can always have a specialized method for a specific class of event that will override the default. For example, a sheet may need to have only pointer click events dispatched to itself, and may delegate all other events to some other input client. Such a sheet should have delegatesheet-input-mixin as a superclass, and have a more specific method for dispatch-event on its class and click-event.

⇒ standard-sheet-input-mixin  [Class]

This class of sheet provides a method for dispatch-event that calls queue-event on each device event. Note that configuration events invoke handle-event immediately.

⇒ immediate-sheet-input-mixin  [Class]

Issue: Is this a good name? RWK proposed this. Anybody have other opinions? — RSL

This class of sheet provides a method for dispatch-event that calls handle-event immediately for all events.

⇒ mute-sheet-input-mixin  [Class]
⇒ delegate-sheet-input-mixin  [Class]

Issue: Is this a good name? — RSL

This class of sheet provides a method for dispatch-event that calls dispatch-event on a designated substitute and the event. The initialization argument :delegate or the accessor delegate-sheet-delegate may be used to set the recipient of dispatched events.

Issue: What is a “substitute” and how do you “designate” it? Is the substitute what delegate-sheet-delegate returns? Does’t this want an initarg for the substitute? — SWM

⇒ delegate-sheet-delegate sheet  [Generic Function]

⇒ (setf delegate-sheet-delegate) delegate sheet [Generic Function]

This may be set to another recipient of events dispatched to a sheet of class delegate-sheet-input-mixin. If the delegate is nil, events are discarded.

8.2 Standard Device Events

An event is a CLIM object that represents some sort of user gesture (such as moving the pointer or pressing a key on the keyboard) or that corresponds to some sort of notification from the display server. Event objects store such things as the sheet associated with the event, the x and y bposition of the pointer within that sheet, the key name or character corresponding to a key on the keyboard, and so forth.

Figure 8.1 shows all the event classes.

⇒ event [Protocol Class]

The protocol class that corresponds to any sort of “event”. If you want to create a new class that behaves like an event, it should be a subclass of event. Subclasses of event must obey the event protocol.

All of the event classes are immutable.

event
   device-event
      keyboard-event
         key-press-event
         key-release-event
      pointer-event
         pointer-button-event
           pointer-button-press-event
           pointer-button-release-event
           pointer-button-hold-event
         pointer-motion-event
           pointer-enter-event
           pointer-exit-event
   window-event
      window-configuration-event
      window-repaint-event
   timer-event

Figure 8.1: CLIM event classes. All classes that appear at a given indentation are subclasses of the class that appears above and at a lesser indentation.

⇒ eventp object [Function]

Returns true if object is an event, otherwise returns false.

⇒ :timestamp  [Init Arg]

All subclasses of event must take a :timestamp initarg, which is used to specify the timestamp for the event.

⇒ event-timestamp event [Generic Function]

Returns an integer that is a monotonically increasing timestamp for the the event event. The timestamp must have at least as many bits of precision as a fixnum.

⇒ event-type event [Generic Function]

For the event event, returns a keyword with the same name as the class name, except stripped of the “-event” ending. For example, the keyword :key-press is returned by event-type for an event whose class is key-press-event.

All event classes must implement methods for event-type and event-timestamp.

⇒ device-event  [Class]

⇒ :sheet [Init Arg]

⇒ :modifier-key-state  [Init Arg]

The class that corresponds to any sort of device event. This is a subclass of event.

All subclasses of device-event must take the :sheet and :modifier-key-state initargs, which are used to specify the sheet and modifier key state components for the event.

⇒ event-sheet device-event [Generic Function]

Returns the sheet associated with the event device-event.

⇒ event-modifier-key-state device-event [Generic Function]

Returns a value that encodes the state of all the modifier keys on the keyboard. This will be

a mask consisting of the logior of +shift-key+, +control-key+, +meta-key+, +super-key+,
and +hyper-key+.

All device event classes must implement methods for event-sheet and event-modifier-key-

state.
⇒ keyboard-event  [Class]

⇒ :key-name [Init Arg]

The class that corresponds to any sort of keyboard event. This is a subclass of device-event.

All subclasses of keyboard-event must take the :key-name initarg, which is used to specify the key name component for the event.

⇒ keyboard-event-key-name keyboard-event [Generic Function]

Returns the name of the key that was pressed or released in a keyboard event. This will be a symbol whose value is port-specific. Key names corresponding to the set of “standard” characters (such as the alphanumerics) will be a symbol in the keyword package.

⇒ keyboard-event-character keyboard-event [Generic Function]

Returns the character associated with the event keyboard-event, if there is any.

All keyboard event classes must implement methods for keyboard-event-key-name and keyboard-

event-character.
⇒ key-press-event  [Class]
⇒ key-release-event  [Class]

The classes that correspond to a key press or release event. This is a subclass of keyboard-

event.
⇒ pointer-event  [Class]

⇒ :pointer [Init Arg]

⇒ :button [Init Arg] ⇒ :x [Init Arg]

⇒ :y [Init Arg]

The class that corresponds to any sort of pointer event. This is a subclass of device-event.

All subclasses of pointer-event must take the :pointer, :button, :x, and :y initargs, which are used to specify the pointer object, pointer button, and native x and y position of the pointer at the time of the event. The sheet’s x and y positions are derived from the supplied native x and y positions and the sheet itself.

⇒ pointer-event-x pointer-event [Generic Function] ⇒ pointer-event-y pointer-event [Generic Function]

Returns the x and y position of the pointer at the time the event occurred, in the coordinate system of the sheet that received the event. All pointer events must implement a method for these generic functions.

⇒ pointer-event-native-x pointer-event [Generic Function] ⇒ pointer-event-native-y pointer-event [Generic Function]

Returns the x and y position of the pointer at the time the event occurred, in the pointer’s native coordinate system. All pointer events must implement a method for these generic functions.

⇒ pointer-event-pointer pointer-event [Generic Function]

Returns the pointer object to which this event refers.

⇒ pointer-event-button pointer-event [Generic Function]

Returns the number of the pointer button that was pressed, which will be one of +pointer-

left-button+, +pointer-middle-button+, or +pointer-right-button+.

All pointer event classes must implement methods for pointer-event-x, pointer-event-y,

pointer-event-native-x, pointer-event-native-y, pointer-event-pointer, and pointer-
event-button.
⇒ pointer-button-event  [Class]

The class that corresponds to any sort of pointer button event. This is a subclass of pointer-

event.
⇒ pointer-button-press-event  [Class]
⇒ pointer-button-release-event  [Class]
⇒ pointer-button-hold-event  [Class]

The classes that correspond to a pointer button press, button release, and click-and-hold events. These are subclasses of pointer-button-event.

⇒ pointer-motion-event  [Class]

CHAPTER 8. SHEET PROTOCOLS 59

The class that corresponds to any sort of pointer motion event. This is a subclass of pointer-

event.
⇒ pointer-enter-event  [Class]
⇒ pointer-exit-event  [Class]

The classes that correspond to a pointer enter or exit event. This is a subclass of pointer-

motion-event.
⇒ window-event  [Class]

⇒ :region [Init Arg] The class that corresponds to any sort of windowing event. This is a subclass of device-event. All subclasses of window-event must take a :region initarg, which is used to specify the damage region associated with the event.

⇒ window-event-region window-event [Generic Function]

Returns the region of the sheet that is affected by a window event. ⇒ window-event-native-region window-event [Generic Function]

Returns the region of the sheet in native coordinates. ⇒ window-event-mirrored-sheet window-event [Generic Function]

Returns the mirrored sheet that is attached to the mirror on which the event occurred. All window event classes must implement methods for window-event-region, window-event-

native-region, and window-event-mirrored-sheet.
⇒ window-configuration-event  [Class]

The class that corresponds to a window changing its size or position. This is a subclass of

window-event.
⇒ window-repaint-event  [Class]

The class that corresponds to a request to repaint the window. This is a subclass of window-

event.
⇒ timer-event  [Class]

The class that corresponds to a timeout event. This is a subclass of event.

⇒ +pointer-left-button+  [Constant]
⇒ +pointer-middle-button+  [Constant]
⇒ +pointer-right-button+  [Constant]

Constants that correspond to the left, middle, and right button on a pointing device. pointer-

event-button will returns one of these three values.

⇒ +shift-key+  [Constant]
⇒ +control-key+  [Constant]

⇒ +meta-key+ [Constant]

⇒ +super-key+  [Constant]
⇒ +hyper-key+  [Constant]

Constants that correspond to the shift, control, meta, super, and hyper modifier keys being held down on the keyboard. These constants must be powers of 2 so that they can be combined with logior and tested with logtest. event-modifier-key-state will return some combination of these values.

Implementations must support at least shift, control, and meta modifiers. Control and meta might correspond to the control and option or command shift keys on a Macintosh keyboard, for example.

⇒ key-modifier-state-match-p button modifier-state &body clauses [Macro]

This macro generates code that will check whether the modifier state modifier-state and the pointer button button match all of the clauses. clauses are implicitly grouped by and. Matching a button or a modifier means that that the modifier state indicates that the button or modifier is pressed.

A clause may be one of:

• A pointer button. One of :left, :middle or :right.

   • A modifier key. One of :shift, :control, :meta, :super or :hyper.
   • (and [clause]+)
   • (or [clause]+)

• (not clause)

8.3 Output Protocol

The output protocol is concerned with the appearance of displayed output on the window associated with a sheet.

Sheets either participate fully in the output protocol or are mute for output. If any functions in the output protocol are called on a sheet that is mute for output, the sheet-is-mute-for-output error will be signalled.

8.3.1 Output Properties

Each sheet retains some output state that logically describes how output is to be rendered on its window. Such information as the foreground and background ink, line thickness, and transformation to be used during drawing are provided by this state. This state may be stored in a medium associated with the sheet itself, be derived from a parent, or may have some global default, depending on the sheet itself.

If a sheet is mute for output, it is an error to set any of these values.

⇒ medium [Protocol Class]

The protocol class that corresponds to the output state for some kind of sheet. There is no single advertised standard medium class. If you want to create a new class that behaves like a medium, it should be a subclass of medium. Subclasses of medium must obey the medium protocol.

⇒ mediump object [Function]

Returns true if object is a medium, otherwise returns false.

The following generic functions comprise the basic medium protocol. All mediums must implement methods for these generic functions. Often, a sheet class that supports the output protocol will implement a “trampoline” method that passes the operation on to sheet-medium of the sheet.

⇒ medium-foreground medium [Generic Function] ⇒ (setf medium-foreground) design medium [Generic Function]

Returns (and, with setf, sets) the current foreground ink for the medium medium. This is described in detail in Chapter 10.

⇒ medium-background medium [Generic Function] ⇒ (setf medium-background) design medium [Generic Function]

Returns (and, with setf, sets) the current background ink for the medium medium. This is described in detail in Chapter 10.

⇒ medium-ink medium [Generic Function] ⇒ (setf medium-ink) design medium [Generic Function]

Returns (and, with setf, sets) the current drawing ink for the medium medium. This is described in detail in Chapter 10.

⇒ medium-transformation medium [Generic Function] ⇒ (setf medium-transformation) transformation medium [Generic Function]

Returns (and, with setf, sets) the “user” transformation that converts the coordinates presented to the drawing functions by the programmer to the medium medium’s coordinate system. By default, it is the identity transformation. This is described in detail in Chapter 10.

⇒ medium-clipping-region medium [Generic Function] ⇒ (setf medium-clipping-region) region medium [Generic Function]

Returns (and, with setf, sets) the clipping region that encloses all output performed on the medium medium. It is returned and set in user coordinates. That is, to convert the user clipping region to medium coordinates, it must be transformed by the value of medium-transformation. For example, the values returned by

(let (cr1 cr2)
  ;; Ensure that the sheet's clipping region and transformation will be reset:
  (with-drawing-options (sheet :transformation +identity-transformation+
                               :clipping-region +everywhere+)
    (setf (medium-clipping-region sheet) (make-rectangle* 0 0 10 10))
    (setf (medium-transformation sheet) (clim:make-scaling-transformation 2 2))
    (setf cr1 (medium-clipping-region sheet))
    (setf (medium-clipping-region sheet) (make-rectangle* 0 0 10 10))
    (setf (medium-transformation sheet) +identity-transformation+)
    (setf cr2 (medium-clipping-region sheet))
    (values cr1 cr2)))

are two rectangles. The first one has edges of (0,0,5,5), while the second one has edges of (0,0,20,20).

By default, the user clipping region is the value of +everywhere+.

Issue: What are “user coordinates”? We need to define all of the coordinate systems in one place: device, window, stream, etc. — SWM

⇒ medium-line-style medium [Generic Function] ⇒ (setf medium-line-style) line-style medium [Generic Function]

Returns (and, with setf, sets) the current line style for the medium medium. This is described in detail in Chapter 10 and Section 10.3.

⇒ medium-text-style medium [Generic Function] ⇒ (setf medium-text-style) text-style medium [Generic Function]

Returns (and, with setf, sets) the current text style for the medium medium of any textual output that may be displayed on the window. This is described in detail in Chapter 10.

⇒ medium-default-text-style medium  [Generic Function]

⇒ (setf medium-default-text-style) text-style medium [Generic Function]

Returns (and, with setf, sets) the default text style for output on the medium medium. This is described in detail in Chapter 10.

⇒ medium-merged-text-style medium  [Generic Function]

Returns the actual text style used in rendering text on the medium medium. It returns the result of

(merge-text-styles (medium-text-style medium)
                   (medium-default-text-style medium))

Thus, those components of the current text style that are not nil will replace the defaults from medium’s default text style. Unlike the preceding text style function, medium-merged-text-style is read-only.

8.3.2 Output Protocol Functions

The output protocol functions on mediums (and sheets that support the standard output protocol) include those functions described in Section 12.6.

Issue: Need to do better here — SWM

8.3.3 Output Protocol Classes

Issue: To be written. — RSL

⇒ standard-sheet-output-mixin  [Class]
⇒ primitive-sheet-output-mixin  [Class]

(No client transformation/clipping region, no foreground/background inks, no text styles.)

⇒ mute-sheet-output-mixin  [Class]
⇒ permanent-medium-sheet-output-mixin  [Class]
⇒ temporary-medium-sheet-output-mixin  [Class]

8.3.4 Associating a Medium with a Sheet

Before a sheet may be used for output, it must be associated with a medium. Some sheets are permanently associated with media for output efficiency; for example, CLIM window stream sheets have a medium that is permanently allocated to the window.

However, many kinds of sheets only perform output infrequently, and therefore do not need to be associated with a medium except when output is actually required. Sheets without a permanently associated medium can be much more lightweight than they otherwise would be. For example, in a program that creates a sheet for the purpose of displaying a border for another sheet, the border sheet receives output only when the window’s shape is changed.

To associate a sheet with a medium, the macro with-sheet-medium is used.

⇒ with-sheet-medium (medium sheet) &body body [Macro]

Within the body, the variable medium is bound to the sheet’s medium. If the sheet does not have a medium permanently allocated, one will be allocated, associated with the sheet for the duration of the body, and deallocated as the when the body has been exited. The values of the last form of the body are returned as the values of with-sheet-medium.

The medium argument is not evaluated, and must be a symbol that is bound to a medium. body may have zero or more declarations as its first forms.

⇒ with-sheet-medium-bound (sheet medium) &body body  [Macro]

with-sheet-medium-bound is used to associate the specific medium medium with the sheet sheet for the duration of the body body. Typically, a single medium will be allocated an passed to several different sheets that can use the same medium.

If the sheet already has a medium allocated to it, the new medium will not be given to the sheet. If the value of medium is nil, with-sheet-medium-bound is exactly equivalent to with-sheet-medium. The values of the last form of the body are returned as the values of with-sheet-

medium-bound.

body may have zero or more declarations as its first forms.

⇒ sheet-medium sheet [Generic Function]

Returns the medium associated with the sheet sheet. If sheet does not have a medium allocated

to it, sheet-medium returns nil.

8.4 Repaint Protocol

The repaint protocol is the mechanism whereby a program keeps the display up-to-date, reflecting the results of both synchronous and asynchronous events. The repaint mechanism may be invoked by user programs each time through their top-level command loop. It may also be invoked directly or indirectly as a result of events received from the display server host. For example, if a window is on display with another window overlapping it, and the second window is buried, a “damage notification” event may be sent by the server; CLIM would cause a repaint to be executed for the newly-exposed region.

8.4.1 Repaint Protocol Functions

⇒ dispatch-repaint sheet region [Generic Function]

Requests a repaint of the region region within the sheet sheet. The region is given in sheet coordinates. Depending on the class of the sheet, this may cause queue-repaint or handlerepaint to be invoked.

All CLIM implementations must support repainting for regions that are rectangles or region sets composed entirely of rectangles.

⇒ queue-repaint sheet region [Generic Function]

Requests that a repaint event for the region region be placed in the input queue of the sheet sheet. A program that reads events out of the queue will be expected to call handle-event for the repaint region; the method for that generic function on repaint events will generally call

repaint-sheet.

⇒ handle-repaint sheet medium region [Generic Function]

Recursively causes repainting of the sheet sheet and any of its children that overlap the region region. medium is the medium to use for the repainting; if it is nil, handle-repaint will allocate a medium and associate it with the sheet. handle-repaint will call repaint-sheet on sheet, and then call handle-repaint on all of the children of sheet.

⇒ repaint-sheet sheet region [Generic Function]

Implements repainting for a given sheet class. It may only be called on a sheet that has an associated medium. sheet and region are as for dispatch-repaint.

8.4.2 Repaint Protocol Classes

⇒ standard-repainting-mixin  [Class]
Defines a dispatch-repaint method that calls queue-repaint.
⇒ immediate-repainting-mixin  [Class]

Issue: Is this a good name? — RSL

Defines a dispatch-repaint method that calls handle-repaint.
⇒ mute-repainting-mixin  [Class]
Defines a dispatch-repaint method that calls queue-repaint, and a method on repaint-

sheet that does nothing. This means that its children will be recursively repainted when the repaint event is handled.

8.5 Sheet Notification Protocol

The notification protocol allows sheet clients to be notified when a sheet hierarchy is changed. Sheet clients can observe modification events by providing :after methods for functions defined by this protocol.

8.5.1 Relationship to Window System Change Notifications

Issue: To be written. — RSL

⇒ note-sheet-grafted sheet [Generic Function] ⇒ note-sheet-degrafted sheet [Generic Function] ⇒ note-sheet-adopted sheet [Generic Function] ⇒ note-sheet-disowned sheet [Generic Function] ⇒ note-sheet-enabled sheet [Generic Function] ⇒ note-sheet-disabled sheet [Generic Function]

These notification functions are invoked when the state change has been made to the sheet sheet.

8.5.2 Geometry Notifications

Issue: To be written. — RSL

⇒ note-sheet-region-changed sheet  [Generic Function]
⇒ note-sheet-transformation-changed sheet  [Generic Function]

These notification functions are invoked when the region or transformation of the sheetsheet has been changed. When the regions and transformations of a sheet are changed directly, the client

   is required to call note-sheet-region-changed or note-sheet-transformation-changed.

Ports, Grafts, and Mirrored Sheets

9.1 Introduction

A sheet hierarchy must be attached to a display server so as to permit input and output. This is managed by the use of ports and grafts.

9.2 Ports

A port is a logical connection to a display server. It is responsible for managing display output and server resources, and for handling incoming input events. Typically, the programmer will create a single port that will manage all of the windows on the display.

A port is described with a server path. A server path is a list whose first element is a keyword that selects the kind of port. The remainder of the server path is a list of alternating keywords and values whose interpretation is port type-specific.

⇒ find-port &key (server-path *default-server-path*)  [Function]

Finds a port that provides a connection to the window server addressed by server-path. If no such connection exists, a new connection will be constructed and returned.

The following server paths are currently supported:

⇒ :x11 &key host display-id screen-id [Server Path]

Given this server path, find-port finds a port for the X server on the given host, using the display-id and screen-id.

On a Unix host, if these values are not supplied, the defaults come from the display environment variable. Each CLIM implementation must describe how it uses such environment variables.

⇒ :genera &key screen [Server Path]

Issue: This is old and obsolete. Ditto :coral, or whatever we’re going to call it now. — RSL

⇒ *default-server-path*  [Variable]

This special variable is used by find-port and its callers to default the choice of a display service to locate. Binding this variable in a dynamic context will affect the defaulting of this argument to these functions. This variable will be defaulted according to the environment. In the Unix environment, for example, CLIM will attempt to set this variable based on the value of the display environment variable.

⇒ sheet-port sheet [Generic Function]

Returns the port associated with the sheet sheet. sheet-port is defined for all kinds of sheets (including grafts and streams that support the CLIM graphics protocol) and mediums. For degrafted sheets or other objects that aren’t currently associated with particular ports, sheetport will return nil.

⇒ with-port-locked port &body body  [Macro]

Executes body after grabbing a lock associated with the port port, which may be a port or any object on which the function sheet-port works. If object currently has no port, body will be executed without locking.

body may have zero or more declarations as its first forms.

⇒ port-properties port indicator [Generic Function] ⇒ (setf port-properties) property port indicator [Generic Function]

These functions provide a port-based property list. They are primarily intended to support users of CLIM that may need to associate certain information with ports. For example, the implementor of a special graphics package may need to maintain resource tables for each port on which it is used.

⇒ map-over-ports function [Function]

Invokes function on each existing port. Function is a function of one argument, the port; it has dynamic extent.

⇒ restart-port port [Generic Function]

In a multi-process Lisp, restart-port restarts the global input processing loop associated with the port port. All pending input events are discarded. Server resources may or may not be released and reallocated during or after this action.

⇒ destroy-port port [Generic Function] Destroys the connection with the window server represented by the port port. All sheet hierarchies that are associated with port are forcibly degrafted by disowning the children of grafts on port using sheet-disown-child. All server resources utilized by such hierarchies or by any graphics objects on port are released as part of the connection shutdown.

⇒ add-watcher port watcher [Generic Function] ⇒ delete-watcher port watcher [Generic Function] ⇒ reset-watcher watcher how [Generic Function]

Watchers are a mechanism for clients to be notified when the port is destroyed or restarted. addwatcher and delete-watcher provide an interface for adding and removing watcher to the list of watchers that the port port maintains. destroy-port and restart-port invoke reset-watcher on each of these watchers with :destroy and :restart being passed in as how, respectively.

Issue: What exactly is a watcher? The above is not specific enough. — SWM

9.3 Grafts

A graft is a special sheet that is directly connected to a display server. Typically, a graft is the CLIM sheet that represents the root window of the display. There may be several grafts that are all attached to the same root window; these grafts may have differing coordinate systems.

To display a sheet on a display, it must have a graft for an ancestor. In addition, the sheet and all of its ancestors must be enabled, including the graft. In general, a sheet becomes grafted when it (or one of its ancestors) is adopted by a graft.

⇒ sheet-grafted-p sheet [Generic Function]

Returns true if any of the sheet’s ancestors is a graft, otherwise returns false.

⇒ find-graft &key (port (find-port)) (server-path *default-server-path*) (orientation :default)

(units :device) [Function]

Finds a graft that represents the display device on the port port that also matches the other supplied parameters. If no such graft exists, a new graft is constructed and returned.

If server-path is supplied, find-graft finds a graft whose port provides a connection to the window server addressed by server-path.

It is an error to provide both port and server-path in a call to find-graft.

orientation specifies the orientation of the graft’s coordinate system. Supported values are :default and :graphics, which have the meanings describe below:

• :default—a coordinate system with its origin is in the upper left hand corner of the display device with y increasing from top to bottom and x increasing from left to right.

• :graphics—a coordinate system with its origin in the lower left hand corner of the display

device with y increasing from bottom to top and x increasing from left to right.

units specifies the units of the coordinate system and defaults to :device, which means the device units of the host window system (such as pixels). Other supported values include :inches, :millimeters, and :screen-sized, which means that one unit in each direction is the width and height of the display device.

Issue: I don’t know how much of this is obsolete. — RSL

⇒ sheet-graft sheet [Generic Function]

Returns the graft currently associated with the sheet sheet. sheet-graft is defined for all kinds of sheets (including streams that support the CLIM graphics protocol) and mediums. For degrafted sheets or other objects that aren’t currently associated with a particular graft, sheetgraft will return nil.

⇒ map-over-grafts function port [Function]

Invokes function on each existing graft associated with the port port. function is a function of one argument, the graft; it has dynamic extent.

⇒ with-graft-locked graft &body body  [Macro]

Executes body after grabbing a lock associated with the graft graft, which may be a graft or any object on which the function sheet-graft works. If object currently has no graft, body will be executed without locking.

body may have zero or more declarations as its first forms.

⇒ graft-orientation graft [Generic Function]

Returns the orientation of the graft graft’s coordinate system. The returned value will be either :default or :graphics. The meanings of these values are the same as described for the orientation argument to find-graft.

⇒ graft-units graft [Generic Function]

Returns the units of the graft graft’s coordinate system. The returned value will be one of

:device, :inches, :millimeters, or :screen-sized. The meanings of these values are the

same as described for the units argument to find-graft.

⇒ graft-width graft &key (units :device) [Generic Function] ⇒ graft-height graft &key (units :device) [Generic Function]

Returns the width and height of the graft graft (and by extension the associated host window) in

the units indicated. Units may be any of :device, :inches, :millimeters, or :screen-sized.

The meanings of these values are the same as described for the units argument to find-graft. Note if a unit of :screen-sized is specified, both of these functions will return a value of 1.

⇒ graft-pixels-per-millimeter graft  [Function]

⇒ graft-pixels-per-inch graft  [Function]

Returns the number of pixels per millimeter or inch of the graft graft. These functions are provided as a convenience to programmers and can be easily written in terms of graft-width

or graft-height.

Issue: Do we want to support non-square pixels? If so, these functions aren’t sufficient. — Rao

9.4 Mirrors and Mirrored Sheets

A mirrored sheet is a special class of sheet that is attached directly to a window on a display server. Grafts, for example, are always mirrored sheets. However, any sheet anywhere in a sheet hierarchy may be a mirrored sheet. A mirrored sheet will usually contain a reference to a window system object, called a mirror. For example, a mirrored sheet attached to an X11 server might have an X window system object stored in one of its slots. Allowing mirrored sheets at any point in the hierarchy enables the adaptive toolkit facilities.

Since not all sheets in the hierarchy have mirrors, there is no direct correspondence between the sheet hierarchy and the mirror hierarchy. However, on those display servers that support hierarchical windows, the hierarchies must be parallel. If a mirrored sheet is an ancestor of another mirrored sheet, their corresponding mirrors must have a similar ancestor/descendant relationship.

CLIM interacts with mirrors when it must display output or process events. On output, the mirrored sheet closest in ancestry to the sheet on which we wish to draw provides the mirror on which to draw. The mirror’s drawing clipping region is set up to be the intersection of the user’s clipping region and the sheet’s region (both transformed to the appropriate coordinate system) for the duration of the output. On input, events are delivered from mirrors to the sheet hierarchy. The CLIM port must determine which sheet shall receive events based on information such as the location of the pointer.

In both of these cases, we must have a coordinate transformation that converts coordinates in the mirror (so-called “native” coordinates) into coordinates in the sheet and vice-versa.

9.4.1 Mirror Functions

⇒ sheet-direct-mirror sheet [Generic Function]

Returns the mirror of the sheet sheet. If the sheet is not mirrored (or does not currently have a mirror), sheet-mirror returns nil.

⇒ sheet-mirrored-ancestor sheet  [Generic Function]

Returns the nearest mirrored ancestor of the sheet sheet.

⇒ sheet-mirror sheet [Generic Function] Returns the mirror of the sheet sheet. If the sheet is not itself mirrored, sheet-mirror returns the direct mirror of its nearest mirrored ancestor. sheet-mirror could be implemented as:

(defun sheet-mirror (sheet)
  (sheet-direct-mirror (sheet-mirrored-ancestor sheet)))

⇒ realize-mirror port mirrored-sheet [Generic Function]

Creates a mirror for the sheet mirrored-sheet on the port port, if it does not already have one. The returned value is the sheet’s mirror.

9.4.2 Internal Interfaces for Native Coordinates

⇒ sheet-native-transformation sheet  [Generic Function]

Returns the transformation for the sheet sheet that converts sheet coordinates into native coordinates. The object returned by this function is volatile, so programmers must not depend on the components of the object remaining constant.

⇒ sheet-native-region sheet [Generic Function]

Returns the region for the sheet sheet in native coordinates. The object returned by this function is volatile, so programmers must not depend on the components of the object remaining constant.

Issue: These used to be called fetch-mirrored-sheet, fetch-native-transformation, and
fetch-native-clipping-region. — RSL
⇒ sheet-device-transformation sheet  [Generic Function]

Returns the transformation used by the graphics output routines when drawing on the mirror. This is the composition of the sheet’s native transformation and the user transformation. The object returned by this function is volatile, so programmers must not depend on the components of the object remaining constant.

⇒ sheet-device-region sheet [Generic Function]

Returns the actual clipping region to be used when drawing on the mirror. This is the intersection of the user’s clipping region (transformed by the device transformation) with the sheet’s native region. The object returned by this function is volatile, so programmers must not depend on the components of the object remaining constant.

⇒ invalidate-cached-transformations sheet  [Generic Function]
sheet-native-transformation and sheet-device-transformation typically cache the trans-

formations for performance reasons. invalidate-cached-transformations clears the cached native and device values for the sheet sheet’s transformation and clipping region. It is invoked when a sheet’s native transformation changes, which happens when a sheet’s transformation is changed or when invalidate-cached-transformations is called on any of its ancestors.

⇒ invalidate-cached-regions sheet  [Generic Function]

sheet-native-region and sheet-device-region typically cache the regions for performance reasons. invalidate-cached-regions clears the cached native and device values for the sheet sheet’s native clipping region. It is invoked when a sheet’s native clipping region changes, which happens when the clipping region changes or when invalidate-cached-regions is called on any of its ancestors.

Part IV

Sheet and Medium Output Facilities Drawing Options

This chapter describes the drawing options that are used by CLIM’s drawing functions, and the relationship between drawing options, sheets, and mediums. These drawing options control various aspects of the drawing process, and can be provided as keyword arguments to all of the drawing functions.

10.1 Medium Components

Medium objects contain components that correspond to the drawing options; when no value for a drawing option is explicitly provided to a drawing function, it is taken from the medium. These values can be directly queried or modified using accessors defined on the sheet or medium. They can also be temporarily bound within a dynamic context using with-drawing-options, with-text-style, and related forms.

setf of one of these components while it is temporarily bound (via with-drawing-options, for instance) takes effect immediately but is undone when the dynamic binding context is exited.

In systems that support multiple processes, the consequences are unspecified if one process reads or writes a medium component that is temporarily bound by another process.

The following functions read and write components of a medium related to drawing options. While these functions are defined for mediums, they can also be called on sheets support the sheet output protocol and on streams that output to such sheets. All classes that support the medium protocol must implement methods for these generic functions. Often, a sheet class that supports the output protocol will implement a “trampoline” method that passes the operation on to sheet-medium of the sheet.

⇒ medium-foreground medium [Generic Function] ⇒ medium-background medium [Generic Function] Returns the foreground and background inks (which are designs) for the medium medium, respectively. The foreground ink is the default ink used when drawing. The background ink is the ink used when erasing. See Chapter 13 for a more complete description of designs.

Any indirect inks are resolved against the foreground and background at the time a design is rendered.

⇒ (setf medium-foreground) design medium [Generic Function] ⇒ (setf medium-background) design medium [Generic Function]

Sets the foreground and background ink, respectively, for the medium medium to design. You

may not set medium-foreground or medium-background to an indirect ink.

design is an unbounded design. If the background design is not completely opaque at all points, the consequences are unspecified.

Changing the foreground or background of a sheet that supports output recording causes the contents of the stream’s viewport to be erased and redrawn using the new foreground and background.

⇒ medium-ink medium [Generic Function]

The current drawing ink for the medium medium, which can be any design. The drawing functions draw with the color and pattern that this specifies. See Chapter 13 for a more complete description of inks. The :ink drawing option temporarily changes the value of medium-ink.

⇒ (setf medium-ink) design medium [Generic Function]

Sets the current drawing ink for the medium medium to design. design is as for mediumforeground, and may be an indirect ink as well.

⇒ medium-transformation medium [Generic Function]

The current user transformation for the medium medium. This transformation is used to transform the coordinates supplied as arguments to drawing functions to the coordinate system of the drawing plane. See Chapter 5 for a complete description of transformations. The :transformation drawing option temporarily changes the value of medium-transformation.

⇒ (setf medium-transformation) transformation medium [Generic Function]

Sets the current user transformation for the medium medium to the transformation transformation.

⇒ medium-clipping-region medium [Generic Function]

The current clipping region for the medium medium. The drawing functions do not affect the drawing plane outside this region. The :clipping-region drawing option temporarily changes

the value of medium-clipping-region.

⇒ (setf medium-clipping-region) region medium [Generic Function] Sets the current clipping region for the medium medium to region. region must be a subclass of area. Furthermore, some implementations may signal an error if the clipping region is not a rectangle or a region set composed entirely of rectangles.

⇒ medium-line-style medium [Generic Function]

The current line style for the medium medium. The line and arc drawing functions render according to this line style. See Section 10.3 for a complete description of line styles. The :line-style drawing option temporarily changes the value of medium-line-style.

⇒ (setf medium-line-style) line-style medium [Generic Function]

Sets the current line style for the medium medium to the line style line-style.

⇒ medium-default-text-style medium  [Generic Function]

The default text style for the medium medium. medium-default-text-style will return a fully specified text style, unlike medium-text-style, which may return a text style with null components. Any text styles that are not fully specified by the time they are used for rendering

are merged against medium-default-text-style using merge-text-styles. See Chapter 11

for a complete description of text styles.

⇒ (setf medium-default-text-style) text-style medium [Generic Function]

Sets the default text style for the medium medium to the text style text-style. text-style must be a fully specified text style.

Some CLIM implementations may arrange to erase and redraw the output on an output recording stream when the default text style of the stream is changed. Implementations that do this must obey the proper vertical spacing for output streams, and must reformat tables, graphs, and so forth, as necessary. Because of the expense of this operation, CLIM implementations are not required to support this.

⇒ medium-text-style medium [Generic Function]

The current text style for the medium medium. The text drawing functions, including ordinary stream output, render text as directed by this text style merged against the default text style. This controls both graphical text (such as that drawn by draw-text*) and stream text (such as that written by write-string). See Chapter 11 for a complete description of text styles. The :text-style drawing option temporarily changes the value of medium-text-style.

⇒ (setf medium-text-style) text-style medium [Generic Function]

Sets the current text style for the medium medium to the text style text-style. text-style need not be a fully merged text style.

⇒ medium-current-text-style medium  [Generic Function]

The current, fully merged text style for the medium medium. This is the text style that will be used when drawing text output, and is the result of merging medium-text-style against

medium-default-text-style.

10.2 Drawing Option Binding Forms

⇒ with-drawing-options (medium &rest drawing-options) &body body [Macro]

Binds the state of the medium designated by medium to correspond to the supplied drawing options, and executes the body with the new drawing options specified by drawing-options in effect. Each option causes binding of the corresponding component of the medium for the dynamic extent of the body. The drawing functions effectively do a with-drawing-options when drawing option arguments are supplied to them.

medium can be a medium, a sheet that supports the sheet output protocol, or a stream that outputs to such a sheet. The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

with-drawing-options must be implemented by expanding into a call to invoke-with-drawing-

options, supplying a function that executes body as the function argument to invoke-with-drawing-options. The exact behavior of this macro is described under invoke-with-drawing-

options.

⇒ invoke-with-drawing-options medium function &rest drawing-options [Generic Function]

Binds the state of the medium medium to correspond to the supplied drawing options, and then calls the function function with the new drawing options in effect. function is a function of one argument, the medium; it has dynamic extent. drawing-options is a list of alternating keywordvalue pairs, and must have even length. Each option in drawing-options causes binding of the corresponding component of the medium for the dynamic extent of the body.

medium can be a medium, a sheet that supports the sheet output protocol, or a stream that outputs to such a sheet. All classes that obey the medium protocol must implement a method

for invoke-with-drawing-options.

The drawing options can be any of the following, plus any of the suboptions for line styles and text styles. The default value specified for a drawing option is the value to which the corresponding component of a medium is normally initialized.

⇒ :ink [Option]

A design that will be used as the ink for drawing operations. The drawing functions draw with the color and pattern that this specifies. The default value is +foreground-ink+. See Chapter 13 for a complete description of inks.

The :ink ink drawing option temporarily changes the value of (medium-ink medium) to ink, replacing the previous ink; the new and old inks are not combined in any way.

⇒ :transformation  [Option]

This transforms the coordinates used as arguments to drawing functions to the coordinate system of the drawing plane. The default value is +identity-transformation+. See Chapter 5 for a complete description of transformations.

The :transformation xform drawing option temporarily changes the value of(medium-transformation

medium) to (compose-transformations (medium-transformation medium) xform).
⇒ :clipping-region  [Option]

The drawing functions do not affect the drawing plane outside this region. The clipping region must be an area. Furthermore, some implementations might signal an error if the clipping region is not a rectangle or a region set composed entirely of rectangles. Rendering is clipped both by this clipping region and by other clipping regions associated with the mapping from the target drawing plane to the viewport that displays a portion of the drawing plane. The default is +everywhere+, or in other words, no clipping occurs in the drawing plane, only in the viewport.

The :clipping-region region drawing option temporarily changes the value of (medium-clipping-

region medium) to (region-intersection (transform-region (medium-transformation medium)

region) (medium-clipping-region medium)). If both a clipping region and a transformation are supplied in the same set of drawing options, the clipping region argument is transformed by the newly composed transformation before calling region-intersection.

Issue: A better explanation is needed. It does the right thing, but it’s hard to tell that from this description. — DCPL

⇒ :line-style  [Option]

The line and arc drawing functions render according to this line style. The line style suboptions and default are defined in Section 10.3.

The :line-style ls drawing option temporarily changes the value of (medium-line-style medium) to ls, replacing the previous line style; the new and old line styles are not combined in any way.

If line style suboptions are supplied, they temporarily change the value of (medium-line-style medium) to a line style constructed from the specified suboptions. Components not specified by suboptions are defaulted from the :line-style drawing option, if it is supplied, or else from the previous value of (medium-line-style medium). That is, if both the :line-style option and line style suboptions are supplied, the suboptions take precedence over the components of

the :line-style option.
⇒ :text-style  [Option]

The text drawing functions, including ordinary stream output, render text as directed by this text style merged against the default text style. The default value has all null components. See Chapter 11 for a complete description of text styles, including the text style suboptions.

The :text-style ts drawing option temporarily changes the value of (medium-text-style

medium) to (merge-text-styles ts (medium-text-style medium)).

If text style suboptions are supplied, they temporarily change the value of (medium-text-style medium) to a text style constructed from the specified suboptions, merged with the :textstyle drawing option if it is specified, and then merged with the previous value of (mediumtext-style medium). That is, if both the :text-style option and text style suboptions are supplied, the suboptions take precedence over the components of the :text-style option.

10.2.1 Transformation “Convenience” Forms

The following three functions are no different than using with-drawing-options with the :transformation keyword argument supplied. However, they are sufficiently useful that they are provided as a convenience to programmers.

In order to preserve referential transparency, these three forms apply the translation, rotation, or scaling transformation first, then the rest of the transformation from (medium-transformation medium). That is, the following two forms would return the same transformation (assuming that the medium’s transformation in the second example is the identity transformation):

(compose-transformations
  (make-translation-transformation dx dy)
  (make-rotation-transformation angle))
(with-translation (medium dx dy)
  (with-rotation (medium angle)
    (medium-transformation medium)))

⇒ with-translation (medium dx dy) &body body [Macro]

Establishes a translation on the medium designated by medium that translates by dx in the x direction and dy in the y direction, and then executes body with that transformation in effect.

dx and dy are as for make-translation-transformation.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

⇒ with-scaling (medium sx &optional sy origin) &body body [Macro]

Establishes a scaling transformation on the medium designated by medium that scales by sx in the x direction and sy in the y direction, and then executes body with that transformation in effect. If sy is not supplied, it defaults to sx. If origin is supplied, the scaling is about that point; if it is not supplied, it defaults to (0, 0).

sx and sy are as for make-scaling-transformation.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

⇒ with-rotation (medium angle &optional origin) &body body [Macro] Establishes a rotation on the medium designated by medium that rotates by angle, and then executes body with that transformation in effect. If origin is supplied, the rotation is about that point; if it is not supplied, it defaults to (0, 0).

angle and origin are as for make-rotation-transformation.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

10.2.2 Establishing Local Coordinate Systems

⇒ with-local-coordinates (medium &optional x y) &body body  [Macro]

Binds the dynamic environment to establish a local coordinate system on the medium designated by medium with the origin of the new coordinate system at the position (x, y). The “directionality” of the coordinate system is otherwise unchanged. x and y are real numbers, and both default to 0.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

⇒ with-first-quadrant-coordinates (medium &optional x y) &body body  [Macro]

Binds the dynamic environment to establish a local coordinate system on the medium designated by medium with the positive x axis extending to the right and the positive y axis extending upward, with the origin of the new coordinate system at the position (x, y). x and y are real numbers, and both default to 0.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

10.3 Line Styles

A line or other path is a one-dimensional object. However in order to be visible, the rendering of a line must occupy some non-zero area on the display hardware. A line style represents the advice of CLIM to the rendering substrate on how to perform the rendering.

⇒ line-style [Protocol Class]

The protocol class for line styles. If you want to create a new class that behaves like a line style, it should be a subclass of line-style. Subclasses of line-style must obey the line style protocol.

⇒ line-style-p object [Function]

Returns true if object is a line style, otherwise returns false.

⇒ standard-line-style  [Class]

An instantiable class that implements line styles. A subclass of line-style. This is the class that make-line-style instantiates. Members of this class are immutable.

⇒ make-line-style &key unit thickness joint-shape cap-shape dashes [Function]

Returns an object of class standard-line-style with the supplied characteristics. The arguments and their default values are described in Section 10.3.1.

10.3.1 Line Style Protocol and Line Style Suboptions

Each of these suboptions has a corresponding reader that can be used to extract a particular component from a line style. The generic functions decribed below comprise the line style protocol; all subclasses of line-style must implement methods for these generic functions.

⇒ :line-unit  [Option]

⇒ line-style-unit line-style [Generic Function]

Gives the unit used for measuring line thickness and dash pattern length for the line style. Possible values are :normal, :point, or :coordinate. The meaning of these options is:

• :normal—thicknesses and lengths are given in a relative measure in terms of the usual or “normal” line thickness. The normal line thickness is the thickness of the “comfortably visible thin line”, ^{1} which is a property of the underlying rendering substrate. This is the default.

• :point—thicknesses and lengths are given in an absolute measure in terms of printer’s points (approximately 1/72 of an inch). ^{2}

• :coordinate—this means that the same units should be used for line thickness as are used for coordinates. In this case, the line thickness is scaled by the medium’s current transformation, whereas :normal and :point do not scale the line thickness.

⇒ :line-thickness  [Option]

⇒ line-style-thickness line-style [Generic Function]

The thickness, in the units indicated by line-style-unit, of the lines or arcs drawn by a drawing function. The thickness must be a real number. The default is 1, which combined with Figure 10.1: Line joint shapes.

1In some window systems, the phrase “thinnest visible line” is used. This is not appropriate for CLIM, which intends to be device independent. (For instance, the thinnest visible line on a 400 d.p.i. laser printer is a function of the user’s viewing distance from the paper.) Another attribute of a “normal” line is that its thickness should approximately match the stroke thickness of “normal” text, where again the exact measurements are the province of the rendering engine, not of CLIM.

2This measure was chosen so that CLIM implementors who interface CLIM to an underlying rendering engine (the window system) may legitimately choose to make it render as 1 pixel on current (1990) display devices.

Figure 10.2: Line cap shapes.

the default unit of :normal, means that the default line drawn is the “comfortably visible thin line”.

⇒ :line-joint-shape  [Option]

⇒ line-style-joint-shape line-style [Generic Function]

Specifies the shape of joints between segments of unfilled figures. The possible shapes are :miter, :bevel, :round, and :none; the default is :miter. Note that the joint shape is implemented by the host window system, so not all platforms will necessarily fully support it.

⇒ :line-cap-shape  [Option]

⇒ line-style-cap-shape line-style [Generic Function]

Specifies the shape for the ends of lines and arcs drawn by a drawing function, one of :butt, :square, :round, or :no-end-point; the default is :butt. Note that the cap shape is implemented by the host window system, so not all platforms will necessarily fully support it.

⇒ :line-dashes  [Option]

⇒ line-style-dashes line-style [Generic Function]

Controls whether lines or arcs are drawn as dashed figures, and if so, what the dashing pattern is. Possible values are:

• nil—lines are drawn solid, with no dashing. This is the default.

• t—lines are drawn dashed, with a dash pattern that is unspecified and may vary with the rendering engine. This allows the underlying display substrate to provide a default dashed line for the programmer whose only requirement is to draw a line that is visually distinguishable from the default solid line.

• A sequence—specifies a sequence, usually a vector, controlling the dash pattern of a drawing function. It is an error if the sequence does not contain an even number of elements. The elements of the sequence are lengths (as real numbers) of individual components of the dashed line or arc. The odd elements specify the length of inked components, the even elements specify the gaps. All lengths are expressed in the units described by line-style-

     unit.

(See also make-contrasting-dash-patterns.)

10.3.2 Contrasting Dash Patterns

⇒ make-contrasting-dash-patterns n &optional k  [Function]

If k is not supplied, this returns a vector of n dash patterns with recognizably different appearance. Elements of the vector are guaranteed to be acceptable values for :dashes, and do not include nil, but their class is not otherwise specified. The vector is a fresh object that may be modified.

If k is supplied, it must be an integer between 0 and n − 1 (inclusive), in which case makecontrasting-dash-patterns returns the k’th dash-pattern rather than returning a vector of dash-patterns.

If the implementation does not have n different contrasting dash patterns, make-contrasting-dash-patterns signals an error. This will not happen unless n is greater than eight.

⇒ contrasting-dash-pattern-limit port  [Generic Function]

Returns the number of contrasting dash patterns that can be rendered on any medium on the port port. Implementations are encouraged to make this as large as possible, but it must be at least 8. All classes that obey the port protocol must implement a method for this generic function.

Text Styles

When specifying a particular “appearance” for rendered characters, there is a tension between portability and access to the specific device font. CLIM provides a portable mechanism for describing the desired text style in abstract terms. Each CLIM “port” defines a mapping between these abstract style specifications and particular device-specific fonts. In this way, an application programmer can specify the desired text style in abstract terms secure in the knowledge that an appropriate device font will be selected at run time by CLIM. However, some programmers may require direct access to particular device fonts. The text style mechanism supports specifying device fonts by name, allowing the programmer to sacrifice portability for control.

11.1 Text Styles

Text style objects have components for family, face, and size. Not all of these attributes need be supplied for a given text style object. Text styles can be merged in much the same way as pathnames are merged; unspecified components in the style object (that is, components that have nil in them) may be filled in by the components of a “default” style object. A text style object is called fully specified if none of its components is nil, and the size component is not a relative size (that is, is neither :smaller nor :larger).

⇒ text-style [Protocol Class]

The protocol class for text styles. If you want to create a new class that behaves like a text style, it should be a subclass of text-style. Subclasses of text-style must obey the text style protocol.

⇒ text-style-p object [Function]

Returns true if object is a text style, otherwise returns false.

⇒ standard-text-style  [Class]

CHAPTER 11. TEXT STYLES 86

An instantiable class that implements text styles. It is a subclass of text-style. This is the class that make-text-style instantiates. Members of this class are immutable. The interface to text styles is as follows:

⇒ make-text-style family face size [Function] Returns an object of class standard-text-style with a family of family, a face of face, and a size of size.

family is one of :fix, :serif, :sans-serif, or nil.
face is one of :roman, :bold, :italic, (:bold :italic), or nil.

size is a real number representing the size in printer’s points, one of the logical sizes (:normal,

:tiny, :very-small, :small, :large, :very-large, :huge), a relative size (:smaller or :larger),
or nil.

Issue: Need to describe what family, face, size mean in terms of visual appearance. — York

⇒ *default-text-style*  [Constant]

The default text style used by all CLIM mediums, if no text style was explicitly specified for the mediums. This must be a fully merged text style.

11.1.1 Text Style Protocol and Text Style Suboptions

The following generic functions comprise the text style protocol. All subclasses of text-style must implement methods for each of these generic functions. Each of the suboptions described below has a corresponding reader accessor that can be used to extract a particular component from a text style.

⇒ text-style-components text-style [Generic Function]

Returns the components of the text style text-style as three values, the family, face, and size.

⇒ :text-family  [Option]

⇒ text-style-family text-style [Generic Function]

Specifies the family of the text style text-style.

⇒ :text-face  [Option]

⇒ text-style-face text-style [Generic Function]

Specifies the face of the text style text-style.

⇒ :text-size  [Option]

⇒ text-style-size text-style [Generic Function]

Specifies the size of the text style text-style.

⇒ parse-text-style style-spec [Function]

Returns a text style object. style-spec may be a text-style object or a device font, in which case it is returned as is, or it may be a list of the family, face, and size (that is, a “style spec”), in which case it is “parsed” and a text-style object is returned. This function is for efficiency, since a number of common functions that take a style object as an argument can also take a style spec, in particular draw-text.

⇒ merge-text-styles style1 style2 [Generic Function]

Merges the text styles style1 with style2, that is, returns a new text style that is the same as style1, except that unspecified components in style1 are filled in from style2. For convenience, the two arguments may be also be style specs.

When merging the sizes of two text styles, if the size from style1 is a relative size, the resulting size is either the next smaller or next larger size than is specified by style2. The ordering of sizes,

from smallest to largest, is :tiny, :very-small, :small, :normal, :large, :very-large, and
:huge.

Issue: Need to describe face-merging properly. — SWM

⇒ text-style-ascent text-style port [Generic Function] ⇒ text-style-descent text-style port [Generic Function] ⇒ text-style-height text-style port [Generic Function] ⇒ text-style-width text-style port [Generic Function]

Returns the ascent, descent, height, and width (respectively) of the font corresponding to the text style text-style as it would be rendered on any medium on the port port. text-style must be a fully specified text style.

The ascent of a font is the distance between the top of the tallest character in that font and the font’s baseline. The descent of a font is the distance between the baseline and the bottom of the lowest descending character (usually “g”, “p”, “q”, or “y”). The height of a font is the sum of the ascent and the descent of the font. The width of a font is the width of some representative character in the font.

The methods for these generic functions will typically specialize both the text-style and port arguments. Implementations should also provide “trampoline” for these generic function for mediums and output sheets; the trampolines will simply call the method for the port.

⇒ text-style-fixed-width-p text-style port [Generic Function]

Returns true if the text styles text-style will map to a fixed-width font on any medium on the port port, otherwise returns false. text-style must be a fully specified text style.

The methods for this generic function will typically specialize both the text-style and port arguments. Implementations should also provide a “trampoline” for this generic function for mediums and output sheets; the trampoline will simply call the method for the port.

Issue: Discuss baselines? Kerning? — SWM

⇒ text-size medium string &key text-style (start 0) end [Generic Function]

Computes the “cursor motion” in device units that would take place if string (which may be either a string or a character) were output to the medium medium starting at the position (0, 0). Five values are returned: the total width of the string in device units, the total height of the string in device units, the final x cursor position (which is the same as the width if there are no #\Newline characters in the string), the final y cursor position (which is 0 if the string has no #\Newline characters in it, and is incremented by the line height of medium for each #\Newline character in the string), and the string’s baseline.

text-style specifies what text style is to be used when doing the output, and defaults to mediummerged-text-style of the medium. text-style must be a fully specified text style. start and end may be used to specify a substring of string.

If a programmer needs to account for kerning or the ascent or descent of the text style, he should measure the size of the bounding rectangle of the text rendered on medium.

All mediums and output sheets must implement a method for this generic function.

11.2 Text Style Binding Forms

⇒ with-text-style (medium text-style) &body body [Macro]

Binds the current text style of the medium designated by medium to correspond to the new text style. text-style may either a text style object or a style spec (that is, a list of the a family, a face code, and a size). body is executed with the new text style in effect.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

with-text-style must be implemented by expanding into a call to invoke-with-text-style, supplying a function that executes body as the function argument to invoke-with-text-style.

⇒ invoke-with-text-style medium function text-style [Generic Function]

Binds the current text style of the medium medium to correspond to the new text style, and calls the function function with the new text style in effect. text-style may either a text style object or a style spec (that is, a list of the a family, a face code, and a size). function is a function of one argument, the medium; it has dynamic extent.

medium can be a medium, a sheet that supports the sheet output protocol, or a stream that outputs to such a sheet. All classes that obey the medium protocol must implement a method

for invoke-with-text-style.

⇒ with-text-family (medium family) &body body [Macro] ⇒ with-text-face (medium face) &body body [Macro] ⇒ with-text-size (medium size) &body body [Macro]

Binds the current text style of the medium designated by medium to correspond to a new text style consisting of the current text style with the new family, face, or size (respectively) merged in. face, family, and size are as for make-text-style. body is executed with the new text style in effect.

The medium argument is not evaluated, and must be a symbol that is bound to a sheet or medium. If medium is t, *standard-output* is used. body may have zero or more declarations as its first forms.

These macros are “convenience” forms of with-text-style that must expand into calls to

invoke-with-text-style.

11.3 Controlling Text Style Mappings

Text styles are mapped to fonts using the text-style-mapping function, which takes a port, a character set, and a text style and returns a font object. All ports must implement methods for the following generic functions, for all classes of text style.

The objects used to represent a font mapping are unspecified and are likely to vary from port to port. For instance, a mapping might be some sort of font object on one type of port, or might simply be the name of a font on another.

Issue: We still need to describe what a device font is. Ditto, character sets. — SWM

Part of initializing a port is to define the mappings between text styles and font names for the port’s host window system.

⇒ text-style-mapping port character-set text-style [Generic Function]

Returns the font mapping that will be used when rendering characters in the character set character-set in the text style text-style on any medium on the port port. If there is no mapping associated with character-set and text-style on port, then some other object will be returned that corresponds to the “unmapped” text style.

⇒ (setf text-style-mapping) mapping port character-set text-style [Generic Function]

Sets the text style mapping for port, character-set, and text-style to mapping. port, character-set, and text-style are as for text-style-mapping. mapping is either a font name or a list of the form (:style family face size); in the latter case, the given style is translated at runtime into the font represented by the specified style.

Issue: While there is nothing wrong with this on the surface, there are indications that it is not really right. It turns out that several platforms don’t even use this mechanism, which may indicate that it is not good enough. — SWM ⇒ make-device-font-text-style display-device device-font-name [Function]

Returns a text style object that will be mapped directly to the specified device font when text is output to a to the display device with this style. Device font styles do not merge with any other kind of style.

Graphics

The CLIM graphic drawing model is an idealized model of graphical pictures. The model provides the language that application programs use to describe the intended visual appearance of textual and graphical output. Usually not all of the contents of the screen are described using the graphic drawing model. For example, menus and scroll bars might be described in higher-level terms.

An important aspect of the CLIM graphic drawing model is its extreme device independence. The model describes ideal graphical images and ignores limitations of actual graphics devices. One consequence of this is that the actual visual appearance of the screen can only be an approximation of the appearance specified by the model. Another consequence of this is that the model is highly portable.

CLIM separates output into two layers, a text/graphics layer in which one specifies the desired visual appearance independent of device resolution and characteristics, and a rendering layer in which some approximation of the desired visual appearance is created on the device. Of course application programs can inquire about the device resolution and characteristics if they wish and modify their desired visual appearance on that basis. (There is also a third layer above these two layers, the adaptive toolkit layer where one specifies the desired functionality rather than the desired visual appearance.)

Issue: There are still no functions to ask about device resolution and characteristics. Also, do we really need to refer to the adaptive toolkit layer here? — SWM

CLIM’s drawing functions provide convenient ways to draw several commonly-used shapes.

The interaction between graphics and output recording will be described in Chapter 16.

12.1 Definitions

Drawing plane. A drawing plane is an infinite two-dimensional plane on which graphical output occurs. The drawing plane contains an arrangement of colors and opacities that is modified by each graphical output operation. It is not possible to read back the contents of a drawing plane, except by examining the output-history. Normally each window has its own drawing plane.

Coordinates. Coordinates are a pair of real numbers in implementation-defined units that identify a point in the drawing plane.

Sheets and Mediums. In this chapter, we use a sheet as a destination for output. Associated with a sheet is a medium, which has a drawing plane, two designs called the medium’s foreground and background, a transformation, a clipping region, a line style, and a text style. There are permedium, dynamically scoped, default drawing options. Different medium classes are provided to allow programmers to draw on different sorts of devices, such as displays, printers, and virtual devices such as bitmaps.

Note that a stream is a special kind of sheet that implements the stream protocol; streams include additional state such as the current text cursor (which is some point in the drawing plane). While the functions defined here are specified to be called on sheets, they can also be called on streams and mediums.

By default, the “fundamental” coordinate system of a CLIM stream (not a general sheet or medium, whose fundamental coordinate system is not defined) is a left handed system with x increasing to the right, and y increasing downward. (0, 0) is at the upper left corner.

12.2 Drawing is Approximate

Note that although the drawing plane contains an infinite number of mathematical points, and drawing can be described as an infinite number of color and opacity computations, the drawing plane cannot be viewed directly and has no material existence. It is only an abstraction. What can be viewed directly is the result of rendering portions of the drawing plane onto a medium. No infinite computations or objects of infinite size are required to implement CLIM, because the results of rendering have finite size and finite resolution.

A drawing plane is described as having infinitely fine spatial, color, and opacity resolution, and as allowing coordinates of unbounded positive or negative magnitude. A viewport into a drawing plane, on the other hand, views only a finite region (usually rectangular) of the drawing plane. Furthermore, a viewport has limited spatial resolution and can only produce a limited number of colors. These limitations are imposed by the display hardware on which the viewport is displayed. A viewport also has limited opacity resolution, determined by the finite arithmetic used in the drawing engine (which may be hardware or software or both).

Coordinates are real numbers in implementation-defined units. Often these units equal the spatial resolution of a viewport, so that a line of thickness 1 is equivalent to the thinnest visible line. However, this equivalence is not required and should not be assumed by application programs.

A valid CLIM implementation can be quite restrictive in the size and resolution of its viewports. For example, the spatial resolution might be only a few dozen points per inch, the maximum size might be only a few hundred points on a side, and there could be as few as two displayable colors (usually black and white). The fully transparent and fully opaque opacity levels must always be supported, but a valid CLIM implementation might support only a few opacity levels in between (or possibly even none). A valid CLIM implementation might implement color blending and unsaturated colors by stippling, although it is preferred, when possible, for a viewport to display a uniform color as a uniform color rather than as a perceptible stipple.

When CLIM records the output to a sheet, there are no such limitations since CLIM just remembers the drawing operations that were performed, not the results of rendering.

CLIM provides some ways to ask what resolution limits are in effect for a medium. See Chapter 10 for their descriptions.

The application programmer uses the CLIM graphic drawing model as an interface to describe the intended visual appearance. An implementation does its best to approximate that ideal appearance in a viewport, within its limitations of spatial resolution, color resolution, number of simultaneously displayable colors, and drawing speed. This will usually require tradeoffs, for example between speed and accuracy, and each implementation must make these tradeoffs according to its own hardware/software environment and user concerns. For example, if the actual device supports a limited number of colors, the desired color may be approximated by techniques such as dithering or stippling. If the actual device cannot draw curves exactly, they may be approximated, with or without anti-aliasing. If the actual device has limited opacity resolution, color blending may be approximate. A viewport might display colors that don’t appear in the drawing plane, both because of color and opacity approximation and because of anti-aliasing at the edges of drawn shapes.

It is likely that different implementations will produce somewhat different visual appearance when running the same application. If an application requires more detailed control, it must resort to a lower-level interface, and will become less portable as a result. These lower-level interfaces will be documented on a per-platform basis.

Drawing computations are always carried out “in color”, even if the viewport is only capable of displaying black and white. In other words, the CLIM drawing model is always the fully general model, even if an implementation’s color resolution is limited enough that full use of the model is not possible. Of course an application that fundamentally depends on color will not work well on a viewport that cannot display color. Other applications will degrade gracefully.

Whether the implementation uses raster graphics or some other display technique is invisible at this interface. CLIM does not specify the existence of pixels nor the exact details of scan conversion, which will vary from one drawing engine to the next.

Performance will also vary between implementations. This interface is defined in terms of simple conceptual operations, however an actual implementation may use caching, specialized object representations, and other optimizations to avoid materializing storage-intensive or computationcostly intermediate results and to take advantage of available hardware.

12.3 Rendering Conventions for Geometric Shapes

The intent of this section is to describe the conventions for how CLIM should render a shape on a display device. These conventions and the accompanying examples are meant to describe a set of goals that a CLIM implementation should try to meet. However, compliant CLIM implementations may deviate from these goals if necessary (for example, if the rendering performance on a specific platform would be unacceptably slow if these goals were met exactly and implementors feel that users would be better served by speed than by accuracy). Note that we discuss only pixel-based display devices here, which are the most common, but by no means the only, sort of display device that can be supported by CLIM.

When CLIM draws a geometric shape on some sort of display device, the idealized geometric shape must somehow be rendered on the display device. The geometric shapes are made up of a set of mathematical points, which have no size; the rendering of the shape is usually composed of pixels, which are roughly square. These pixels exist in “device coordinates”, which are gotten by transforming the user-supplied coordinates by all of the user-supplied transformation, the medium transformation, and the transformation that maps from the sheet to the display device. (Note that if the last transformation is a pure translation that translates by an integer multiple of device units, then it has no effect on the rendering other than placement of the figure drawn on the display device.)

Roughly speaking, a pixel is affected by drawing a shape only when it is inside the shape (we will define what we mean by “inside” in a moment). Since pixels are little squares and the abstract points have no size, for most shapes there will be many pixels that lie only partially inside the shape. Therefore, it is important to describe the conventions used by CLIM as to which pixels should be affected when drawing a shape, so that the proper interface to the per-platform rendering engine can be constructed. (It is worth noting that on devices that support color or grayscale, the rendering engine may attempt to draw a pixel that is partially inside the shape darker or lighter, depending on how much of it is inside the shape. This is called anti-aliasing.) The conventions used by CLIM is the same as the conventions used by X11:

• A pixel is a addressed by its upper-left corner.

• A pixel is considered to be inside a shape, and hence affected by the rendering of that shape, if the center of the pixel is inside the shape. If the center of the pixel lies exactly on the boundary of the shape, it is considered to be inside if the inside of the shape is immediately to the right (increasing x direction on the display device) of the center point of the pixel. If the center of the pixel lies exactly on a horizontal boundary, it is considered to be inside if the inside of the shape is immediately below (increasing y direction on the display device) the center point of the pixel.

• An unfilled shape is drawn by taking the filled shape consisting of those points that are within 1/2 the line thickness from the outline curve (using a normal distance function, that is, the length of the line drawn at right angles to the tangent to the outline curve at the nearest point), and applying the second rule, above.

Figure 12.1: Pixel assignment with boundary on decision points.

It is important to note that these rules imply that the decision point used for insideness checking is offset from the point used for addressing the pixel by half a device unit in both the x and y directions. It is worth considering the motivations for these conventions.

When two shapes share a common edge, it is important that only one of the shapes own any pixel. The two triangles in Figure 12.1 illustrate this. The pixels along the diagonal belong to the lower figure. When the decision point of the pixel (its center) lies to one side of the line or the other, there is no issue. When the boundary passes through a decision point, which side the inside of the figure is on is used to decide. These are the triangles that CLIM implementations should attempt to draw in this case.

The reason for choosing the decision point half a pixel offset from the address point is to reduce the number of common figures (such as rectilinear lines and rectangles with integral coordinates) that invoke the boundary condition rule. This usually leads to more symmetrical results. For instance, in Figure 12.2, we see a circle drawn when the decision point is the same as the address point. The four lighter points are indeterminate: it is not clear whether they are inside or outside the shape. Since we want to have each boundary case determined according to which side has the figure on it, and since we must apply the same rule uniformly for all figures, we have no choice but to pick only two of the four points, leading to an undesirable lopsided figure.

If we had instead chosen to take all four boundary points, we would have a nice symmetrical figure. However, since this figure is symmetrical about a whole pixel, it is one pixel wider than it ought to be. The problem with this can be seen clearly in Figure 12.3 if we attempt to draw a rectangle and circle overlaid with the following code:

(defun draw-test (sheet radius)
  (draw-circle* sheet 0 0 radius :ink +foreground-ink+)
  (draw-rectangle* sheet (- radius) (- radius) (+ radius) (+ radius)
                   :ink +flipping-ink+))

It is for this reason that we choose to have the decision point at the center of the pixel. This draws circles that look like the one in Figure 12.4. It is this shape that CLIM implementations CHAPTER 12. GRAPHICS 96

Figure 12.2: Choosing any two of the shaded pixels causes asymmetry. Figure 12.3: Two forms of a circle inscribed in a rectangle.

Figure 12.4: An aesthetically pleasing circle.

should attempt to draw.

A consequence of these rendering conventions is that, when the start or end coordinate (minus 1/2 the line thickness, if the shape is a path) is not an integer, then rendering is not symmetric under reflection transformations. Thus to correctly and portably draw an outline of thickness 1 around a (rectilinear) rectangular area with integral coordinates, the outline path must have half-integral coordinates. Drawing rectilinear areas whose boundaries are not on pixel boundaries cannot be guaranteed to be portable. Another way to say the same thing is that the “control points” for a rectangular area are at the corners, while the control points for a rectilinear path are in the center of the path, not at the corners. Therefore, in order for a path and an area to abut seamlessly, the coordinates of the path must be offset from the coordinates of the area by half the path’s thickness.

12.3.1 Permissible Alternatives During Rendering

Some platforms may distinguish between lines of the minimum thinness from lines that are thicker than that. The two rasterizations depicted in Figure 12.5 are both perfectly reasonable rasterizations of tilted lines that are a single device unit wide. The right-hand line is drawn as a tilted rectangle, the left as the “thinnest visible” line.

For thick lines, a platform may choose to draw the exact tilted fractional rectangle, or the coordinates of that rectangle might be rounded so that it is distorted into another polygonal shape. The latter case may be prove to be faster on some platforms. The two rasterizations depicted in Figure 12.6 are both reasonable.

The decision about which side of the shape to take when a boundary line passes through the decision point is made arbitrarily, although we have chosen to be compatible with the X11 definition. This is not necessarily the most convenient decision. The main problem with this is illustrated by the case of a horizontal line (see Figure 12.7). Our definition chooses to draw CHAPTER 12. GRAPHICS 98

Figure 12.5: Two examples of lines of thickness 1. Figure 12.6: Two examples of lines of thickness 2.

Figure 12.7: Two possible definitions of horizontal lines. Left figure is X11 definition.

the rectangular slice above the coordinates, since those pixels are the ones whose centers have the figure immediately above them. This definition makes it simpler to draw rectilinear borders around rectilinear areas.

12.4 Drawing Functions

Each drawing function takes keyword arguments allowing any drawing option or suboption to be supplied separately in the call to the function. In some implementations of CLIM, the drawing functions may ignore drawing options that are irrelevant to that function; in other implementations, an error may be signalled. See Chapter 10 for a more complete discussion of the drawing options. An error will be signalled if any drawing function is called on a sheet that is mute for output.

While the functions in this section are specified to be called on sheets, they can also be called on streams and mediums.

Implementation note: The drawing functions are all specified as ordinary functions, not as generic functions. This is intended to ease the task of writing compile-time optimizations that avoid keyword argument taking, check for such things as constant drawing options, and so forth. If you need to specialize any of the drawing methods, use define-drawing-function-method.

Each drawing function comes in two forms, a “structured” version and a “spread” version. The structured version passes points, whereas the spread version passes coordinates. See Section 2.3 for more information on this.

Any drawing functions may create an output record that corresponds to the figure being drawn. See Chapter 15 for a complete discussion of output recording. During output recording, none of these functions capture any arguments that are points, point sequences, coordinate sequences, or text strings. Line styles, text styles, transformations, and clipping regions may be captured.

Note that the CLIM specification does not specify more complex shapes such as cubic splines and Bézier curves. These are suitable candidates for extensions to CLIM.

⇒ draw-point sheet point &key ink clipping-region transformation line-style line-thickness line-

unit [Function] ⇒ draw-point* sheet x y &key ink clipping-region transformation line-style line-thickness line-unit

[Function]

These functions (structured and spread arguments, respectively) draw a single point on the sheet sheet at the point point (or the position (x, y)).

The unit and thickness components of the current line style (see Chapter 10) affect the drawing of the point by controlling the size on the display device of the “blob” that is used to render the point.

⇒ draw-points sheet point-seq &key ink clipping-region transformation line-style line-thickness

line-unit [Function] ⇒ draw-points* sheet coord-seq &key ink clipping-region transformation line-style line-thickness

line-unit [Function]

These functions (structured and spread arguments, respectively) draw a set of points on the sheet sheet. point-seq is a sequence of point objects; coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements.

These functions exist as equivalents to

(map nil #`(lambda (point) (draw-point sheet point)) point-seq)

and

(do ((i 0 (+ i 2)))
    ((= i (length coord-seq)))
  (draw-point* sheet (elt coord-seq i) (elt coord-seq (+ i 1))))

for convenience and efficiency.

⇒ draw-line sheet point1 point2 &key ink clipping-region transformation line-style line-thickness

line-unit line-dashes line-cap-shape [Function] ⇒ draw-line* sheet x1 y1 x2 y2 &key ink clipping-region transformation line-style line-thickness

line-unit line-dashes line-cap-shape [Function]

These functions (structured and spread arguments, respectively) draw a line segment on the sheet sheet from the point point1 to point2 (or from the position (x1,y1) to (x2,y2)).

The current line style (see Chapter 10) affects the drawing of the line in the obvious way, except that the joint shape has no effect. Dashed lines start dashing at point1.

⇒ draw-lines sheet point-seq &key ink clipping-region transformation line-style line-thickness lineunit line-dashes line-cap-shape [Function] ⇒ draw-lines* sheet coord-seq &key ink clipping-region transformation line-style line-thickness

line-unit line-dashes line-cap-shape [Function]

These functions (structured and spread arguments, respectively) draw a set of disconnected line segments. point-seq is a sequence of point objects; coord-seq is a sequence of coordinate pairs. It is an error if coord-seq does not contain an even number of elements.

These functions are equivalent to

(do ((i 0 (+ i 2)))
    ((= i (length point-seq)))
  (draw-line sheet (elt point-seq i) (elt point-seq (1+ i))))

and

(do ((i 0 (+ i 4)))
    ((= i (length coord-seq)))
  (draw-line* sheet (elt coord-seq i) (elt coord-seq (+ i 1))
                    (elt coord-seq (+ i 2)) (elt coord-seq (+ i 3))))

⇒ draw-polygon sheet point-seq &key (filled t) (closed t) ink clipping-region transformation line-

style line-thickness line-unit line-dashes line-joint-shape line-cap-shape [Function] ⇒ draw-polygon* sheet coord-seq &key (filled t) (closed t) ink clipping-region transformation line-

style line-thickness line-unit line-dashes line-joint-shape line-cap-shape [Function]

Draws a polygon or polyline on the sheet sheet. When filled is false, this draws a set of connected lines, otherwise it draws a filled polygon. If closed is true (the default) and filled is false, it ensures that a segment is drawn that connects the ending point of the last segment to the starting point of the first segment. The current line style (see Chapter 10) affects the drawing of unfilled polygons in the obvious way. The cap shape affects only the “open” vertices in the case when closed is false. Dashed lines start dashing at the starting point of the first segment, and may or may not continue dashing across vertices, depending on the window system.

point-seq is a sequence of point objects; coord-seq is a sequence of coordinate pairs. It is an error if coord-seq does not contain an even number of elements.

If filled is true, a closed polygon is drawn and filled in. In this case, closed is assumed to be true as well.

⇒ draw-rectangle* sheet x1 y1 x2 y2 &key (filled t) ink clipping-region transformation line-style line-thickness line-unit line-dashes line-joint-shape [Function]

Draws either a filled or unfilled rectangle on the sheet sheet that has its sides aligned with the coordinate axes. One corner of the rectangle is at the position (x1,y1) and the opposite corner is at (x2,y2). The arguments x1, y1, x2, and y1 are real numbers that are canonicalized in the

same way as for make-bounding-rectangle. filled is as for draw-polygon*.

Issue: This needs some good short text to explain that “aligned with the coordinate axes” is the axes relative to the current transformation, not the result of transforming the points. But I’m having trouble dreaming up such text. — DCPL

The current line style (see Chapter 10) affects the drawing of unfilled rectangles in the obvious way, except that the cap shape has no effect.

⇒ draw-ellipse sheet center-pt radius-1-dx radius-1-dy radius-2-dx radius-2-dy &key (filled t) start-angle end-angle ink clipping-region transformation line-style line-thickness line-unit linedashes line-cap-shape [Function]

⇒ draw-ellipse* sheet center-x center-y radius-1-dx radius-1-dy radius-2-dx radius-2-dy &key (filled t) start-angle end-angle ink clipping-region transformation line-style line-thickness lineunit line-dashes line-cap-shape [Function]

These functions (structured and spread arguments, respectively) draw an ellipse (when filled is true, the default) or an elliptical arc (when filled is false) on the sheet sheet. The center of the ellipse is the point center-pt (or the position (center-x,center-y)).

Two vectors, (radius-1-dx,radius-1-dy) and (radius-2-dx,radius-2-dy) specify the bounding parallelogram of the ellipse as explained in Chapter 3. All of the radii are real numbers. If the two vectors are collinear, the ellipse is not well-defined and the ellipse-not-well-defined error will be signalled. The special case of an ellipse with its major axes aligned with the coordinate axes can be obtained by setting both radius-1-dy and radius-2-dx to 0.

start-angle and end-angle are real numbers that specify an arc rather than a complete ellipse. Angles are measured with respect to the positive x axis. The elliptical arc runs positively (counter-clockwise) from start-angle to end-angle. The default for start-angle is 0; the default for end-angle is 2π.

In the case of a “filled arc” (that is when filled is true and start-angle or end-angle are supplied and are not 0 and 2π), the figure drawn is the “pie slice” area swept out by a line from the center of the ellipse to a point on the boundary as the boundary point moves from start-angle to end-angle.

When drawing unfilled ellipses, the current line style (see Chapter 10) affects the drawing in the obvious way, except that the joint shape has no effect. Dashed elliptical arcs start “dashing” at start-angle.

⇒ draw-circle sheet center-pt radius &key (filled t) start-angle end-angle ink clipping-region

transformation line-style line-thickness line-unit line-dashes line-cap-shape [Function] ⇒ draw-circle* sheet center-x center-y radius &key (filled t) start-angle end-angle ink clipping-

region transformation line-style line-thickness line-unit line-dashes line-cap-shape [Function]

These functions (structured and spread arguments, respectively) draw a circle (when filled is true, the default) or a circular arc (when filled is false) on the sheet sheet. The center of the circle is center-pt or (center-x,center-y) and the radius is radius. These are just special cases of

draw-ellipse and draw-ellipse*. filled is as for draw-ellipse*.

start-angle and end-angle allow the specification of an arc rather than a complete circle in the same manner as that of the ellipse functions, above.

The “filled arc” behavior is the same as that of an ellipse, above.

⇒ draw-text sheet string-or-char point &key text-style (start 0) end (align-x :left) (align-y :baseline) toward-point transform-glyphs ink clipping-region transformation text-style text-family text-face text-size [Function]

⇒ draw-text* sheet string-or-char x y &key text-style (start 0) end (align-x :left) (align-y :baseline) toward-x toward-y transform-glyphs ink clipping-region transformation text-style text-family textface text-size [Function]

The text specified by string-or-char is drawn on the sheet sheet starting at the position specified by the point point (or the position (x, y)). The exact definition of “starting at” is dependent on align-x and align-y. align-x is one of :left, :center, or :right. align-y is one of :baseline, :top, :center, or :bottom. align-x defaults to :left and align-y defaults to :baseline; with these defaults, the first glyph is drawn with its left edge and its baseline at point.

text-style defaults to nil, meaning that the text will be drawn using the current text style of the sheet’s medium.

start and end specify the start and end of the string, in the case where string-or-char is a string. If start is supplied, it must be an integer that is less than the length of the string. If end is supplied, it must be an integer that is less than the length of the string, but greater than or equal to start.

Normally, glyphs are drawn from left to right no matter what transformation is in effect. towardx or toward-y (derived from toward-point in the case of draw-text) can be used to change the direction from one glyph to the next one. For example, if toward-x is less than the x position of point, then the glyphs will be drawn from right to left. If toward-y is greater than the y position of point, then the glyphs’ baselines will be positioned one above another. More precisely, the reference point in each glyph lies on a line from point to toward-point, and the spacing of each glyph is determined by packing rectangles along that line, where each rectangle is “char-width” wide and “char-height” high.

If transform-glyphs is true, then each glyph is transformed as an image before it is drawn. That is, if a rotation transformation is in effect, then each glyph will be rotated individually. If transform-glyphs is not supplied, then the individual glyphs are not subject to the current transformation. It is permissible for CLIM implementations to ignore transform-glyphs if it is too expensive to implement.

12.5 Pixmaps

A pixmap can be thought of as an “off-screen window”, that is, a sheet that can be used for graphical output, but is not visible on any display device. Pixmaps are provided to allow a programmer to generate a piece of output associated with some display device that can then be rapidly drawn on a real display device. For example, an electrical CAD system might generate a pixmap that corresponds to a complex, frequently used part in a VLSI schematic, and then use copy-from-pixmap to draw the part as needed.

The exact representation of a pixmap is explicitly unspecified. There is no interaction between the pixmap operations and output recording, that is, displaying a pixmap on a sheet is a pure drawing operation that affects only the display, not the output history. Some sheets may not support pixmaps; in this case, an error will be signalled.

⇒ allocate-pixmap sheet width height [Generic Function]

Allocates and returns a pixmap object that can be used on any sheet that shares the same characteristics as sheet. The exact definition of “shared characteristics” will vary from host to host. The pixmap is width units wide, height units high, and as deep as is necessary to store the information for the sheet. The exact representation of pixmaps is explicitly unspecified.

The returned value is the pixmap.

⇒ deallocate-pixmap pixmap [Generic Function]

Deallocates the pixmap pixmap.

⇒ copy-to-pixmap sheet sheet-x sheet-y width height &optional pixmap (pixmap-x 0) (pixmap-y 0) [Generic Function]

Copies the pixels from the sheet sheet starting at the position specified by (sheet-x,sheet-y) into the pixmap pixmap at the position specified by (pixmap-x,pixmap-y). A rectangle whose width and height is specified by width and height is copied. sheet-x and sheet-y are specified in window coordinates, where (0, 0) is the upper-left corner of the window, including the margin area.

If pixmap is not supplied, a new pixmap will be allocated. Otherwise, pixmap must be an object returned by allocate-pixmap that has the appropriate characteristics for sheet.

The returned value is the pixmap.

⇒ copy-from-pixmap pixmap pixmap-x pixmap-y width height sheet window-x window-y [Generic Function]

Copies the pixels from the pixmap pixmap starting at the position specified by (pixmap-x,pixmap-

y) into the sheet sheet at the position (sheet-x,sheet-y). A rectangle whose width and height is specified by width and height is copied. sheet-x and sheet-y are specified in window coordinates, where (0, 0) is the upper-left corner of the window, including the margin area.

pixmap must be an object returned by allocate-pixmap that has the appropriate characteristics for sheet.

The returned value is the pixmap.

This is intended to specialize on both the pixmap and sheet arguments.

⇒ copy-area sheet from-x from-y width height to-x to-y [Generic Function]

Copies the pixels from the sheet sheet starting at the position specified by (from-x,from-y) to the position (to-x,to-y) on the same sheet. A rectangle whose width and height is specified by width and height is copied. from-x, from-y, to-x, and to-y are specified in window coordinates, where (0, 0) is the upper-left corner of the window, including the margin area.

⇒ with-output-to-pixmap-stream (stream-var sheet) &body body  [Macro]

Binds stream-var to a “pixmap stream”, that is, a stream that does output to a pixmap with the characteristics appropriate to the sheet sheet, and then evaluates body in that context. All the output done to the stream stream-var inside of body is drawn on the pixmap stream.

The returned value is a pixmap that can be drawn on sheet using copy-from-pixmap.

12.6 Graphics Protocols

Every medium must implement methods for the various graphical drawing generic functions. Furthermore, every sheet that supports the standard output protocol must implement these methods as well; often, the sheet methods will trampoline to the methods on the sheet’s medium. All of these generic functions take the same arguments as the non-generic spread function equivalents, except the arguments that are keyword arguments in the non-generic functions are positional arguments in the generic functions.

Every port must implement methods for the various graphical drawing generic functions. All of these generic functions take as (specialized) arguments the port and medium, followed by an x and a y offset, followed by the drawing function-specific arguments, followed by the ink, line style (or text style), and clipping region.

The drawing function-specific arguments will either be x and y positions, or a sequence of x and y positions. These positions will be in medium coordinates, and must be transformed by applying the medium’s device transformation in order to produce device coordinates. The x and y offsets are real numbers that can be used to optimize the implementation of a simple scrolling transformation. These offsets must be added to the positions before the device transformation is applied. Note that the user transformation will have already been applied to the positions when the port-specific drawing function is called.

The ink, line style (or text style), and clipping regions arguments are optional, and default

from the medium (medium-ink, medium-line-style (or medium-current-text-style), and

medium-clipping-region, respectively). Each port method will decode the ink, line (or text) style, and clipping region in a port-specific way and communicate it to the underlying port.

Issue: Do we need define-graphics-generic and define-graphics-method, or whatever, so

that the graphics protocol is easier to extend? Such things should also help define the hooks into output recording. — SWM

12.6.1 General Behavior of Drawing Functions

Using draw-line* as an example, calling any of the drawing functions specified above results in the following series of function calls on a non-output recording sheet:

• A program calls draw-line* on arguments sheet, x1, y1, x2, and y2, and perhaps some drawing options.

• draw-line* merges the supplied drawing options into the sheet’s medium, and then calls medium-draw-line on the sheet. (Note that a compiler macro could detect the case where there are no drawing options or constant drawing options, and do this at compile time.)

• medium-draw-line on the sheet trampolines to the medium’s medium-draw-line method.

• medium-draw-line performs the necessary user transformations by applying the medium transformation to x1, y1, x2, and y2, and to the clipping region. Then medium-draw-line calls port-draw-line to do the actual drawing.

12.6.2 Medium-specific Drawing Functions

All mediums and all sheets that support the standard output protocol must implement methods for the following generic functions.

: Note: CLIM implementations should provide “trampoline” methods on sheets that support the standard output protocol that simply call the same generic function on the medium. Sheets that support output recording will require extra mechanism before delegating to the medium in order to implement such functionality as creating output records and handling scrolling.

⇒ medium-draw-point medium x y [Generic Function]

Draws a point on the medium medium. The point is drawn at (x, y), transformed by the medium’s current transformation. medium-draw-point will call port-draw-point in order to draw the point.

⇒ medium-draw-points medium coord-seq [Generic Function]

Draws a set of points on the medium medium. coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements. The coordinates in coord-seq are transformed by the medium’s current transformation. medium-draw-points will call port-draw-points in order to draw the points.

⇒ medium-draw-line medium x1 y1 x2 y2 [Generic Function]

Draws a line on the medium medium. The line is drawn from (x1, y1) to (x2, y2), with the start and end positions transformed by the medium’s current transformation. medium-draw-line will call port-draw-line in order to draw the line.

⇒ medium-draw-lines medium coord-seq [Generic Function] Draws a set of disconnected lines on the medium medium. coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements. The coordinates in coord-seq are transformed by the medium’s current transformation.

medium-draw-lines will call port-draw-lines in order to draw the line.

⇒ medium-draw-polygon medium coord-seq closed [Generic Function]

Draws a polygon or polyline on the medium medium. coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements. The coordinates in coord-seq are transformed by the medium’s current transformation. mediumdraw-polygon will call port-draw-polygon in order to draw the polygon.

⇒ medium-draw-rectangle medium x1 y1 x2 y2 [Generic Function]

Draws a rectangle on the medium medium. The corners of the rectangle are at (x1, y1) and (x2, y2), with the corner positions transformed by the medium’s current transformation. mediumdraw-rectangle will call port-draw-rectangle in order to draw the rectangle.

⇒ medium-draw-ellipse medium center-x center-y radius-1-dx radius-1-dy radius-2-dx radius-2-dy start-angle end-angle [Generic Function]

Draws an rectangle on the medium medium. The center of the rectangle is at (x, y), and the radii are specified by the two vectors (radius-1-dx,radius-1-dy) and (radius-2-dx,radius-2-dy). The center point and radii are transformed by the medium’s current transformation. mediumdraw-ellipse will call port-draw-ellipse in order to draw the ellipse.

start-angle and end-angle are real numbers that specify an arc rather than a complete ellipse. The medium transformation must be applied to the angles as well.

⇒ medium-draw-text medium text x y (start 0) end (align-x :left) (align-y :baseline) toward-x toward-y transform-glyphs [Generic Function]

Draws a character or a string on the medium medium. The text is drawn starting at (x, y), and towards (toward-x,toward-y); these positions are transformed by the medium’s current trans-

formation. medium-draw-text will call either port-draw-string or port-draw-character in

order to draw the text.

12.6.3 Port-specific Drawing Functions

The following port-specific functions are required by the drawing functions in the API. If the optional arguments to these functions are not supplied, they are defaulted from the medium.

⇒ port-draw-point port medium x-offset y-offset x y &optional ink line-style clipping-region [Generic Function]

Draws a point on the medium medium on the port port. The point is drawn at (x, y), with x-offset added to x and y-offset added to y, and the device transformation applied.

⇒ port-draw-points port medium x-offset y-offset coord-seq &optional ink line-style clippingregion [Generic Function]

Draws a set of points on the medium medium on the port port. coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements. port-draw-points could be implemented by repeatedly calling port-draw-point, but some ports may support faster primitives to do this.

⇒ port-draw-line port medium x-offset y-offset x1 y1 x2 y2 &optional ink line-style clippingregion [Generic Function]

Draws a line on the medium medium on the port port. The line is drawn from (x1, y1) to (x2, y2), with x-offset added to x1 and x2 and y-offset added to y1 and y2, and the device transformation applied.

⇒ port-draw-lines port medium x-offset y-offset coord-seq &optional ink line-style clippingregion [Generic Function]

Draws a set of disconnected lines on the medium medium on the port port. coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements. port-draw-lines could be implemented by repeatedly calling port-draw-line, but some ports may support faster primitives to do this.

⇒ port-draw-polygon port medium x-offset y-offset coord-seq closed &optional ink line-style clippingregion [Generic Function]

Draws a polygon or polyline on the medium medium on the port port. When line-style is nil, this draws a filled polygon; otherwise, line-style is the line style to use when drawing a set of connected lines. coord-seq is a sequence of coordinate pairs, which are real numbers. It is an error if coord-seq does not contain an even number of elements. The coordinate sequence specifies the corners of the polygon; x-offset is added to the x coordinates and y-offset is added to the y coordinates, and the device transformation is then applied.

When port-draw-polygon is drawing a set of connected lines, then if closed is true, a closed polygon is drawn. If closed is false, the polygon will not be closed.

⇒ port-draw-rectangle port medium x-offset y-offset x1 y1 x2 y2 &optional ink line-style clippingregion [Generic Function]

Draws a rectangle on the medium medium on the port port. When line-style is nil, this draws a filled rectangle; otherwise, line-style is the line style to use when drawing an unfilled rectangle. The corners of the rectangle are at (x1, y1) and (x2, y2), with x-offset added to x1 and x2 and y-offset added to y1 and y2, and the device transformation applied.

⇒ port-draw-ellipse port medium x-offset y-offset center-x center-y radius-1-dx radius-1-dy radius-2-dx radius-2-dy start-angle end-angle &optional ink line-style clipping-region [Generic Function]

Draws an ellipse rectangle on the medium medium on the port port. When line-style is nil, this draws a filled ellipse; otherwise, line-style is the line style to use when drawing an unfilled ellipse.

The center of the ellipse is at (center-x,center-y), with x-offset and y-offset added to centerx and center-y, and the device transformation applied. Two vectors, (radius-1-dx,radius-1-dy) and (radius-2-dx,radius-2-dy) specify the bounding parallelogram of the ellipse as explained in Chapter 3. When the ellipse vectors have the same length, the ellipse is circle. The device transformation must be applied to the vectors as well.

start-angle and end-angle are real numbers that specify an arc rather than a complete ellipse. The device transformation must be applied to the angles as well.

⇒ port-draw-string port medium x-offset y-offset text x y (start 0) end (align-x :left) (align-y :baseline) toward-x toward-y transform-glyphs &optional ink text-style clipping-region [Generic Function]

Draws a string on the medium medium on the port port. The string is drawn starting at (x, y), and towards (toward-x,toward-y). align-x is one of :left, :center, or :right. align-y is one of

:baseline, :top, :center, or :bottom.

start and end specify the start and end of the string. start is an integer that is less than the length of the string. end is an integer that is less than the length of the string, but greater than or equal to start.

Normally, glyphs are drawn from left to right, but toward-x and toward-y can be used to change the direction from one glyph to the next one. The reference point in each glyph lies on a line from (x, y) to (toward-x,toward-y) and the spacing of each glyph is determined by packing rectangles along that line, where each rectangle is “char-width” wide and “char-height” high. Of course, some ports may not be able to fully support this.

If transform-glyphs is true, then each glyph is transformed as an image before it is drawn. It is permissible for CLIM implementations to ignore transform-glyphs if it is too expensive to implement.

⇒ port-draw-character port medium x-offset y-offset character x y (align-x :left) (align-y :baseline) &optional ink text-style clipping-region [Generic Function]

Draws a single character on the medium medium on the port port at the position (x, y). align-x

is one of :left, :center, or :right. align-y is one of :baseline, :top, :center, or :bottom.

Drawing in Color

This chapter describes the :ink drawing option and the simpler values that can be supplied for that option, such as colors. More complex values that have a regular or irregular pattern in the ink are described in Chapter 14.

Issue: We need to add a thing called a “raster ink”, which includes things like plane masks, pixel values, etc. Be clear that this is a platform and device dependent. — SWM

Issue: We need to add a thing called a “palette”, which is simply an abstract color map. — SWM

13.1 The :ink Drawing Option

The :ink drawing option, used with the drawing functions described in Chapter 12, can take as its value:

• a color,

• an opacity,

   • the constant +foreground-ink+,
   • the constant +background-ink+,

• a flipping ink, or

• other values described in Chapter 14

More exactly, an ink can be any member of the class design. For now you may think of a design as a possibly translucent color. More general designs are described in Chapter 14.

The drawing functions work by selecting a region of the drawing plane and painting it with color. The region to be painted is the intersection of the shape specified by the drawing function and the :clipping-region drawing option, which is then transformed by the :transformation drawing option. The :ink drawing option is a design that specifies a new arrangement of colors (and opacities) in this region of the medium’s drawing plane. Any viewports or dataports attached to this drawing plane are updated accordingly. The :ink drawing option is never affected by the :transformation drawing option nor by the sheet transformation; this ensures that stipple patterns on adjacent sheets join seamlessly.

Issue: The description of how the clipping region and transformations contribute isn’t good enough. It is true if there are no other transformations and clipping regions present, and both are specified in the current drawing operation. But it doesn’t say what happens if things are nested. I’m not sure it needs to. Rather, I think it should just say that the the region is clipped by the current clipping region in effect, then transformed by the current transform in effect, and that the rules for these are discussed in the drawing options section. — DCPL

Drawing consists conceptually of the following sequence of operations, performed in parallel at every point in the drawing plane. Of course, the actual implementation does not involve an infinite (or large parallel) computation.

1. The design specifies a color and an opacity at the point. These can depend on the drawing plane’s current color and opacity, on the medium’s foreground color, and on the medium’s background color.

2. The color blending function is applied to the design’s color and opacity and the drawing plane’s color and opacity, returning a new color and opacity for the point.

3. The drawing plane’s color and opacity at that point are set to the new color and opacity.

13.2 Designs

⇒ design [Protocol Class]

A design is an object that represents a way of arranging colors and opacities in the drawing plane. The design class is the protocol class for designs. If you want to create a new class that behaves like a design, it should be a subclass of design. Subclasses of design must obey the design protocol.

The fundamental operation of the CLIM graphic drawing model is to draw a design onto a drawing plane, thus drawing is always controlled by designs. The designs discussed in this chapter do the same thing at each point in the drawing plane. Chapter 14 discusses more general designs and reveals that regions are also designs.

A design can be characterized in several different ways:

All designs are either bounded or unbounded. Bounded designs are transparent everywhere beyond a certain distance from a certain point. Drawing a bounded design has no effect on the drawing plane outside that distance. Unbounded designs have points of non-zero opacity arbitrarily far from the origin. Drawing an unbounded design affects the entire drawing plane.

All designs are either uniform or non-uniform. Uniform designs have the same color and opacity at every point in the drawing plane. Uniform designs are always unbounded, unless they are completely transparent.

All designs are either solid or translucent. At each point a solid design is either completely opaque or completely transparent. A solid design can be opaque at some points and transparent at others. In translucent designs, at least one point has an opacity that is intermediate between completely opaque and transparent.

All designs are either colorless or colored. Drawing a colorless design uses a default color specified by the medium’s foreground design. This is done by drawing with (compose-in +foregroundink+ the-colorless-design). See Chapter 14 for the details of compose-in.

⇒ designp object [Function]

Returns true if object is a design, otherwise returns false.

13.3 Color

⇒ color [Protocol Class]

A member of the class color is a completely opaque design that represents the intuitive definition of color: white, black, red, pale yellow, and so forth. The visual appearance of a single point is completely described by its color. Drawing a color sets the color of every point in the drawing plane to that color, and sets the opacity to 1. The color class is the protocol class for a color, and is a subclass of design. If you want to create a new class that behaves like a color, it should be a subclass of color. Subclasses of color must obey the color protocol.

All of the standard instantiable color classes provided by CLIM are immutable.

A color can be specified by three real numbers between 0 and 1 (inclusive), giving the amounts of red, green, and blue. Three 0’s mean black; three 1’s mean white. The intensity-hue-saturation color model is also supported, but the red-green-blue color model is the primary model we will use in the specification.

⇒ colorp object [Function]

Returns true if object is a color, otherwise returns false.

The following functions create colors. These functions produce objects that have equivalent effects; the only difference is in how the color components are specified. The resulting objects are indistinguishable when drawn. Whether these functions use the specified values exactly or approximate them because of limited color resolution is unspecified. Whether these functions create a new object or return an existing object with equivalent color component values is unspecified.

⇒ make-rgb-color red green blue [Function] Returns a member of class color. The red, green, and blue arguments are real numbers between 0 and 1 (inclusive) that specify the values of the corresponding color components.

⇒ make-ihs-color intensity hue saturation [Function]

Returns a member of class color. The intensity argument is a real number between 0 and \sqrt{3} (inclusive). The hue and saturation arguments are real numbers between 0 and 1 (inclusive).

⇒ make-gray-color luminance [Function]

Returns a member of class color. luminance is a real number between 0 and 1 (inclusive). On a black-on-white display device, 0 means black, 1 means white, and the values in between are shades of gray. On a white-on-black display device, 0 means white, 1 means black, and the values in between are shades of gray.

The following two functions comprise the color protocol. Both of them return the components of a color. All subclasses of color must implement methods for these generic functions.

⇒ color-rgb color [Generic Function]

Returns three values, the red, green, and blue components of the color color. The values are real numbers between 0 and 1 (inclusive).

⇒ color-ihs color [Generic Function]

Returns three values, the intensity, hue, and saturation components of the color color. The first value is a real number between 0 andn \sqrt{3} (inclusive). The second and third values are real numbers between 0 and 1 (inclusive).

13.3.1 Standard Color Names

Table 13.1 lists all the provided color constants. Application programs can define other colors; these are provided because they are commonly used in the X Windows community, not because there is anything special about these particular colors. This table is a subset of the color listed in the file /X11/R4/mit/rgb/rgb.txt, from the X11 R4 distribution.

13.3.2 Contrasting Colors

⇒ make-contrasting-inks n &optional k  [Function]

If k is not supplied, this returns a vector of n designs with recognizably different appearance. Elements of the vector are guaranteed to be acceptable values for the :ink argument to the drawing functions, and will not include +foreground-ink+, +background-ink+, or nil. Their class is otherwise unspecified. The vector is a fresh object that may be modified.

If k is supplied, it must be an integer between 0 and n − 1 (inclusive), in which case makecontrasting-inks returns the k’th design rather than returning a vector of designs.

+alice-blue+           +antique-white+           +aquamarine+
+azure+                +beige+                   +bisque+
+black+                +blanched-almond+         +blue+
+blue-violet+          +brown+                   +burlywood+
+cadet-blue+           +chartreuse+              +chocolate+
+coral+                +cornflower-blue+         +cornsilk+
+cyan+                 +dark-goldenrod+          +dark-green+
+dark-khaki+           +dark-olive-green+        +dark-orange+
+dark-orchid+          +dark-salmon+             +dark-sea-green+
+dark-slate-blue+      +dark-slate-gray+         +dark-turquoise+
+dark-violet+          +deep-pink+               +deep-sky-blue+
+dim-gray+             +dodger-blue+             +firebrick+
+floral-white+         +forest-green+            +gainsboro+
+ghost-white+          +gold+                    +goldenrod+
+gray+                 +green+                   +green-yellow+
+honeydew+             +hot-pink+                +indian-red+
+ivory+                +khaki+                   +lavender+
+lavender-blush+       +lawn-green+              +lemon-chiffon+
+light-blue+           +light-coral+             +light-cyan+
+light-goldenrod+      +light-goldenrod-yellow+  +light-gray+
+light-pink+           +light-salmon+            +light-sea-green+
+light-sky-blue+       +light-slate-blue+        +light-slate-gray+
+light-steel-blue+     +light-yellow+            +lime-green+
+linen+                +magenta+                 +maroon+
+medium-aquamarine+    +medium-blue+             +medium-orchid+
+medium-purple+        +medium-sea-green+        +medium-slate-blue+
+medium-spring-green+  +medium-turquoise+        +medium-violet-red+
+midnight-blue+        +mint-cream+              +misty-rose+
+moccasin+             +navajo-white+            +navy-blue+
+old-lace+             +olive-drab+              +orange+
+orange-red+           +orchid+                  +pale-goldenrod+
+pale-green+           +pale-turquoise+          +pale-violet-red+
+papaya-whip+          +peach-puff+              +peru+
+pink+                 +plum+                    +powder-blue+
+purple+               +red+                     +rosy-brown+
+royal-blue+           +saddle-brown+            +salmon+
+sandy-brown+          +sea-green+               +seashell+
+sienna+               +sky-blue+                +slate-blue+
+slate-gray+           +snow+                    +spring-green+
+steel-blue+           +tan+                     +thistle+
+tomato+               +turquoise+               +violet+
+violet-red+           +wheat+                   +white+
+white-smoke+          +yellow+                  +yellow-green+

Table 13.1: Table of Color Names If the implementation does not have n different contrasting inks, make-contrasting-inks signals an error. This will not happen unless n is greater than eight.

The rendering of the design may be a color or a stippled pattern, depending on whether the output medium supports color.

⇒ contrasting-inks-limit port  [Generic Function]

Returns the number of contrasting colors (or stipple patterns if port is monochrome or grayscale) that can be rendered on any medium on the port port. Implementations are encouraged to make this as large as possible, but it must be at least 8. All classes that obey the medium protocol must implement a method for this generic function.

13.4 Opacity

⇒ opacity [Protocol Class]

A member of the class opacity is a completely colorless design that is typically used as the second argument to compose-in to adjust the opacity of another design. See Chapter 14 for the details of compose-in. The opacity class is the protocol class for an opacity, and is a subclass of design. If you want to create a new class that behaves like an opacity, it should be a subclass of opacity. Subclasses of opacity must obey the opacity protocol.

All of the standard instantiable opacity classes provided by CLIM are immutable.

Opacity controls how graphical output covers previous output. Opacity can vary from totally opaque to totally transparent. Intermediate opacity values result in color blending so that the earlier picture shows through what is drawn on top of it.

An opacity may be specified by a real number between 0 and 1 (inclusive). 0 is completely transparent, 1 is completely opaque, fractions are translucent. The opacity of a design is the degree to which it hides the previous contents of the drawing plane when it is drawn.

The fully transparent and fully opaque opacity levels (that is, opacities 0 and 1) must always be supported, but a valid CLIM implementation might only support a handful of opacity levels in between (including none). A valid CLIM implementation might implement color blending and unsaturated colors by stippling, although it is preferred, when possible, for a viewport to display a uniform color as a uniform color rather than as a perceptible stipple.

⇒ opacityp object [Function]

Returns true if object is an opacity, otherwise returns false.

The following function returns an opacity:

⇒ make-opacity value [Function]

Returns a member of class opacity whose opacity is value, which is a real number in the range from 0 to 1 (inclusive), where 0 is fully transparent and 1 is fully opaque.

The following function returns the sole component of an opacity. This is the only function in the opacity protocol. All subclasses of opacity must implement methods for this generic function.

⇒ opacity-value opacity [Generic Function]

Returns the opacity value of the opacity opacity, which is a real number in the range from 0 to 1 (inclusive).

13.5 Color Blending

Drawing a design that is not completely opaque at all points allows the previous contents of the drawing plane to show through. The simplest case is drawing a solid design: where the design is opaque, it replaces the previous contents of the drawing plane; where the design is transparent, it leaves the drawing plane unchanged. In the more general case of drawing a translucent design, the resulting color is a blend of the design’s color and the previous color of the drawing plane. For purposes of color blending, the drawn design is called the foreground and the drawing plane is called the background.

The function compose-over performs a similar operation: it combines two designs to produce a design, rather than combining a design and the contents of the drawing plane to produce the new contents of the drawing plane. For purposes of color blending, the first argument to compose-over is called the foreground and the second argument is called the background. See Chapter 14 for the details of compose-over.

Color blending is defined by an ideal function F: (r_{1}, g_{1}, b_{1}, o_{1}, r_{2}, g_{2}, b_{2}, o_{2}) → (r_{3}, g_{3}, b_{3}, o_{3}) that operates on the color and opacity at a single point. (r_{1}, g_{1}, b_{1}, o_{1}) are the foreground color and opacity. (r_{2}, g_{2}, b_{2}, o_{2}) are the background color and opacity. (r_{3}, g_{3}, b_{3}, o_{3}) are the resulting color and opacity. The color blending function F is conceptually applied at every point in the drawing plane.

F performs linear interpolation on all four components:

\begin{aligned}o_{3} & = & o_{1} & + & (1 − o_{1}) ∗ o_{2} \\ r_{3} & = & (o_{1} ∗ r_{1} & + & (1 − o_{1}) ∗ o_{2} ∗ r_{2})/o_{3} \\ g_{3} & = & (o_{1} ∗ g_{1} & + & (1 − o_{1}) ∗ o_{2} ∗ g_{2})/o_{3} \\ b_{3} & = & (o_{1} ∗ b_{1} & + & (1 − o_{1}) ∗ o_{2} ∗ b_{2})/o_{3} \end{aligned}

Note that if o_{3} is zero, these equations would divide zero by zero. In that case r_{3}, g_{3}, and b_{3} are defined to be zero.

CLIM requires that F be implemented exactly if o_{1} is zero or one or if o_{2} is zero. If o_{1} is zero, the result is the background. If o_{1} is one or o_{2} is zero, the result is the foreground. For fractional opacity values, an implementation can deviate from the ideal color blending function either because the implementation has limited opacity resolution or because the implementation can compute a different color blending function much more quickly.

If a medium’s background design is not completely opaque at all points, the consequences are unspecified. Consequently, a drawing plane is always opaque and drawing can use simplified color blending that assumes o_{2} = 1 and o_{3} = 1. However, compose-over must handle a non-opaque background correctly.

Note that these (r, g, b, o) quadruples of real numbers between 0 and 1 are mathematical and an implementation need not store information in this form. Most implementations are expected to use a different representation.

13.6 Indirect Inks

Drawing with an indirect ink is the same as drawing another design named directly. For example, +foreground-ink+ is a design that draws the medium’s foreground design and is the default value of the :ink drawing option. Indirect inks exist for the benefit of output recording. For example, one can draw with +foreground-ink+, change to a different medium-foreground, and replay the output record; the replayed output will come out in the new color.

You can change the foreground or background design of a medium at any time. This changes the contents of the medium’s drawing plane. The effect is as if everything on the drawing plane is erased, the background design is drawn onto the drawing plane, and then everything that was ever drawn (provided it was saved in the output history) is drawn over again, using the medium’s new foreground and background.

If an infinite recursion is created using an indirect ink, an error is signalled when the recursion is created, when the design is used for drawing, or both.

Two indirect inks are defined, but no advertised way is provided to create more of them.

⇒ +foreground-ink+  [Constant]

An indirect ink that uses the medium’s foreground design.

⇒ +background-ink+  [Constant]

An indirect ink that uses the medium’s background design.

13.7 Flipping Ink

⇒ make-flipping-ink design1 design2 [Function]

Returns a design that interchanges occurrences of the two designs design1 and design2. Drawing the resulting design over a background (either by drawing or with compose-over) is defined to change the color in the background that would have been drawn by design1 at that point into the color that would have been drawn by design2 at that point, and vice versa. The effect on any color other than the colors determined by those two designs is unspecified; however, drawing