(navigation image)
Home American Libraries | Canadian Libraries | Universal Library | Community Texts | Project Gutenberg | Children's Library | Biodiversity Heritage Library | Additional Collections
Search: Advanced Search
Anonymous User (login or join us)
Upload
See other formats

Full text of "X toolkit intrinsics programming manual for X version 1.1"

The Definitive Guides 
to the X Window System 



Volume Four 



X Toolkit Intrinsics 
Programming Manual 

for X Version 11 
By Adrian Nye and Tim O Reilly 



O Reilly & Associates, Inc. 



Volume Four 



X Toolkit Intrinsic s 
Programming Manual 



for Version 11 of the 
X Window System 

by Adrian Nye and Tim O Reilly 



O Reilly & Associates, Inc. 



Copyright 7990 O Reilly & Associates, Inc. 
All Rights Reserved 



The X Window System is a trademark of the Massachusetts Institute of Technology 

UNIX is a registered trademark of AT&T 
Macintosh is a trademark of Macintosh Laboratory, Inc., licensed to 

Apple Computer, Inc. 
MacPaint is a registered trademark of Apple Computers, Inc. 

OPEN LOOK is a trademark of AT AT 

XView and SunView are trademarks of Sun Microsystems, Inc. 

OSF/Motif is a trademark of the Open Software Foundation, Inc. 

DECwindows is a trademark of Digital Equipment Corporation 

Genera is a registered trademark of Symbolics, Inc. 

Cedar is a trademark of Xerox, Inc. 

Explorer is a trademark of Texas Instruments, Inc. 

Tetris is a trademark ofAcademySoft-ELORG 

C++ is a trademark of AT&T 

Revision and Printing History 

First Printing January 1990. 

Small Print 

Portions of this document (chiefly the appendices) are based in part on X Toolkit Intrinsics-C Language Interface, by 
Joel McCormack, Paul Asente, and Ralph Swick, and X Toolkit Athena Widgets-C Language Interface, by Ralph 
Swick and Terry Weissman. both of which are copyright 1985, 1986, 1987, 1988, 1989, 1990 the Massachusetts 
Institute of Technology, Cambridge, Massachusetts, and Digital Equipment Corporation, Maynard, Massachusetts. 

We ve used this material under the terms of its copyright, which grants free use, subject to the following conditions: 

"Permission to use, copy, modify and distribute this documentation (i.e., the original MIT 
and DEC material) for any purpose and without fee is hereby granted, provided that the 
above copyright notice appears in all copies and that both that copyright notice and this per 
mission notice appear in supporting documentation, and that the name of MET or Digital not 
be used in advertising or publicity pertaining to distribution of the software without specific, 
written prior permission. MIT and Digital make no representations about the suitability of 
the software described herein for any purpose. It is provided as is* without expressed or 
implied warranty." 

Note, however, that those portions of this document that are based on the original XI 1 documentation and other 
source material have been significantly revised, and that all such revisions are copyright 1990 O Reilly & Associ 
ates, Inc. Inasmuch as the proprietary revisions can t be separated from the freely copyable MIT source material, the 
net result is that copying of this document is not allowed. Sorry for the doublespeak! 

While every precaution has been taken in the preparation of this book, we assume no responsibility for errors or 
omissions. Neither do we assume any liability for damages resulting from the use of the information contained 
herein. 

ISBN 0-937 175-34-X 



The X Window System Series 

The books in the X Window System series from O Reilly and Associates 
are based in part on the original MIT X Window System documentation, 
but are far more comprehensive and easy to use. Over 20 computer 
vendors recommend or license volumes in the series. In short, these are the 
definitive guides to the X Window System. 

Volume 0, X Protocol Reference Manual. A complete programmer s 
reference to the X Network Protocol, the language in which computers 
communicate all the information between the X server and X clients. 414 
pages, $30.00 

Volumes 1 and 2, Xlib Programming Manual and Xlib 
Reference Manual. Complete guides to programming with the X library 
(Xlib), the lowest level of programming interface to X. 664 and 725 pages, 
$34.95 each, or $60.00 as a set. 

Volume 3, X Window System User s Guide. Describes window 
system concepts and the most common client applications available for X, 
Release 3. For experienced users, later chapters explain customizing the X 
environment and include an alternate .uwmrc file. 576 pages, $26.95 

Volumes 4 and 5, X Toolkit Intrinsics Programming Manual and 
X Toolkit Intrinsics Reference Manual. Complete guides to 
programming with the Xt Intrinsics, the library of C language routines 
created to facilitate the design of user interfaces, with reusable compon 
ents called widgets. 582 and 545 pages, $30.00 each, or $55.00 as a set. 

Volume 7, XView Programming Manual. XView is an easy-to-use 
toolkit, not just for Sun developers. This volume provides complete 
information on the XView toolkit, from concepts to creating XView 
applications to reference pages. 566 pages. $30.00. 

For orders or a free catalog of all our books, please contact us. For 
international orders (outside U.S. or Canada) see our list of distributors in 
the back of this book. 

O Reilly & Associates, Inc. 

Creators and publishers of Nutshell Handbooks 
HANDBOOKS 632 Petaluma Avenue Sebastopol CA 95472 

email: uunet!ora!nuts 1-800-338-6887 in CA 1-800-533-6887 +1 707-829-0515 





Table of Contents 



Page 



Preface 



XXI 



Summary of Contents xxiii 

Assumptions xxiv 

Related Documents xxv 

How to Use This Manual xxv 

Font Conventions Used in This Manual xxviii 

Requests for Comments xxix 

Bulk Sales Information xxix 

Obtaining the X Window System Software xxix 

Example Programs xxix 

Acknowledgments , ... xxx 



1 Introduction to the X Window System l 

1.1 The Server and Client 6 

1.2 The Software Hierarchy 8 

1.3 Event-driven Programming 10 

1.4 The Window Manager 1 1 

1.5 Extensions to X ..12 



2 Introduction to the X Toolkit 13 

2.1 Programming with Widgets 15 

2.1.1 Contents of a Widget Set 17 

2.1.2 Widget Classes and Instances 18 

2.1.3 Widget Configurability with Resources 22 

2.1.4 Widget Independence 23 

2.1.5 Widget-Application Interaction 25 

2.1.6 Xtand Object-oriented Programming (OOP) 28 

2.1.6.1 The Object 28 

2.1.6.2 Methods 29 

2.1.6.3 Messages 29 

2.1.6.4 Encapsulation 29 

2.2 Structure of X Toolkit Applications 30 

2.3 A Simple X Toolkit Application 31 

2.3.1 The Code 31 

2.3.2 Compiling the Application 34 

2.3.3 The Application-defaults File 36 



2.3.4 To Hardcode or Not to Hardcode 38 

2.4 Connecting Widgets to Application Code 39 

2.4.1 Callbacks 40 

2.4.2 Actions 43 

2.4.2.1 The Actions Table 45 

2.4.2.2 Format of an Action Procedure 46 

2.4.2.3 The Translation Table 47 

2.4.2.4 Hardcoding Translations 48 

2.5 More About Resources 49 

2.5.1 Setting and Getting Resources from the Application 50 

2.5.2 Core Resources 52 

2.5.3 Other Inherited Resources .. 54 



3 More Widget Programming Techniques 59 

3.1 Using Composite Widgets 61 

3.1.1 Setting Resources for an Instance Hierarchy 63 

3.1.2 Geometry Management in Practice 65 

3.2 Using Constraint Widgets 67 

3.3 Using Pop Ups 70 

3.4 More About Callbacks 77 

3.4.1 Passing Data to Callback Functions 77 

3.4.2 Callback Lists 79 

3.5 Application Resources 80 

3.5.1 The Application Data Structure 81 

3.5.2 The Resource List 81 

3.5.3 Getting the Resources 85 

3.6 Command-line Options 86 

3.6.1 Standard Command-line Options 86 

3.6.2 Defining Your Own Command-line Options 88 

3.7 Preventing User Customization of Widget Resources 91 

3.7.1 The Argument List 92 

3.7.1.1 Another Way to Set Arguments 93 

3.7.1.2 Merging Argument Lists 95 

3.7.2 The Varargs Interfaces 95 

3.8 Application Contexts 97 

3.8.1 Xtlnitialize Equivalents 98 



4 An Example Application 101 

4.1 xbitmapl: Bitmap Editor Using a BitmapEdit Widget 104 

4.1.1 Widget Public Functions 106 

4.1.2 Application-defaults File 107 

4.2 xbitmap2: Adding Scrollbars to Handle Large Bitmaps 107 

4.2.1 Overriding Translations 112 

4.2.2 Action Arguments in the Translation Table 113 



VI 



4.2.3 The resize_thumbs Action 113 

4.2.4 Scrollbar Callbacks 1 14 

4.3 xbitmap3: Adding Graphics to Display the Bitmap 116 

4.3.1 Graphics from the Application 119 

4.3.2 Writing a Bitmap File 122 

4.4 xbitmap4: Bitmap Editor Without a BitmapEdit Widget 123 



5 Inside a Widget 133 

5.1 Widget Source File Organization 135 

5.2 The Private Header File BitmapEditP.h 136 

5.2.1 Parts and Records 137 

5.2.2 Class Part and Class Record 138 

5.2.3 Instance Part and Instance Record 139 

5.3 The Widget Source File BitmapEditc 141 

5.3.1 Obligatory Include Files 141 

5.3.2 Defining the Resource List 143 

5.3.3 The Translation Table and Actions Table 145 

5.3.4 Declaring Methods 147 

5.3.5 Initializing the Class Record 148 

5.3.5.1 The Core Class Part 148 

5.3.5.2 Initializing the Core Methods 151 

5.3.6 Description of Core Methods 153 

5.3.7 Packaging the Class Record for Application Use 155 

5.3.8 A Sample Method 155 

5.4 The Public Header File BitmapEdiLh 158 

5.5 The Process of Widget Writing 160 

5.6 Summary of Conventions 162 



6 Basic Widget Methods 163 

6.1 The X Graphics Model Inside Widgets 166 

6.2 The initialize Method 166 

6.2.1 Creating GCs 168 

6.3 The expose Method 170 

6.4 The set_values Method 174 

6.5 The resize Method 177 

6.6 The query_geometry Method 180 

6.7 The destroy Method 183 

6.8 Actions in the Widget Framework 184 



7 Events, TVanslations, and Accelerators 187 

7.1 Translation Table Syntax 190 

7.1.1 The Directive .. 191 



vii 



7.1.2 Selecting the Events to Translate 191 

7.1.3 Details in Keyboard Events 194 

7.1.4 Details in Other Event Types 195 

7.1.5 Modifiers 196 

7.1.5.1 Physical Keys Used as Modifiers 197 

7.1.5.2 Default Interpretation of the Modifier List 198 

7.1.5.3 Prohibiting a Modifier 199 

7.1.5.4 Requiring an Exact Match 200 

7.1.5.5 Paying Attention to the Case of Keysyms 200 

7.1.6 Event Sequences 201 

7.1.6.1 Special Considerations Involving Motion Events 202 

7.1.6.2 Modifiers and Event Sequences 202 

7.1.6.3 Using Modifiers to Specify Button Event Sequences 202 

7.1.6.4 Key Event Sequences 203 

7.1.7 Interactions Between Translations 203 

7.1.7.1 Order of Translations 203 

7.1.7.2 Event Sequences Sharing Initial Events 204 

7.1.7.3 Event Sequences Sharing Noninitial Events 204 

7.2 Accelerators 205 

7.2.1 Event Propagation 207 

7.2.2 Installing Accelerators in Multiple Widgets 209 

7.2.3 Defining the Accelerator Table in the Code 210 

7.2.4 The display_accelerators Method 211 



8 More Input Techniques 213 

8.1 Event Handlers 216 

8.1.1 Adding Event Handlers 218 

8.1.2 Adding Nonmaskable Event Handlers 219 

8.1.3 Removing Event Handlers 220 

8.1.4 Adding Raw Event Handlers 220 

8.2 Writing Routines That Use Specific Event Data 221 

8.2.1 Event Types and Structure Names 222 

8.3 File, Pipe, and Socket Input 224 

8.3.1 Getting File Input 224 

8.3.2 Getting Pipe Input 226 

8.4 Timeouts 227 

8.4.1 Visibility Interest 230 

8.5 Work Procedures 231 

8.6 Low-level Management of the Event Queue 233 

8.6.1 XtPending and XtPeekEvent 234 

8.6.2 Event Filters 234 

8.6.3 Input Sensitivity 235 



VIII 



9 Resource Management and Type Conversion 237 

9.1 Review of Resource Fundamentals 239 

9.2 How the Resource Database Works 243 

9.2.1 Form of Resource Specifications 243 

9.2.2 Merging of Resource Files 245 

9.2.3 Resource Matching Algorithm 246 

9.2.4 Resource Precedence Rules 249 

9.3 Type Conversion 251 

9.3.1 Conversions from XtRString 251 

9.3.2 Other Built-in Type Conversions 254 

9.3.3 Special Resource Defaults That Do Not Use Conversion 255 

9.3.4 Registering Type Converters 257 

9.3.4.1 Passing Arguments to a Type Converter 259 

9.3.4.2 Type Converter Caching 260 

9.3.5 Explicitly Invoking a Converter 261 

9.3.6 Writing a Type Converter 262 

9.3.6.1 Defining the Default Value 264 

9.4 Subparts and Subresources 264 

9.4.1 The Hook Methods 265 

9.4.2 Managing Subresources 266 



10 Interclient Communications 267 

10.1 Window Manager Interactions 270 

10.1.1 Shell Subclasses 270 

10.1.2 Setting Shell Resources 271 

10.1.3 Screen Space 273 

10.1.4 Input Model 274 

10.1.5 Colormaps 276 

10.1.6 Icons 277 

10.1.7 Window Manager Decorations 279 

10.2 Selections: Widget-To- Widget Communication 280 

10.2.1 How Selection Works 281 

10.2.2 Highlighting the Selected Data (Owner) 284 

10.2.3 Making the Selection with XtOwnSelection (Owner) 288 

10.2.4 Requesting the Selection (Requestor) 289 

10.2.4.1 Possible Target Type Atoms 290 

10.2.4.2 The Paste Action from BitmapEdit 292 

10.2.5 Converting the Selection (Owner) 293 

10.2.6 Finally Pasting the Selection (Requestor) 295 

10.2.7 If the Selection is Lost (Owner) 297 

10.2.8 When the Selection Transfer is Complete (Owner) 297 

10.2.9 ICCCM Compliance 298 

10.2.9.1 Xmu Atom Caching 299 



10.2.9.2 Converting the Standard Selections 300 

10.2.9.3 The Clipboard Selection 301 

10.2.10 Miscellaneous Selection Routines 302 



11 Geometry Management 303 

11.1 How Composite Management Works 306 

11.1.1 Initial Geometry Negotiation 308 

11.1.2 User Resizes the Application 311 

11.1.3 Widget Desires a Size Change 311 

11.1.4 Application Resizes a Widget 312 

11.2 Writing a Composite Widget 312 

11.2.1 Basic Core Methods in Composite Widgets 315 

11.2.2 Laying Out Child Widgets 317 

11.2.3 The change_managed Method 319 

11.2.4 XtQueryGeometry and the query _geometry Method 320 

11.2.5 XtMakeGeometryRequest and the geometry_manager Method 320 

11.2.6 The set_values_almost Method 322 

11.2.7 The insert_child and delete_child Methods 323 

11.3 How Constraint Management Works 325 

11.4 Writing a Constraint Widget 325 

11.4.1 The Core Resource List 325 

11.4.2 The Constraint Resource List 326 

11.4.3 Class Structure Initialization 327 

11.4.4 The Constraint initialize Method 329 

11.4.5 The class_part_init Method 331 

11.4.6 The geometry_manager Method 332 

1 1.4.7 The resize Method 336 

11.4.8 The Core and Constraint set_values Methods 338 

11.4.9 The change_managed Method 338 

11.4.10 The query_geometry Method 339 

11.4.11 Delaying Geometry Recalculation 340 

1 1.5 Compound Widgets 340 

1 1.6 Stacking Order 341 



12 Menus, Gadgets, and Cascaded Pop Ups 343 

12.1 Menu Styles and Implementation 347 

12.1.1 How Menus are Popped Up 348 

12.1.2 Menu Panes 349 

12.2 Several Ways to Create and Use Menus 351 

12.2.1 A Spring-Loaded Menu: Pointer Grabbing 351 

12.2.2 A Drop-Down Menu 359 

12.2.3 Cascaded Menus 362 

12.2.4 Using the R4 SimpleMenu Widget 367 

12.3 About Dialog Boxes 371 



12.4 Gadgets 372 

12.4.1 Inside a Gadget 375 

12.4.2 Private Header File 376 

12.4.3 The Gadget Source File 377 

12.4.4 The Public Header File 378 

12.4.5 The Gadget Parent 378 



13 Miscellaneous Toolkit Programming Techniques 383 

13.1 Errors and Warnings 385 

13.2 Macros For Getting Widget Information 388 

13.3 The Keyboard Focus and accept_focus Method 389 

13.4 Keyboard Interpretation 391 

13.5 Memory Allocation 392 

13.6 Application Contexts 393 

13.6.1 Multiple Application Contexts 394 

13.6.2 Rewriting XtMainLoop for Multiple Application Contexts 394 

13.7 Multiple Top-level Shells 395 

13.8 Connecting to Multiple Servers 396 



A OPEN LOOK and Motif 397 

A.I The AT&T OPEN LOOK Widgets 403 

A.I.I Application Controls 404 

A.I. 1.1 Command Buttons 404 

A.I. 1.2 Exclusive and Nonexclusive Settings 406 

A.l.1.3 Analog Controls 408 

A. 1.2 Composite Widgets 408 

A.l.2.1 Menus and Control Areas 408 

A. 1.2.2 General Purpose Composite Widgets 409 

A.l.2.3 Scrollbars and Scrollable Windows 409 

A.1.3 Pop Ups 411 

A.1.4 Text Widgets 414 

A.I. 5 Drawing Areas 414 

A.2 The OSF/Motif Widgets 414 

A.2.1 Application Controls 417 

A.2.1.1 Command Buttons 417 

A.2.1.2 Analog Controls 418 

A.2.2 Composite Widgets 418 

A.2.2.1 Menus and Control Areas 418 

A.2.2.2 General Purpose Composite Widgets 421 

A.2.2.3 Scrollable Windows 422 

A.2.3 PopUps 423 

A.2.4 Text Widgets 424 

A.2.5 Drawing Areas 424 



XI 



B The Varargs Interfaces 425 

B.I TheR4 Varargs Interface 427 

B.I.I XtVaTypedArg and XtVaNestedList 428 

B.2 WidgetWrap 429 



C Specifying Fonts and Colors 431 

C.I Color Specification 433 

C.I.I Color Names 433 

C.1.2 Hexadecimal Color Specification 434 

C.l.2.1 The RGB Color Model 435 

C.I. 2.2 How Many Colors are Available? 436 

C.2 Font Specification 438 

C.2.1 Font Naming Conventions 439 

C.2.2 Font Name Wildcarding 441 

C.2.3 Font Name Aliasing 442 

C.2.4 Making the Server Aware of Aliases 443 

C.2.5 The fonts.dir Files 444 

C.3 Window Geometry 445 



D Naming Conventions 447 



E Converting Widgets from Xll Release 2 to Xll Release 3 451 

E.I New Core Fields 454 

E.1.1 The Display Accelerator Method 454 

E.I. 2 The Extension Pointer 454 

E.2 Obsolete Composite Fields 454 

E.3 Auditing Data Types 455 

E.4 Name Change to Misc.h Header File 455 

E.5 Interface Change to accept_focus Method 456 

E.6 Data Change to set_values Method 456 

E.7 New Geometry Request Mode 456 

E.8 Translation Table Syntax 457 

E.9 Resource Name and Class Qualifiers 457 

E.10 Bug Fix to XtGet Values 458 

E.ll Changes to Shell Defaults 458 

E.12 XtAddlnput and XtAddTimeout 458 



XII 



F The xbitmap Application 459 

F.I The BitmapEdit Widget 461 

F.2 The BitmapEdiP.h Private Header File 473 

F.3 The BitmapEdiLh Public Header File 475 

F.4 xbitmapS 476 



G Sources of Additional Information 483 

G.I Getting the X Software 485 

G.I.I Bug Fixes 486 

G.I. 1.1 Notes 488 

G.I. 1.2 Fairness 488 

G.2 Netnews 489 

G.3 Training and Consulting 489 

G.3.1 Phone Support 490 

G.4 The X Consortium 490 

G.5 Finding Out for Yourself 491 



Glossary 493 



Index ..519 



XIII 



Figures 



Page 



1-1 An X application, and an application on a traditional text terminal 4 

1-2 A three-button mouse directing the pointer to select a menu item 4 

1-3 Screen layout of a typical user s X Window System 5 

1-4 Applications can run on any system across the network 7 

1-5 The software architecture of Xt Intrinsics-based applications 9 

2-1 A widget-based application 16 

2-2 Inheritance among the Athena widgets 19 

2-3 An Athena VPaned widget (paned in R4) 20 

2-4 An Athena Dialog widget 21 

2-5 A Viewport widget 21 

2-6 Several Label widgets configured using resources 23 

2-7 Widgets operate independently of the application 24 

2-8 XtSet Values lets the application set how a widget will operate itself 25 

2-9 Application registers a function with Xt during startup phase 26 

2-10 Xt calls the function during the event-loop phase in response to an occurrence 27 

2-11 xhello: appearance on screen 31 

2-12 The appearance of xgoodbye when the pointer is in the window 40 

2-13 xfarewell run with new resource settings 56 

3-1 xboxl: appearance on the screen 64 

3-2 Two configurations of xboxl 65 

3-3 Results upon resize of Scroll widgets inside a Box widget 67 

3-4 The xmh application and its instance hierarchy 68 

3-5 Effect of the Form XtNfromHoriz resource 70 

3-6 xbox3: popping up a Dialog widget 71 

3-7 The widget instance and X window hierarchies are different only for pop ups 76 

4-1 xbitmapl: how it looks on the screen 104 

4-2 xbitmap2: scrollbars added 108 

4-3 The instance hierarchy of xbitmap2 110 

4-4 xbitmap3: true-scale normal and reverse bitmaps added 117 

4-5 Application draws into Pixmap and copies it to widget window 118 

5-1 The class hierarchy of the BitmapEdit widget (with other classes shown dotted) 137 

5-2 Order of code in widget .c file 142 

6-1 compress_exposures: 2 rectangles if FALSE; bounding box and a region if TRUE 173 

7-1 xboxl: two Command widgets in a Box 205 

7-2 Key event propagation in xbox 208 

8-1 xtetris in play 228 

9-1 The quit widget in a sample widget hierarchy 247 

9-2 Steps in matching resource entries for one resource of widget being created 252 

10-1 An icon with and without an icon pixmap 278 

10-2 The process of selection transfer 283 

11-1 Role of border width in widget geometry 307 



XIV 



11-2 Initial geometry negotiation, assuming sufficient shell space 309 

11-3 Initial geometry negotiation, if resizing is necessary 310 

11-4 A widget requesting a size change 313 

11-5 A ScrollBox widget at two different sizes 315 

11-6 Geometry negotiation by the set_values_almost method 324 

12-1 Command widgets in a button box, and the same commands as a menu 346 

12-2 Menus from the OPEN LOOK and Motif widget sets 350 

12-3 xmenul: application with spring-loaded pop-up menu 354 

12-4 xmenu2: a drop-down menu 359 

12-5 xmenu5: cascaded spring-loaded menus 363 

12-6 xmenu?: a menu using the Athena SimpleMenu widget 368 

12-7 Class hierarchy derivation of Core 374 

13-1 Using XtCalLAcceptFocus to set the keyboard focus to a child of a dialog widget ... 390 

A- 1 An OPEN LOOK application 403 

A-2 Class inheritance hierarchy of the AT&T OPEN LOOK widgets 405 

A-3 An OPEN LOOK ControlArea with OblongButton and ButtonStack widgets 406 

A-4 OPEN LOOK RectButtons controlled by Exclusives and Nonexclusives widgets 407 

A-5 An OPEN LOOK CheckBox widget 408 

A-6 An OPEN LOOK Slider widget 408 

A-7 An OPEN LOOK Scrollbar 410 

A-8 An OPEN LOOK ScrollingList widget 411 

A-9 An OPEN LOOK Notice 412 

A-10 An OPEN LOOK PopupWindow 413 

A-ll An OPEN LOOK Help window 413 

A-12 Look and feel of a Motif application 415 

A- 13 Class inheritance hierarchy of the Motif widget set 416 

A- 14 Motif DrawnButton and PushButton widgets 417 

A-15 A Motif RowColumn widget configured as a Menu Bar 419 

A-16 A Motif RowColumn widget configured with four Radio Boxes 419 

A- 17 A Motif RowColumn widget configured as a drop-down menu 420 

A-18 A Motif Form widget and children 421 

A-19 A Motif ScrollBar 422 

A-20 A Motif SelectionBox 423 

C-l Multiple planes used to index a colormap 437 

C-2 A Release 3 font name .. ... 439 






xv 



Examples 



Page 



2-2 XHello: the application-defaults file 37 

2-3 xgoodbye.c: complete code 40 

2-4 XGoodbye: the application-defaults file 42 

2-5 xfarewell.c: complete code 43 

2-6 An XtActionProc with widget and event arguments 46 

2-7 XFarewell: the application-defaults file 47 

2-8 Code Fragment: specifying translations in the program 49 

2-9 Code fragment to set a widget resource 50 

2-10 Code fragment to set multiple resources of a widget 51 

2-11 Code fragment to get a widget resource 51 

2-12 Alternate resource settings for xfarewell 54 

3-1 xboxl.c: complete code 62 

3-2 XBoxl: application-defaults file 64 

3-3 XBox2: application-defaults file 69 

3-4 xbox3: application-defaults file 71 

3-5 Creating a pop-up dialog box 72 

3-6 Passing a single value to a callback function 77 

3-7 Passing a pointer to a structure to a callback function 78 

3-8 Initializing a callback list 80 

3-9 xbitmap: getting application resources 81 

3-10 The resource list for xbitmap 82 

3-11 Calling XtGetApplicationResources and checking values 85 

3-12 xbitmap: specifying command-line options 88 

3-13 An argument list 92 

3-14 Using an argument list in widget creation 92 

3-15 Setting the argument list with XtSetArg 93 

3-16 Incorrectly setting the argument list with XtSetArg 94 

3-17 The WidgetWrap interface to creating a widget 95 

3-18 The R4 varargs interface to creating a widget 96 

3-19 Using R3Initialize and explicit application contexts 98 

3-20 R3Initialize: substitute for Xtlnitialize that returns an explicit application context ... 98 

4-1 xbitmapl: complete code 105 

4-2 XBitmapl: application-defaults file 107 

4-3 xbitmap2: adding scrollbars 110 

4-4 xbitmap2: resize_thumbs routine 113 

4-5 xbitmap2: scrolling callback functions 114 

4-6 xbitmap3: implementing small pixmaps by drawing into Core widgets 118 

4-7 xbitmap3: the cell_toggled routine 121 

4-8 xbitmap3: the redraw_small_picture routine 121 

4-9 xbitmap3: writing a bitmap file 122 

4-10 xbitmap4: implementing the bitmap editor from the application 124 



xvi 



5-1 BitmapEditP.h: the class part and class record 138 

5-2 BitmapEditP.h: the instance part and instance record 139 

5-3 BitmapEditP.h: declaring the external class record 140 

5-4 BitmapEdiLc: include files 141 

5-5 BitmapEdit s resource list 143 

5-6 Setting the resource list into the class structure 145 

5-7 The default translation table and the actions table 146 

5-8 Translations in the Core Class Record 146 

5-9 BitmapEditc: function type declarations 147 

5-10 BitmapEditc: initialization of Core class record 148 

5-11 BitmapEdiLc: declaring the class record pointer 155 

5-12 BitmapEditc: inheriting a self-contained method 155 

5-13 Inheriting by invoking the superclass method from a widget method 157 

5-14 BitmapEdit.h: incidental declarations 158 

6-1 The initialize method 167 

6-2 Creating GCs from the initialize method 169 

6-3 The expose method 171 

6-4 The set_values method 174 

6-5 BitmapEdit: the resize method 177 

6-6 BitmapEdit: modification to set_values method to support changing cell size 180 

6-7 The XtWidgetGeometry structure 180 

6-8 BitmapEdit: the query_geometry method 182 

6-9 The destroy method 183 

6-10 BitmapEdit: action routines 184 

7-1 Installing accelerators in an application 206 

7-2 Specifying the XtNaccelerators resource from the application-defaults file 206 

7-3 Conflicting translations and accelerators 209 

7-4 Installing accelerators from both command widgets 209 

7-5 Accelerators resource settings for two widgets 210 

8-1 Registering an event handler, and the handler function itself 218 

8-2 Adding a nonmaskable event handler 219 

8-3 Casting the event structure by declaring action routine arguments 221 

8-4 Handling multiple event types in an action routine 222 

8-5 Getting file input with XtAddlnput 225 

8-6 Reading stdin from an Xt application 227 

8-7 xtetris: registering a timeout, and the timeout function 228 

8-8 xtetris: calling XtRemoveTimeOut 229 

8-9 Registering an Xt Work Procedure 232 

8-10 A work procedure to create a pop-up widget 232 

8-1 1 Skeleton of a custom main loop 233 

9-1 Two resources defined by the Athena Label widget 240 

9-2 A sample merged resource database 247 

9-3 Sample resource database with eliminated entries and components 248 

9-4 Resource database after final elimination of entries and components 248 

9-5 Resource database finalists in original form 250 

9-6 A resource definition converting an int to a pixmap 254 

9-7 A resource definition using XtRImmediate 255 

9-8 A resource definition using XtRCallProc 256 



XVII 



9-9 An example of an XtResourceDefaultProc 256 

9-10 Registering a type converter 258 

9-11 Adding a converter with arguments 259 

9-12 Manually invoking a type converter 261 

9-13 The XtRString to XtREdgeType type converter 262 

9-14 Testing for a special-case default value 264 

9-15 Simplified get_values_hook method of the AsciiSrc subpart of the Text widget 265 

10-1 Setting the XtNinput resource of a Shell widget 276 

10-2 Creating an icon pixmap, and setting XtNiconPixmap 278 

10-3 BitmapEdit: actions that highlight selection 284 

10-4 BitmapEdit: getting the atom for a widget-specific target type 291 

10-5 BitmapEdit: action to paste a selection 292 

10-6 BitmapEdit: converting the selection value 293 

10-7 BitmapEdit pasting selection in requestor_callback function 295 

10-8 BitmapEdit the lose_ownership_proc 297 

10-9 BitmapEdit: initializing Xmu s atom caching mechanism in the initialize method . 300 

10-10 BitmapEdit: converting standard targets in the convert_proc 300 

11-1 ScrollBox: the set_values method 316 

11-2 ScrollBox: the resize method 316 

11-3 ScrollBox: the query_geometry method 316 

11-4 ScrollBox: private routine to lay out child widgets 318 

11-5 Form: the Core resource list 325 

11-6 Form: constraint resource list 326 

11-7 Form: constraint data structure 327 

11-8 Form: class structure initialization 328 

11-9 Form: the Constraint initialize method 330 

11-10 The class_part_init method of Form 331 

11-11 Form: the geometry_manager method 332 

11-12 Form: private functions: RefigureLocations and the layout method 333 

11-13 Form: the LayoutChild private function 335 

11-14 Form: the resize method 336 

11-15 Form: the change_managed method 338 

11-16 Form: the query_geometry method 339 

1 1-17 Form: the public function for delaying calls to change_managed 340 

12-1 xmenul: complete code 354 

12-2 XMenul: the application-defaults file 358 

12-3 xmenu2: code to place drop-down menu 360 

12-4 XMenu2: translation portion of the application-defaults file 361 

12-5 xmenuS: actions that place, pop-up, and pop-down main menus and submenus 363 

12-6 XMenuS: translation portion of application-defaults file 366 

12-7 xmenu7: using the SimpleMenu widget and its children 368 

12-8 XMenu7: application-defaults file 370 

12-9 Sme gadget: class part and complete class structure declaration 376 

12-10 Sme gadget: instance part and complete instance structure declaration 377 

12-11 SimpleMenu: expose method calling gadget children s expose methods 379 

12-12 SimpleMenu: resize method 380 

12-13 SimpleMenu: the Notify action routine 381 

13-1 How to invoke XtErrorMsg (from AsciiSrc.c) 386 



XVIII 



13-2 Getting widget IDs with XtNameToWidget 389 

C-l Sample fonts.alias file 443 

C-2 fonts.dir file in /usr/lib/Xl l/fonts/100dpi 444 

F-l BitmapEdit complete widget code 461 

F-2 BitmapEdiP.h: complete private header file 473 

F-3 BitmapEdith: complete public header file 475 

F-4 xbitmapS: complete application code 476 



XIX 



Tables 



Page 



2-1. Core Resources 52 

2-2. Label Resources 54 

3-1. Resource type strings 84 

3-2. Standard Command-line Parameters 87 

3-3. XrmOptionKind: Command-line Option Style Constants 90 

5-1. Resource List Constant Conventions 145 

5-2. Inheritance Style of Various Methods 152 

5-3. Summary of Xt Structure Name Conventions 162 

6-1. XtWidgetGeometry request_mode Symbols 181 

6-2. XtWidgetGeometry stack_mode Symbols 181 

7-1. Event Type Abbreviations in Translation Tables 192 

7-2. Notify Mode Values for Enter, Leave, and Focus Events 196 

7-3. Modifiers Used in Translation Tables 196 

7-4. Modifier Symbols 199 

8-1. Event Masks and Event Types 216 

8-2. Event Types and Event Structures 223 

8-3. Other Input Source Masks 224 

9-1. Resource Type Strings 241 

9-2. Built-in Type Converters from XtRString 253 

9-3. Other Built-in Converters 254 

9-4. Xmu Converters 257 

10-1. Shell Resources 271 

10-2. Target Types Suggested inlCCCM 298 

11-1. Return Codes of geometry_manager Method 321 

13-1. Xt Error and Warning Message Utilities 387 

13-2. Xt Routines That Use Default and Explicit Application Contexts 393 

A-l. Comparison of Athena, OPEN LOOK, and Motif Widgets 400 

B-l. Varargs Calls and XtArgVal Equivalents 427 

C-l. Geometry Specification: x and y Offsets 445 



xx 



Preface 



By convention, a preface introduces the book itself, while the introduction 
starts in on the subject matter. You should read through the preface to get an 
idea of how the book is organized, the conventions it follows, and so on. 



In The Preface: 

Summary of Contents xxiii 

Assumptions xxiv 

Related Documents xxv 

How to Use This Manual xxv 

Font Conventions Used in This Manual xxviii 

Requests for Comments xxix 

Bulk Sales Information xxix 

Obtaining the X Window System Software xxix 

Example Programs xxx 

Acknowledgments xxxi 



Preface 



The X Toolkit is the collective name for two subroutine libraries designed to simplify the 
development of X Window System applications the Xt Intrinsics and the Xaw widget set 
A widget is a pre-built user-interface component The Xt library consists of routines for 
building and using widgets. Xt is written using Xlib, the lowest level C-language interface to 
the X Window System. Both the Xt Intrinsics and Xlib are required by the X standard (esta 
blished by the X Consortium) on any system that allows programming of X applications in C. 

The Xaw widget library is based on Xt and provides a small number of widgets that can be 
used to write simple application programs. Xaw was developed by MIT s Project Athena, 
and the acronym Xaw stands for "Athena Widgets." Xaw was designed as a simple demon 
stration and test of the Intrinsics not as a complete set of widgets for writing demanding 
applications. There are numerous other widget sets provided by system vendors to imple 
ment their particular user-interface styles. The two most widely-used are OSF s Motif, and 
AT&T s OPEN LOOK widget set 

This book describes how to build applications using the Xt Intrinsics. It provides a complete 
tutorial with programming examples. 

The book uses the Athena widgets to demonstrate how to use existing widgets, but it is 
equally applicable to and provides a good introduction to programming with any other 
widget set based on Xt. It is based on Release 3 of the Intrinsics and the Athena widgets, but 
with the permission of the X Consortium staff, includes some advance information on 
Release 4, based on the Beta release to Consortium members. 



Summary of Contents 

The discussion of the X Toolkit is divided into three volumes, Volumes Four, Five, and Six of 
the X Window System Series available from O Reilly & Associates, Inc. 

This is the first of the three, Volume Four, X Toolkit Intrinsics Programming Manual. It pro 
vides an explanation of the X Toolkit, including tutorial material and numerous programming 
examples. Arranged by task or topic, each chapter brings together a group of Xt functions, 
describes the conceptual foundation on which they are based, and illustrates how they are 
most often used in writing applications. This volume is structured to be useful as a tutorial 
and also as a task-oriented reference. 



Preface xxiii 



Volume Five, the X Toolkit Intrinsics Reference Manual, includes reference pages for each of 
the Xt functions, as well as for the widget classes defined by Xt, organized alphabetically for 
ease of reference; a permuted index; and numerous appendices and quick reference aids. 

Volume Six, the X Toolkit Widget Reference Manual, includes reference pages for each of the 
most widely used widget sets: the Athena widgets, developed by MIT as a demonstration of 
Xt, the OPEN LOOK widgets from AT&T, and the Open Software Foundation s Motif widget 
set This volume will be available in mid 1990. 

The three volumes are designed to be used together. To get the most out of the examples in 
Volume Four, you will need the exact calling sequences of each function from Volume Five. 
To understand fully how to use each of the functions described in Volume Five, all but the 
most experienced Toolkit "hacker" will need the explanation and examples in Volume Four. 
Volume Six provides the details on the actual widgets you can use to build your applications. 
Instead of Volume Six, you can use the widget documentation provided by your system ven 
dor. Until Volume Six is available, the Athena Widget reference pages will be duplicated in 
Volume Five. 

All three volumes include material from the original Toolkit documentation provided by 
MIT, though in Volume Four this is mostly limited to the appendices. We have done our best 
to incorporate all the useful information from the MIT documentation, to correct references 
we found to be in error, to reorganize and present it in a more useful form, and to supplement 
it with conceptual material, tutorials, reference aids, and examples. In other words, this man 
ual is not only a replacement, but is a superset of the MIT documentation. 

Those of you familiar with the MIT documentation will recognize that each reference page in 
Volume Five includes the detailed description of the routine found in X Toolkit Intrinsics C 
Language Interface, plus in many cases additional text that clarifies ambiguities and 
describes the context in which the routine would be used. We have also added cross- 
references to related reference pages and to where additional information can be found in 
Volume Four. 



Assumptions 

This book makes no assumptions about the reader s knowledge of object-oriented program 
ming or the X Window System. Readers should be proficient in the C programming lan 
guage, although examples are provided for infrequently used features of the language that are 
necessary or useful when programming with the X Toolkit. In addition, general familiarity 
with the principles of raster graphics will be helpful. 

However, the X Toolkit is not self-sufficient. Even though the Toolkit is intended to hide the 
low-level X interface provided by Xlib, there are times in writing applications or widgets 
when Xlib functions will be necessary because no Xt feature exists to do the same thing. 
This book describes the most common occasions for using Xlib, but does not provide a refer 
ence to the particular functions involved. Additional documentation on Xlib, such as that 
provided by Volume One, Xlib Programming Manual, and Volume Two, Xlib Reference 
Manual, will be indispensable. 



xxiv X Toolkit Intrinsics Programming Manual 



Related Documents 

Five other books on the X Window System are available from O Reilly & Associates, Inc.: 
Volume Zero X Protocol Reference Manual 
Volume One Xlib Programming Manual 
Volume Two Xlib Reference Manual 
Volume Three X Window System User s Guide 
Volume Seven XView Programming Manual 

The following documents are included on the XI 1 source tape: 

X Toolkit Intrinsics C Language Interface, by Joel McCormack, Paul Asente, 

and Ralph Swick 
X Toolkit Athena Widgets C Language Interface, by Ralph Swick and 

Terry Weissman 
Xlib C Language X Interface, by Jim Gettys, Ron Newman, and Robert Scheifler 

The following Nutshell Handbooks published by O Reilly and Associates, Inc., are useful 
when programming in C: 

Checking C Programs with lint, by Ian Darwin 
Managing Projects with make, by Steve Talbott 
Using C on the UNIX System, by Dave Curry 

The following is the classic introduction to C programming: 

The C Programming Language, by B. W. Kernighan and D. M. Ritchie 

How to Use This Manual 



Volume Four treats both application programming with widgets and widget programming 
(the design and coding of new widgets). 

The first four chapters treat widgets largely as "black boxes," which is appropriate, consider 
ing the object-oriented philosophy of the Toolkit These chapters also provide an overview 
of many elements of the X Toolkit, and so are appropriate for all readers. 

Chapter 1, Introduction to the X Window System, provides a discussion of the context in 
which X programs operate. Programmers who are comfortable programming 
with Xlib can skip Chapter 1. 

Chapter 2, Introduction to the X Toolkit, describes the conceptual foundations underlying 
Toolkit programming, and shows how to write simple programs that use 
widgets from existing widget sets. It introduces such fundamental Toolkit 
programming concepts as resources, the Translation Manager, callbacks, and 
actions. 



Preface 



Chapter 3, More Widget Programming Techniques, describes how to use some of the 
more complex widgets found in applications, including composite widgets, 
constraint widgets, and pop ups. It also describes how to define application 
resources and command-line options, and how to hardcode the value of widget 
resources when you create a widget Finally, it describes how to create multi 
ple top-level windows, and how to use application contexts to create applica 
tions that run on more than one processor. 

Chapter 4, An Example Application, describes a complete application, in several itera 
tions. First, it shows a simple version of the program, a bitmap editor, as it 
would be written assuming the existence of a BitmapEdit widget (which is 
actually developed in Chapter 5). Then, two refined versions are developed, 
each demonstrating additional Toolkit programming techniques. Finally, the 
same application is shown as it would be written if the bitmap editor were 
implemented in an application window rather than with the BitmapEdit 
widget 

The next two chapters describe widget internals, and the process of creating new widgets. 
While this information is not essential for application programmers, it will help even some 
one uninterested in writing new widgets to understand the sometimes peculiar style of 
Toolkit programming. 

Chapter 5, Inside a Widget, describes the code inside a widget Much of this code is 
common to all widgets. You can think of it as a framework that Xt uses to 
implement a widget s features. After reading this chapter, you should under 
stand the procedure for creating your own widget around this framework. 

Chapter 6, Basic Widget Methods, describes a widget s initialize, expose, 
set_values, destroy, resize and query_geometry methods. (A 
widget s methods are internal routines called automatically by Xt to give the 
widget a degree of independence from the application.) The chapter explains 
when Xt calls each method, and describes in detail what should be in each of 
these methods. Among other things, these methods prepare for and do the 
drawing of graphics that appear in a widget This chapter describes what the 
Toolkit adds to the graphics model provided by Xlib, but does not describe in 
detail how to draw using Xlib; this topic is described in Chapters 5, 6, and 7 of 
Volume One, Xlib Programming Manual. 

Later chapters treat various topics of interest to either application or widget programmers, or 
both. Some of these topics have been introduced in the earlier chapters, and are explored 
more completely in the later ones. 

Chapter 7, Events, Translations, and Accelerators, describes the complete syntax of 
translation tables, which allow the user to configure the mapping of event 
sequences into widget actions. It also describes accelerators, a mechanism for 
mapping events in one widget to actions in another. 

Chapter 8, More Input Techniques, describes how to handle events with event handlers, 
and how to use information from the event structure inside an event handler or 
action routine. It also describes how to get file, pipe, or socket input, how to 
use timeouts to call a function after a delay or at particular intervals, and how 



xxvi X Toolkit Intrinsics Programming Manual 



to use work procedures to do background processing. Finally, it discusses 
some low-level features of Xt for directly interacting with the event queue. 

Chapter 9, Resource Management and Type Conversion, is a more thorough discussion of 
how resources work and how they should be used. This chapter describes in 
detail the resource file format and the rules that govern the precedence of 
resource settings. It also describes how to add your own type converter so that 
you can set application- or widget-specific data through resources. Finally, it 
describes subresources and how to use them. 

Chapter 10, Inter client Communications, discusses communication through the X server 
between application and the window manager, and between two applications. 
The application-window manager communication is performed by code in the 
Shell widget. The application sets shell resources to control this communica 
tion with the window manager. Application-application communication is 
usually done with a process called selections. This form of communication is 
already implemented in most widgets that display text, but you may want to 
implement it in your own custom widgets. Selections can also pass other 
kinds of data such as graphics. 

Chapter 11, Geometry Management, discusses how composite and constraint widgets man 
age the layout of widgets, and how to write your own simple composite and 
constraint widgets. 

Chapter 12, Menus, Gadgets, and Cascaded Pop Ups, describes how menus work, and sev 
eral ways to create menu widgets. One of these ways involves the use of win- 
dowless widgets, or gadgets. This chapter also describes how to use more 
advanced features of the Xt pop-up mechanism, including modal cascades, to 
implement cascading pop-up menus. 

Chapter 13, Miscellaneous Toolkit Programming Techniques, describes various Xt func 
tions that have not been treated elsewhere in the book. These include func 
tions for error and warning handling, case conversion, and so on. 

Appendix A, OPEN WOK and Motif, provides an overview of the widgets available in 
AT&T s OPEN LOOK widget set and OSF s Motif. These widgets are con 
trasted with those in the Athena widget set. 

Appendix B, The Varargs Interfaces, describes Dan Heller s WidgetWrap library available 
for Release 3, and Xt s own varargs interface introduced in Release 4. These 
libraries clean up Xt s application programming interface. 

Appendix C, Specifying Fonts and Colors, gives information on the values that can be used 
when specifying fonts and colors as resources. 

Appendix D, Naming Conventions, describes a suggested set of conventions for naming 
widgets and elements with widget code. 

Appendix E, Converting Widgets from XI 1 Release 2 to XI 1 Release 3, describes the 
changes between Release 2 (which was the first release of the Toolkit) and 
Release 3. This manual describes Release 3, but notes any changes necessary 
to make the code work in other releases. 



Preface 



XXVII 



Appendix F, The xbitmap Application, shows the complete code for all versions of the xbit- 
map application and the BitmapEdit widget, which are described in Chapters 
4 and 5. 

Appendix G, Sources of Additional Information, lists where to get the X software, compa 
nies that offer training in X programming, and description of additional books 
on the subject that have been or will be published soon. 

Glossary This section gives you somewhere to turn should you run across an unfamiliar 
term. Some care has been taken to see that all terms are defined where they 
are first used in the text, but not everyone will read the manual in sequential 
order. 

Master Index provides a thorough, combined index to Volumes Four and Five, making it 
easy to look up all the appropriate references to a topic, in either volume. 

Volume Five consists of a permuted index, reference pages to each library function, and 
appendices that cover macros, structures, and defined symbols. 

Font Conventions Used in This Manual 



Italics are used for: 

UNIX pathnames, filenames, program names, user command names, and options for user 
commands 

New terms where they are defined 

Typewriter Font is used for: 

Anything that would be typed verbatim into code, such as examples of source code and 
text on the screen 

The contents of include files, such as structure types, structure members, symbols 
(defined constants and bit flags), and macros 

Xt, Xaw, and Xlib functions 

Names of subroutines in the example programs 

Italic Typewriter Fon t is used for: 

Arguments to functions, since they could be typed in code as shown but are arbitrary 

Helvetica Italics are used for: 

Titles of examples, figures, and tables 

Boldface is used for: 

Chapter and section headings 



xxviii X Toolkit Intrinsics Programming Manual 



Requests for Comments 

To help us provjde you with the best documentation possible, please write to tell us about any 
flaws you find in this manual or how you think it could be improved. 

Our U.S. mail address, e-mail address, and phone numbers are as follows: 

O Reilly & Associates, Inc. 
632 Petaluma Avenue 
Sebastopol, CA 95472 
800-338-6887, in CA 800-533-6887 
international +1 707-829-0515 

UUCP: uunet!ora!adrian Internet: adrian@ora.com 

Bulk Sales Information 



This manual is being resold as the official X Window System documentation by many work 
station manufacturers. For information on volume discounts for bulk purchase, call O Reilly 
and Associates, Inc., at 800-338-6887 (in California, 800-533-6887), or send e-mail to 
linda@ora.com. 

For companies requiring extensive customization of the book, source licensing terms are also 
available. 



Obtaining the X Window System Software 

The X Window system is copyrighted but freely distributed. The only restriction this places 
on its use is that the copyright notice identifying the author and the terms of use must accom 
pany all copies of the software or documentation. Thanks to this policy, the software is avail 
able for nominal cost from a variety of sources. See Appendix G, Sources of Additional 
Information, for a listing of these sources. 



Preface xxix 



Example Programs 

The example programs in this book are on the XI 1 Release 4 distribution in the contributed 
section. There are many ways of getting this distribution; most are described in Appendix G. 

The example programs are also available free from UUNET (that is, free except for UUNET s 
usual connect-time charges). If you have access to UUNET, you can retrieve the source code 
using uucp or ftp. For uucp, find a machine with direct access to UUNET, and type the fol 
lowing command: 

uucp uunet\ ! ~uucp/nutshell/Xt/xtprogs . tar . Z yowrhosN.~ /yourname/ 

The backslashes can be omitted if you use the bourne shell (sh) instead of csh. The file 
should appear some time later (up to a day or more) in the directory lusrlspoolluucppub- 
liclyourname. 

To usQftp,ftp to uunet.uu.net and use anonymous as your user name and guest as your pass 
word. Then type the following: 

cd /nutshell/Xt 

binary (you must specify binary transfer for compressed files) 

get xtprogs . shar . Z 

bye 

The file is a compressed shell archive. To restore the files once you have retrieved the 
archive, type: 

uncompress xtprogs. shar 
sh xtprogs. shar 

The example programs will also be available free by ftp from expo.lcs.mit.edu soon after 
Release 4 is released. However, the exact location and filename of the file or files containing 
the examples was not available at press time. The filename and directory will not be the 
same as those described for UUNET. 

The examples will be installed in subdirectories under the current directory, one for each 
chapter in the book. Imakefiles are included. (Imakefiles are used with imake, a program 
supplied with the XI 1 distribution that generates proper Makefiles on a wide variety of sys 
tems.) 

All the application-defaults files are in the main examples directory. The application- 
defaults files are not automatically installed in the system application-defaults directory 
(lusrlliblXlllapp-defaults on UNIX systems). (See Chapter 9, Resource Management and 
Type Conversion, for details.) If you have permission to write to that directory, you can copy 
them there yourself. Otherwise, you can set the XAPPLRESDIR environment variable to the 
complete path of the directory where you installed the examples. The value of XAPPLRES 
DIR must end with a / (slash). (Many of the examples will not function properly without the 
application-defaults files.) 



xxx X Toolkit Intrinsics Programming Manual 



Acknowledgments 

As mentioned above, this manual includes some material from the Xt Toolkit Intrinsics C 
Language Interface, by Joel McCormack, Paul Asente, and Ralph Swick. This is the docu 
ment that defines the X Consortium standard for Xt, known as the Xt specification. Overt 
borrowings from the Xt specification are rare in this volume. However, the Xt specification 
document and the sample code of Xt and the Athena widget set distributed with releases of X 
provides the intellectual basis for most of what appears here. 

We d like to thank Sony Microsystems for the loan of a Sony NEWS workstation running 
their implementation of the X Window System. The speed and power of the Sony work 
station, and the support of their staff, was a great help in developing these books. Additional 
development was done on a Sun-3 workstation running MIT s sample server, a Visual 640 X 
Display Station, and an NCD16 Network Display Station. 

We would also like to thank the reviewers of the Alpha draft of this book, even though we 
almost had to start over because of their comments. They were David Lewis of Integrated 
Computer Solutions (ICS), Wendy Eisner of Sunquest Information Systems, Dan Heller of 
Island Graphics, Inc., (now working with O Reilly and Associates), Miles O Neal of Systems 
and Software Solutions, Inc., and Chris Peterson of MIT Project Athena (now of the X Con 
sortium). Ian Darwin of SoftQuad and Bradley Ross of Cambridge Computer Associates 
reviewed the Beta draft. Extra thanks are due to Ralph Swick, Chris Peterson, and Robert 
Scheifler, who answered many questions during the development of this book. 

Of course, we alone take responsibility for any errors or omissions that remain. 

Special thanks go to Mark Langley, who wrote an early draft-of this book. He helped to edu 
cate us about the Toolkit, and his efforts to make the book a success did not go unnoticed. 

Of course, the authors would like to thank the entire staff of O Reilly and Associates, Inc., 
and Cambridge Computer Associates, Inc., especially Daniel Gilly, Donna Woonteiler, Sue 
Willing, Lenny Muellner, Linda Mui, Ruth Terry, Virginia Estabrook, and Edie Freedman, for 
their help and support in the development of this book. The illustrations (except where bor 
rowed from other books in the series) were done by Andrea Pluhar and Chris Reilley. Tim 
O Reilly and Kathyrn Ellis developed the master index, and Dale Dougherty revised the 
indexing program to permit multi-volume indexing. 

Perhaps most of all, we would like to thank our readers and customers for their patience, 
which we tested by promising that this book would be finished next month every month for 
the last eight months. These days, with word processors, it is easy to generate a book-length 
manuscript, but no easier than it ever was to carve that text into something worth reading. 
We have had that book-length manuscript for a year, but have not been satisfied until now 
that it presented the material in a clear, friendly, and authoritative manner. We hope that the 
extra time we have spent boiling down the facts about this very new and continuously 
advancing subject will prove worthwhile to you, the reader. 



Adrian Nye and Tim O Reilly 



Preface 



1 



Introduction to the X Window System 



This chapter introduces many of the most important concepts on which the X 
Window System is based, and describes the environment in which the X 
Toolkit operates. This chapter assumes that you are new to programming the 
X Window System. If you already have some experience programming the X 
Window System, you may wish to skim this Chapter for a brief review or even 
begin with Chapter 2. 



In This Chapter: 

The Server and Client 6 

The Software Hierarchy 8 

Event-driven Programming 10 

The Window Manager 11 

Extensions to X . ..12 



1 

Introduction to the X Window System 



The X Window System (or simply X)* is a hardware-independent windowing system for 
workstations. It was developed jointly by MIT and Digital Equipment Corporation, and has 
been adopted by the computer industry as a standard platform for graphics applications. 

X controls a "bit-mapped" display in which every pixel (dot on the screen) is individually 
controllable. This allows applications to draw pictures as well as text. Until recently, indi 
vidual control of screen pixels was widely available only on personal computers (PCs) and 
high-priced technical workstations. Most general-purpose machines were limited to output 
on text-only terminals. X brings a consistent world of graphic output to both PCs and more 
powerful machines. Figure 1-1 compares an X application to an application running on a tra 
ditional text terminal. 

Like other windowing systems, X divides the screen into multiple input and output areas 
called windows. Using a terminal emulator, windows can act as "virtual terminals," running 
ordinary text-based applications. However, as shown in Figure 1-1, windows can also run 
applications designed to take advantage of the graphic power of the bitmapped display. 

X takes user input from a pointer. The pointer is usually a mouse but could just as well be a 
track-ball or a tablet. The pointer allows the user to control a program without using the key 
board, by pointing at objects drawn on the screen such as menus and command buttons. This 
method of using programs is often easier to learn than traditional keyboard control, because it 
is more intuitive. Figure 1-2 shows an application with a typical three-button pointer being 
used to select a menu item. 

Of course, X also handles keyboard input. The pointer directs the keyboard focus from win 
dow to window. Only one window at a time can receive keyboard input. 

In X, as in many other window systems, each application need not (and usually does not) 
consist of only a single window. Any part of an application can have its own separate 
subwindow, which simplifies the management of input and output within the application 
code. Such child windows are visible only within the confines of their parent window. 

Windows are rectangular and oriented along the same axes as the edges of the display. Each 
window has its own coordinate system, with the origin in the upper-left corner of the window 
inside its border. The application or the user can change the dimensions of windows. Figure 



"The name "X Windows" is frowned upon by the developers of X. 



Introduction to the X Window System 




X Window System 




Text Terminal 



Figure 1-1. An X application, and an application on a traditional text terminal 





Figure 1-2. A three-button mouse directing the pointer to select a menu item 

1-3 shows a typical screen with several virtual terminals running. The screen also shows 
some applications, such as xmh, xclock, and xload, that run in their own windows. 

X supports both color and black-and-white displays. 



X Toolkit Intrinsics Programming Manual 



xterm windows 



xclock window 



iconified xterm window 



\ 



% rlogin host2 



Dear Mr. Hoffmann: 
.LP 

You called yesterday for 
information about X. 
The X Window System is 
network-based graphic 
window system that was 
developed jit JMJT in 1 984. C 

The X Window System is a 
network-based graphic window 
system that was developed at MIT 
in 1984. Several versions of X 
have been developed, the most 
recent of which is X Version 1 1 
(X11), first released in 1987. X1 1 



\ 






Figure 1-3. Screen layout of a typical user s X Window System 

Many of the above characteristics are also true of several other window systems. What is 
unusual about X is that it is based on a network protocol instead of on system-specific proce 
dure and system calls. This network protocol enables X to be ported to different computer 
architectures and operating systems; it also allows programs to run on one architecture while 
displaying on another. Because of its unique design, X can make a network of different com 
puters cooperate. For example, a computationally intensive application might run on a super 
computer, but take input from and display output on a workstation connected across a local 
area network. To the user, the application would simply appear to be running on the work 
station. 



Introduction to the X Window System 



1 .1 The Server and Client 

To allow programs to be run on one machine and display on another, X was designed as a net 
work protocol a predefined set of requests and replies between two processes, one of 
which is an application program called a client, and the other of which, the server, controls 
the display hardware, keyboard, and pointer. 

The user sits at the machine running the server. At first, this usage of the term server may 
seem a little odd, since file and print servers are normally remote machines. But the usage is 
consistent. The local display is accessible to other systems across the network, and for those 
systems the X server does act like other types of server. 

The X server acts as an intermediary between user programs and the resources of the local 
system such as the keyboard and screen. It contains all device-specific code, and insulates 
applications from differences between display hardware. The server performs the following 
tasks: 

Allows access to the display by multiple clients. The server may deny access from clients 
running on certain machines. 

Interprets network messages from clients and acts on them. These messages are known as 
requests. Some requests command the server to do two-dimensional drawing, move win 
dows, while others ask the server for information. Protocol requests are generated by cli 
ent calls to Xlib, either directly or through Xt and other function libraries. 

Passes user input to clients by sending network messages known as events, which repre 
sent key or button presses, pointer motion, and so forth. Events are generated asynchro- 
nously, and events from different devices may be intermingled. The server must pass the 
appropriate events to each client. 

Maintains complex data structures, including windows and fonts, so that the server can 
perform its tasks efficiently. Clients refer to these abstractions by ID numbers. Server- 
maintained abstractions reduce the amount of data that has to be maintained by each cli 
ent and the amount of data that has to be transferred over the network. 

In X, the term display is often used as a synonym for server, as is the combined term display 
server. However, the terms display and screen are not synonymous. A screen is the actual 
hardware on which the graphics are drawn. A server may control more than one screen. For 
example, a single server might control both a color screen and a monochrome screen, allow 
ing a user to debug an application on both types of screens without leaving seats. 

The user programs displaying on the screen(s) managed by a server are called its clients. 
There may be several clients connected to a single server. Clients may run on the same 
machine as the server if that machine supports multitasking, or clients may run on other 
machines in the network. In either case, the X Protocol is used by the client to send requests 
to draw graphics or to query the server for information, and is used by the server to send user 
input and replies to information requests back to the client.* All communication from the 



*The X Protocol runs on top of any lower-level network protocol that provides bidirectional communication, and de 
livers bytes unduplicated and in sequence. TCP/IP and DECnet are the only currently-supported networks. 



X Toolkit Intrinsics Programming Manual 



client to the server and from the server to the client takes place using the X Protocol. The 
communication path between a client and the server is called a connection. 

It is common for a user to have programs running on several different hosts in the network, 
all invoked from and displaying their windows on a single screen (see Figure 1-4). Clients 
running remotely can be started from the remote machine, or from the local machine using 
the network utilities rlogin or rsh. 




Figure 1-4. Applications can run on any system across the network 

This use of the network is known as distributed processing. The most important application 
of this concept is to provide graphic output for powerful systems that don t have their own 
built-in graphics facilities. However, distributed processing can also help solve the problem 
of unbalanced system loads. When one host machine is overloaded, the users running clients 
on that machine can arrange for some of their programs to run on other hosts. Eventually, 
there may be automatic load-balancing applications, but currently, such remote execution is 
done manually. It is not unusual to see users in the X environment having several xload load 
monitor applications running on various systems throughout the network but displaying on 
their screen, so that they can see the balance of loads throughout the network. 



Introduction to the X Window System 



Before leaving the subject of servers and clients, we should mention PC servers and X termi 
nals. Software is available that allows various types of PCs to operate as X servers.* X ter 
minals are special-purpose devices designed to run just an X server, and to connect to remote 
systems over a local area network. PC servers and X terminals are the least expensive way to 
provide an X screen for a user. Since most PCs use single-tasking operating systems, they 
can t run any clients at the same time as the server. Therefore, they too require a network 
adapter to connect to another system where clients are run. 

X terminals and PC servers both demonstrate the strength of X s client-server model. Even 
though PCs and X terminals aren t able to do multitasking on their own, they give the user 
the effect of multitasking workstations, because they can interact simultaneously with several 
clients running on remote multitasking systems. 



1.2 The Software Hierarchy 

This book is about writing client applications for the X Window System, in C, using the Xt 
Intrinsics library and a set of widgets. This is only one of the many ways to write X applica 
tions, because X is not restricted to a single language or operating system. The only require 
ment of an X application is that it generate and receive X protocol messages. However, using 
the Xt Intrinsics and a widget set is, and is expected to continue to be, the most common way 
of writing applications for several reasons: it is quite powerful; it results in applications that 
cooperate well with other X applications; and the C language is so widely available. 

Figure 1-5 shows the layering of software in an application that uses the Xt Intrinsics and a 
widget set Notice that the Intrinsics are based upon Xlib, the lowest-level C-language inter 
face to X. Xlib provides full access to the capabilities of the X protocol, but does little to 
make programming easier. It handles the interface between an application and the network, 
and includes some optimizations that encourage efficient network usage. 

Xt is built upon Xlib. The purpose of Xt is to provide an object-oriented layer that supports 
the user-interface abstraction called a widget A widget is a reusable, configurable piece of 
code that operates independently of the application except through prearranged interactions. 
A widget set is a collection of widgets that provide commonly used user-interface compo 
nents tied together with a consistent appearance and user interface (also called look and fee I). 
There are several different widget sets from various vendors that are designed to work with 
Xt. The use of widgets separates application code from user-interface code, and provides 
ready-to-use user-interface components such as buttons and scrollbars. Xt, widgets, and 
widget sets are described in much more detail in Chapter 2, Introduction to the X Toolkit. 

In this book, we ll refer to the combination of the Xt Intrinsics and one widget set as the X 
Toolkit or just the Toolkit. When referring to the Xt Intrinsics layer alone, we ll useXY, or the 
Intrinsics. 



*Companies such as Graphics Software Systems, Interactive Systems, and Locus Computing offer server implemen 
tations for IBM-compatible PCs. White Pine Software offers an X server that runs under Multifinder on the Macin 
tosh. An Amiga server is available from GfxBase/Boing. X terminals are available from Visual Technology, NCR, 
Network Computing Devices (NCD), Tektronix, Graphon Corp, and others. The number of X products on the market 
is growing rapidly. 



X Toolkit Intrinsics Programming Manual 



Application 



Widget Set 



Xt Intrinsics 
Xlib 

X Protocol 




X Server 



Device Drivers 



Figure 1-5. The software architecture ofXt Intrinsics-based applications 

Applications often need to call Xlib directly to accomplish certain tasks such as drawing. Xt 
does not provide its own graphics calls, nor does it provide access to every X protocol fea 
ture. This book will describe the features of Xlib that you may need from a Xt application, 
but it will not repeat the detailed description of Xlib programming found in Volume One, 
Xlib Programming Manual. You will find Volume One and Volume Two (Xlib Reference 
Manual) invaluable when you need to make Xlib calls. 

Xlib, Xt, and several widget sets are available on MIT s public software distribution.* The 
darkly shaded areas of Figure 1-5 indicate interfaces that are exclusive standards of the X 
Consortium. That Xlib is an exclusive standard means that computer manufacturers wishing 
to comply with the X Consortium standard must offer Xlib and cannot offer any other low- 
level X interface in C. The lightly shaded areas (such as the Xt Intrinsics) are nonexclusive 
standards vendors are required to provide Xt but are also allowed to provide other toolkit- 
level layers for the C language. For example, Sun and AT&T will offer Xt, but will also offer 



*The Motif and OPEN LOOK toolkits are not on the Release 3 or Release 4 distributions from MIT, but they are avail 
able for minimal cost from the vendors themselves (OSF and AT&T or Sun respectively.) 



Introduction to the X Window System 



9 



XView as an alternate C-language toolkit-level layer. XView was originally designed for 
porting existing Sun View applications to X, but it can also be used for writing new appli 
cations. 

X software is unlike many other window systems in that it was designed to provide mech 
anism without mandating any certain style of user interface. In the words of its designers, X 
provides "mechanism without policy." The Xlib and Xt layers are standard because they can 
support any kind of interface. It is the widget set that actually imposes user-interface con 
ventions, and it is this layer for which no standard has (yet) been considered by the X Con 
sortium. However, because there is a strong need in the market for one or two standard 
widget sets that provide consistent appearance and user-interface conventions, it is likely that 
one or two widget sets will emerge as de facto standards in the near future. 

It is important to note that the X Consortium standards for Xlib and Xt define the program 
ming interface to each library (often referred to as the Application Programmer s Interface, 
or API), not the underlying code. That means that vendors are allowed to modify or rewrite 
the code to gain the best performance from their particular system, as long as they keep the 
programming interface the same. To you, the application writer and user of the Intrinsics, 
this means that you must always rely on documented behavior if you want your application to 
run on different systems. You must avoid accessing private structures, because they may be 
different in another vendor s release of the library, or may be changed in a future release of 
X. 



1.3 Event-driven Programming 

Programming a graphically-based window system is fundamentally different from standard 
procedural programming. In traditional character-based interfaces, once the application 
starts, it is always in control. It knows just what kind of input it will allow, and may define 
exclusive modes to limit that input. For example, the application might ask the user for input 
with a menu, and use the reply to go down a level to a new menu, where the actions that were 
possible at the previous level are no longer available. Or a text editor may operate in one 
mode in which keyboard input is interpreted as editor commands, and another in which it is 
interpreted as data to be stored in an editor buffer. In any case, only keyboard input is 
expected. 

In a window system, by contrast, multiple graphic applications may be running simulta 
neously. In addition to the keyboard, the user can use the pointer to select data, click on but 
tons or scrollbars, or change the keyboard focus from one application to another. Except in 
special cases (for example, where a "dialog box" will not relinquish control of the keyboard 
focus until the user provides some necessary information), applications are modeless the 
user can suddenly switch from the keyboard to the mouse, or from one application area to 
another. Furthermore, as the user moves and resizes windows on the screen, application win 
dows may be obscured or redisplayed. The application must be prepared to respond to any 
one of many different events at any time. 

An X event is a data structure sent by the server that describes something that just happened 
that may be of interest to the application. There are two major categories of events: user 
input and window system side effects. For example, the user pressing a keyboard key or 



10 X Toolkit Intrinsics Programming Manual 



clicking a mouse button generates an event; a window being moved on the screen also gener 
ates events possibly in other applications as well if the movement changes the visible por 
tions of their windows. It is the server s job to distribute events to the various windows on 
the screen. 

Event-driven window programming reduces modes to a minimum, so that the user does not 
need to navigate a deep menu structure and can perform any action at any time. The user, not 
the application, is in control. The application simply performs some setup and then goes into 
a loop from which application functions may be invoked in any order as events arrive. 

1.4 The Window Manager 

Because multiple client applications can be running simultaneously, rules must exist for arbi 
trating conflicting demands for input. For example, does keyboard input automatically go to 
whichever window the pointer is in, or must the user explicitly select a window? How does 
the user move or resize windows? 

Unlike most window systems, X itself makes no rules about this kind of thing. Instead, there 
is a special client called the window manager that manages the positions and sizes of the 
main windows of applications on a server s display. The window manager is just another cli 
ent, but by convention it is given special responsibility to mediate competing demands for the 
physical resources of a display, including screen space, color resources, and the keyboard. 
The window manager allows the user to move windows around on the screen, resize them, 
and usually start new applications. The window manager also defines much of the visible 
behavior of the window system, such as whether windows are allowed to overlap or are tiled 
(side by side), and whether the keyboard keyboard focus simply follows the pointer from 
window to window, or whether the user must click a pointer button in a window to change 
the keyboard focus. 

Applications are required to give the window manager certain information to help it mediate 
competing demands for screen space or other resources. For example, an application speci 
fies its preferred size and size increments. These are known as window manager hints 
because the window manager is not required to honor them. The Toolkit provides an easy 
way for applications to set window manager hints. 

The conventions for interaction with the window manager and with other clients have been 
standardized by the X Consortium as of July 1989 in a manual called the Inter-Client Com 
munication Conventions Manual (ICCCM for short). The ICCCM defines basic policy inten 
tionally omitted from X itself, such as the rules for transferring data between applications 
(selections), for transferring keyboard focus, for installing colormaps, and so on. 

As long as applications and window managers follow the conventions set out in the ICCCM, 
applications created with different toolkits will be able to coexist and work together on the 
same server. Toolkit applications should be immune to the effects of changes from earlier 
conventions because the conventions are implemented by code hidden in a standard widget 
called Shell. However, you should be aware that some older applications and window man 
agers do not play by the current rules. 



Introduction to the X Window System 1 1 



1 .5 Extensions to X 

X is also extensible. The code includes a defined mechanism for incorporating extensions, so 
that vendors aren t forced to modify the existing system in incompatible ways when adding 
features. An extension requires an additional piece of software on the server side and an 
additional library at the same level as Xlib on the client side. After an initial query to see 
whether the server portion of the extension software is installed, these extensions are used 
just as Xlib routines and perform at the same level. 

Among the extensions currently being developed are support for 2-D spline curves, for 3-D 
graphics, and for display PostScript. These extensions can be used in Toolkit applications 
just as Xlib can. 



12 X Toolkit Intrinsics Programming Manual 



2 



Introduction to the X Toolkit 



This chapter provides a conceptual introduction to the X Toolkit, followed by a 
practical tutorial that starts with the most fundamental toolkit program, a "hello 
world" type application consisting of only a single widget. This application is 
successively refined until the major elements of any X Toolkit program have 
been introduced. 



In This Chapter: 

Programming with Widgets 15 

Contents of a Widget Set 17 

Widget Classes and Instances 18 

Widget Configurability with Resources 22 

Widget Independence 23 

Widget-Application Interaction 25 

Xt and Object-oriented Programming (OOP) 28 

The Object 28 

Methods 29 

Messages 29 

Encapsulation 29 

Structure of X Toolkit Applications 30 

A Simple X Toolkit Application 31 

The Code 31 

Compiling the Application 34 

The Application-defaults File 36 

To Hardcode or Not to Hardcode 38 

Connecting Widgets to Application Code 39 

Callbacks 40 

Actions 43 

The Actions Table 45 



Format of an Action Procedure 46 

The Translation Table 47 

Hardcoding Translations 48 

More About Resources 49 

Setting and Getting Resources from the Application 50 

Core Resources 52 

Other Inherited Resources .. ..54 



2 

Introduction to the X Toolkit 



Building applications for a graphical user interface using a low-level programming library 
such as Xlib requires much sophisticated programming. To simplify development, each of 
the user-interface elements of a graphical application scrollbars, command buttons, dialog 
boxes, pop-up or pull-down menus (everything but the main application window) should ide 
ally be available ready-made, so the programmer need only integrate them with the applica 
tion code. 

The purpose of the X Toolkit is to provide such a simplified approach to graphical user- 
interface programming. However, in keeping with the X philosophy of "mechanism, not pol 
icy," the designers of the X Toolkit didn t develop a fixed set of components with a prede 
fined look and feel. Instead, they created a general mechanism for producing reusable user- 
interface components, which can be either built by the application programmer himself, or 
constructed by lower-level "object programmers" and collected in libraries for application 
use. 

The heart of the Toolkit is a C library called Xt, also known as the X Toolkit Intrinsics. Xt 
provides routines for both creating and using user-interface components called widgets. A 
typical application will use Xt along with a library of pre-built widgets (a widget set) such as 
menus, dialog boxes, scrollbars, command buttons, and so forth, working together to provide 
a consistent application "look and feel." 



2.1 Programming with Widgets 

The simplest way to understand the role of widgets in the X Toolkit is to look at a hypotheti 
cal application, such as the one shown in Figure 2-1. 

If you are at all familiar with graphical applications, you will recognize many of the widgets 
called out in the figure as standard user-interface elements: 

Command buttons, which initiate some application action when clicked on with the 
mouse. 

A scrollbar, which allows the user to scroll the data visible in an associated display win 
dow. (The position of a "thumb" within the scrollbar indicates the position of the visible 
data within a larger data buffer, and lets the user change the current position in the buffer 



Introduction to the X Toolkit 15 



main application 
window or widget 



composite 
widget 



shell 
widget 



scrollbar 



label 
widget 



composite 
widget 




command 

button 

widgets 



pop-up 
shell widget 



Figure 2-1. A widget-based application 

by dragging the thumb with the mouse. Widget sets vary in their term for the scrollbar 
thumb.) 

A data entry area, in which the user can type information requested by the application. 

There are other widgets in the application that might not be as obvious: 

Composite widgets, which are used to contain other widgets. In all widget sets, there are 
special classes of widgets whose function is to manage the position (and possibly the 
size) of the child widgets they contain. 

Composite widgets are an important part of any widget set, since they insulate the appli 
cation programmer from having to place each widget individually, or from having to 
reposition or resize various widgets when the application is resized by the user. Compos- 



X Toolkit Intrinsics Programming Manual 



ite widgets automatically adjust the layout of their children when child widgets are added 
or removed. 

Shell widgets. In any X Toolkit application, a special widget called a Shell widget is 
created by the call to initialize the Toolkit This widget is used as the parent of all other 
application widgets (with the exception of pop ups, which receive their own transient 
Shell widget as a parent), and includes special functionality that allows it to interact with 
the window manager. The Shell widget is invisible, since it is overlaid by the main 
widget of the application (typically a composite widget), which is exactly the same size.* 

A special-purpose application window. Most applications have at least one window that 
has unusual characteristics not supported by an existing widget. For example, in our 
hypothetical application, the main application window is used to graph the performance 
of a stock portfolio. 

There are two ways to implement such windows. You can add functionality to an exist 
ing widget (usually what is called a Core widget) by adding actions as described and 
demonstrated in Chapter 4, An Example Application, or you can write your own widget, 
as described beginning in Chapter 5, Inside a Widget. As you will see, after you have 
written the application code to operate the special-purpose window, making a widget that 
does the same thing is mostly a matter of rearranging the code and changing variable 
names. Placing code into a widget gives you easier access to the configurability features 
of Xt, and neatly packages up the code to operate the special window. 

A pop-up dialog box. A pop up is a widget that appears temporarily on the screen, until 
the user provides a certain kind of input. Pop ups are usually invisible when the applica 
tion starts up. Using Xt, applications create pop ups very much like permanent widgets. 
The only difference is that a special kind of Shell widget called a pop-up shell needs to be 
created as the parent of the widget to be popped up. Many types of menus and dialog 
boxes (also referred to as "notices") are intended to be used as pop ups. 



2.1 .1 Contents of a Widget Set 

Shell widgets, and a few other base widget classes (Core, Composite, and Constraint) that are 
used to build more complex widgets, are defined by Xt. The special-purpose application win 
dow is written by the application programmer. All of the other widgets shown in Figure 2-1 
are from the Athena widget set, developed at MIT. 

The Xaw library in the standard X distribution contains the Athena widget set This book 
provides examples using the Athena widgets because they are universally available, and 
because the techniques for using, modifying, and creating widgets are the same, regardless of 
which widget set you use. However, the Athena widget set was not intended to be com 
plete it was built mainly for testing and demonstrating the Intrinsics. Furthermore, the 



*The Shell widget is actually a type of composite widget, which is designed to have only one child widget. Its layout 
policy is extremely simple. It just makes its child widget exactly the same size as itself. 



Introduction to the X Toolkit 



17 



Athena set does not have a particularly attractive appearance. For these reasons, we suggest 
that serious application development efforts should begin with a commercial widget set 

Two commercial widget sets that are easily available and quite complete are OSF s Motif 
and AT&T s OPEN LOOK widgets. Both Motif and OPEN LOOK contain menus, scrollbars, 
command buttons, dialog boxes, and a wide variety of composite widgets. Both have an 
attractive appearance and consistent, well defined user-interface conventions. Each comes 
with a style guide that contains suggestions for designing applications to blend in well with 
other applications using that widget set 

Appendix A, OPEN LOOK and Motif, describes these widget sets. 

2.1.2 Widget Classes and Instances 

A widget library defines classes of widgets. Each class has unique characteristics shared 
with all other members of that class, but distinct from other classes. Command is a class of 
widget, as are Box, Label, Scroll, and the other Athena widgets shown in our hypothetical 
application. Each time you create a widget, you create an instance of one of these predefined 
classes. For example, you might create several Command widgets, each with a unique name, 
containing a unique text label, and each invoking different application code when it is 
clicked on. 

Widget characteristics can be inherited from other, more basic classes of widgets. Inheri 
tance means that a new class of widget has to define only its own unique features, and need 
not re-implement those common to all widgets, or already implemented by an existing super 
class. All classes exist in a hierarchy, which defines from which other classes each class 
inherits features. (Note that the class hierarchy is completely different from the parent-child 
relationship of widget instances you create in an application. The class hierarchy of a partic 
ular widget class is fixed, while the instance hierarchy is set differently in every application.) 

Figure 2-2 shows the class inheritance hierarchy for the Athena Widgets. Classes defined by 
Xt (which are the same for all widget sets) are shaded gray.* 



*Nole that the X Toolkit supports only single inheritance. That is, characteristics can be inherited directly from only 
one superclass (though that superclass may itself have inherited characteristics from prior superclasses). 



18 X Toolkit Intrinsics Programming Manual 





Simple 




Vpaned j Form 
Dialog | 



Label | j Text 1 1 List Grip I j Scroll 



Command 



velShell i TransiemSMl 




Figure 2-2. Inheritance among the Athena widgets 

The Core widget class, defined by the Intrinsics, is the root of the hierarchy, from which all 
other classes are descended. The Core class defines characteristics common to all widgets, 
such as size and position. 

The Athena Simple widget class inherits basic widget features from Core and adds a few 
minor features of its own (for example, the ability to change the cursor shape when it enters 
the window). The Label widget in turn adds the ability to print a string, and mechanisms for 
changing the font and placement of the string. Command then inherits features from Label 
(including those already inherited from Core and Simple) and adds more features (the ability 
to accept user input, and to highlight the button). Command is known as a subclass of Label, 
and Label is the superclass of Command. In general, lower classes in the hierarchy have 
more features. 

As you can see from Figure 2-2, Text, List, Scroll, and Grip, like Label, are simple widgets 
subclassed directly from Core. Command is a refinement of Label. The Text widget provides 
a ready-built, configurable text editor. List displays a list of strings, which can be selected 
individually, and passed to an application function. (For example, this widget might be used 
to implement a file selection box from which the user might select which file to open.) 



Introduction to the X Toolkit 



Scroll widgets are designed to be attached to other windows, and to provide a mechanism by 
which the user can scroll the data in a window by dragging or clicking in the scrollbar. A 
Grip is a small solid box used for resizing panes in a Vpaned widget (see Figure 2-3). 

The Vpaned widget manages a series of vertical panes, which have the constraint that they 
can only be resized in the vertical direction, by using the pointer to drag Grip widgets pro 
vided for that purpose. Vpaned is useful for applications such as xmh, the X mail handler, 
that display data in several different windows simultaneously. 

Figure 2-3 shows a VPaned widget 



vertical 
panes 






f \ Folder ][ Table of Contents || Message ] | Sequence | 


View |[0ptions | 


inbox 


Be- 


[Xau | |xt | Xtbook 1 1 consortium 1 1 drafts 1 1 inbox 1 1 misc | [ personal | 


protocol ] [ xlib 1 1 xlibbook ] |xneus ^, 


mbox:all ^s 


1 11/27 To;adrian Hi Ms. ReaderHow are you today 


A 


mbox;2 ^ 


[fate: Mon, 27 Nov 89 16:19:53 EST 
^ From: adrian (fldrian Nye) 
Message- 1 d : <8911272120 . AA07404@sp i ke> 
ITo: adrian 
Subject: test message 
This is a test of the emergency mail handling 
This is only a test. If this had been a real 
it would not have worked. 


system, 
emergency , 




grips 



Figure 2-3. An Athena VPaned widget (paned in R4) 

Form allows the position of its children to be specified relative either to each other or to fixed 
points in the Form parent Children are thus constrained always to have the same relative 
position in the parent even when it is resized. 

Dialog is a subclass of Form that has been given specific children: a Label, which is used for 
printing a message, an optional Text widget for data entry, and two command widgets, for 
confirming or cancelling the action suggested by the dialog. 

Figure 2-4 shows a Dialog widget 



20 



X Toolkit Intrinsics Programming Manual 



Enter Text Below: 


A. 








Dialog Done 



Figure 2-4. An Athena Dialog widget 

The Composite class adds geometry-management capabilities to the basic characteristics 
defined by Core. Box is a subclass of Composite that is mainly intended to manage a group 
of similarly-sized Command widgets. Viewport is a composite widget that provides a main 
window and horizontal and vertical scrollbars. Figure 2-5 shows a Viewport widget manag 
ing a List widget and a Scroll widget 



scroll 
widget 





pt ions (Sections 1 The 


current manual 


page is: fmt. 






adb 


addbib 


apply 


apropos 






ar 


as 


at 


atq 






atrm 


auk 


basename 


be 






biff 


binmail 


cal 


calendar 






case 


cat 


cb 


cc 






cd 


chsckeQ 


checknr 


chfn 






chgrp 


chmod 


chsh 


clear 






cmp 


col 


colcrt 


colrm 






comm 


compress 


cp 


csh 






ctags 


cu(c) 


date 




lict 


dbx 


IISl 




dc 


dd 


deroff 


df 


widget 




diction 


diff 


diff3 


diffh 






domainnaroe 


du 


echo 


ed 






edit 


efl 


egrep 


eqn 






error 


ex 


expand 


explain 






expr 


f77 


false 


fgrep 






file 


find 


finger 


^Q 






fold 


for 


fp 


fpr 






from 


f split 


ftp(c> 


gcore 






gprof 


graph<9> 


grep 


groups 






hd 


head 


host id 


hostname 






if 


indent 


indxbib 


install 






intro 


iostat 


join 


kill 






last 


lastcomm 


Id 


learn 






leave 


lex 


lint 


lisp 





\ 



Figure 2-5. A Viewport widget 



viewport widget 



Shell is a special class of Composite widget designed for interaction with the window man 
ager. 



Introduction to the X Toolkit 



21 



Most applications use a TopLevel shell for their main window; pop ups use either an Over- 
RideShell or a TransientShell. (See Chapter 12, Menus, Gadgets, and Cascaded Pop Ups for 
more information on Shell widget classes.) 

Constraint is a further refinement of Composite that allows the application or the user to sup 
ply instructions about how the size and position of each child should be managed. 

The Athena widgets are described in Volume Five, X Toolkit Intrinsics Reference Manual. 

New widgets can be subclassed by the widget programmer directly from Core, Composite, or 
Constraint, or can be subclassed from an existing widget in any widget set that has some, but 
not all, of the desired behavior. For example, it is easy to imagine creating subclasses of 
Form to provide other types of preconfigured dialog boxes or data entry screens. 

As long as appropriate widget classes are available, the application programmer needs to 
know little or nothing about widget internals. He can use existing widgets for most purposes. 

2.1.3 Widget Configurability with Resources 

To serve their purpose as reusable user-interface components, widgets must be highly confi 
gurable. For example, an application programmer must be able to define not only a separate 
label for each Command widget, but also the application function that is invoked when the 
button is clicked. The programmer will also want to let the user define additional attributes 
such as font and color. 

To support this degree of configurability, widget classes can declare variables as named 
resources of the widget The application can pass the value of widget resources as arguments 
to the call to create a widget instance, or can set them after creation using the Intrinsics call 
xt Set Value s. In addition, though, as an application starts up, a part of Xlib called the 
resource manager reads configuration settings placed in a series of interrelated ASCE files by 
the user and/or the application developer, and Xt automatically uses this information to con 
figure the widgets in the application. The collection of resource name- value pairs contained 
in the various resource files and set directly by the application is collectively referred to as 
the resource database. 

Figure 2-6 shows several Label widgets configured with different resource settings, to show 
you how radically the appearance of even such a simple widget can be altered. Note that the 
widget s input characteristics can also be configured. 

The resource manager provides a very flexible mechanism for generalizing the behavior of 
widgets. The application developer can "hardcode" the value of resources that cannot be 
changed without crippling the widget or application, and can establish reasonable defaults 
for the rest, so that the user can configure all nonessential aspects of application appearance 
and behavior. 

Note that the term resource is used somewhat ambiguously in X. First, in the original docu 
mentation for Xlib and the X protocol, various data structures that are maintained by the 
server and identified to clients only by an integer ID are referred to as resources. These data 
structures include windows, bitmaps, fonts, and so forth. 



22 X Toolkit Intrinsics Programming Manual 




Hello, World. 



etto SSortb 



Hello, World! 



n 



Figure 2-6. Several Label widgets configured using resources 

Second, the term is commonly used to refer both to a widget variable publicly declared as a 
widget resource, and to the name-value pairs in the resource database. In this book, we will 
use the term resource to refer to the the actual variable and its current value in a widget 
instance, and the term resource setting to refer to a name-value pair in the database. The two 
are closely related, but may not be identical. For example, separate settings for the same 
resource may be requested in an application-defaults file and in an individual user-preference 
file.* Furthermore, the value of a resource may be set on the fly by a call to xt SetValues, 
but this value is never saved in the resource database. (This value can be retrieved from 
within a widget or application by a call to xtGetValues.) 



2.1.4 Widget Independence 

Each widget is, to a large degree, independent of the application. Xt dispatches events to a 
widget, which performs the appropriate actions according to the design of its class, without 
application help. For example, widgets redraw themselves automatically when they become 
exposed after being covered by another window.! Widgets also handle the consequences 



*There are several possible sources of resource settings. Which will actually take effect is determined by rules of 
precedence that are described (along with the various sources of resource settings) in Chapter 9. 
fRedrawing is necessary because only the visible contents of X windows are maintained by the X server. When one 
window is obscured by another, the contents of the obscured window are lost, and must be redrawn when it is expo 
sed. X clients are responsible for redrawing the contents of their windows when this happens. Fortunately, Xt auto 
matically redraws correctly written widgets at the appropriate times so that your application doesn t have to worry 
about it. 



Introduction to the X Toolkit 



23 



when the values of their resources are changed. An instance of Label, for example, does not 
depend on the application that created it to determine its size. By default, Label will choose 
a size large enough to accommodate the current string in the current font. If the application 
changes the text or font in the Label widget with a call to xtSetValues, the Label widget 
itself will attempt to keep its own window large enough to accommodate the current string. 
(Of course, if necessary, the application can also explicitly choose the Label widget s size.) 
When the application tells a Label widget what font to display its string in, the widget knows 
how to load a new font, recalculate its own size, and redraw its string the application 
doesn t have to micro-manage any of this. The application simply sets the font resource of 
the widget, and the widget does the rest. 

Figure 2-7 and Figure 2-8 illustrate how a widget operates independently of the application 
and how xt Set Values lets the application set how a widget operates itself. 




Network 



r 




Drawing 
requests 


Expose and / 
user events 



Xt 

Intrinsics 
routines 



Application Code I 




Widgets operate independently of the application 



Figure 2-7. Widgets operate independently of the application 



24 



X Toolkit Intrinsics Programming Manual 



xt 

Intrinsics 
routines 



Application Code 




...but the application can change various characteristics of the 
widget with XtSetValues 



Figure 2-8. XtSetValues lets the application set how a widget will operate itself 

2.1.5 Widget-Application Interaction 

In the other direction, widgets are designed to let the user control the application. Therefore, 
widgets have the ability to invoke certain sections of application code elements of the 
application s own choosing. Again, though, widgets will operate fine without invoking any 
application code, but if they don t invoke any, they won t do anything for the user. 

One way that the application arranges for widgets to invoke application code is by register 
ing application functions with Xt. Once the application is running, Xt will call these func 
tions in response to some occurrence in the widget. For example, a Command widget usually 
invokes an application function when the user clicks on the widget. (Thus, the widget 
labeled "Quit" might invoke the code that exits the application.) Or the Scroll widget noti 
fies the application when the user has moved the thumb, by calling a function that the appli 
cation has registered with the widget for that purpose. Figure 2-9 and Figure 2-10 illustrate 
how an application registers a function during the startup phase, and how Xt then calls the 
function during the event-loop phase in response to a particular occurrence in the widget. 



Introduction to the X Toolkit 





Network 



Widget 




register callback 
routines (or, less 
often, action routines) 



Application Code I 



Xt 

Intrinsics 
routines 




... and the application can provide and register callback or action 
functions with the widget ... 



Figure 2-9. Application registers a function with Xt during startup phase 

There are three separate mechanisms that can be used to link widgets and application func 
tions: callbacks, actions, and event handlers. 

Generally speaking, a widget expecting to interact with an application will declare one or 
more callback lists as resources; the application adds functions to these callback lists, which 
will be invoked whenever the predefined callback conditions are met. Callback lists are 
resources, so that the application can set or change the function that will be invoked. 

Callbacks are not necessarily invoked in response to any event; a widget can call the speci 
fied routines at any arbitrary point in its code, whenever it wants to provide a "hook" for 
application interaction. For example, all widgets provide a destroyCallback resource 
to allow applications to interpose a routine to be executed when the widget is destroyed. 



26 



X Toolkit Intrinsics Programming Manual 




Widget I 



callback routines 
or action routines 
U invoked 



Application Code I 




Xt 

Intrinsics 
routines 




... which the widget will call when certain events occur. The 
widget gives control back to the application for the duration of 
the callback or action routine. 



Figure 2-10. Xt calls the function during the event-loop phase in response to an occurrence 

However, callbacks are often invoked by widgets from within actions, which are event- 
driven. Action routines are called directly by Xt in response to events specified in a trans 
lation table. The Xt Translation Manager supports a high-level, event-specification syntax, 
which allows easy specification of complicated event sequences (such as double- or triple- 
clicks, or key- and button-press combinations) as the trigger for actions. Furthermore, the 
translation table is a resource, allowing the application developer or the user to configure the 
events that will invoke a given widget action. 

Actions may be internal to the widget and require no interaction with the application. (For 
example, in the Athena Text widget, all editing operations are carried out entirely by the 
widget, using functions defined as actions. The only role required of the application is to 
read and write files.) However, an application can also add actions to a widget, which can 
function in much the same way as callbacks, but without the widget class having made provi 
sion for them. 



Introduction to the X Toolkit 



27 



The purpose of a well-designed widget set is to implement a particular user interface, which 
provides conventions designed to make all applications operate in the same way. A widget s 
callbacks are often designed to support the intended use of the widget, while adding actions 
to a widget can make it behave in ways the designer did not foresee and that the user might 
not expect. Nonetheless, there are cases in which the best way to implement the desired 
behavior is to add actions to an existing widget 

In addition to callbacks and actions, it is also possible for an application (or a widget) to 
implement event handlers, which use a specific event-selection mechanism similar to that 
used in Xlib. Event handlers are rarely used by application programmers, since actions are 
simpler and more configurable. 

Some widgets also declare public routines, which can be used by an application to control 
aspects of the widget s behavior or to get widget data. Usually, the purpose of public rou 
tines is to provide a more convenient means for setting or getting widget data that would 
otherwise have to be accessed through resources. 

2.1.6 Xt and Object-oriented Programming (OOP) 

Xt provides an object-oriented programming (OOP) style, where the objects are widgets. 
However, since Xt is written in C, a language that provides no special support for OOP, Xt 
depends on programming conventions and programmer discipline to maintain the semblance 
of objects. It is very important that the programmer understand the goals and rules of OOP, 
because the language and the system won t enforce these rules. If you are familiar with 
another object-oriented system, you will need to understand Xt s particular implementation 
of OOP. On the other hand, if Xt is your first exposure to OOP, an explanation of its goals 
and concepts should make the whole system make a lot more sense. 

Traditionally, object-oriented programming is defined in terms of the five words object, 
method, message, class, and instance, and the concept of encapsulation. We ve already 
talked about classes and instances. This section describes the remainder of these terms. 

2.1.6.1 The Object 

In OOP, an object contains two elements: the data that represents a state, and code that reads 
or writes that data (called methods). For example, the string displayed by a Label widget is 
part of its state data, and the code that actually draws the string on the window is a method 
that reads the state data. Inside widget code, the state data is represented as structure mem 
bers, and the methods are represented as pointers to functions. Some state data members are 
public; they are resources that can be set or retrieved from outside the object. Other state 
data members are private; they cannot be read or written from outside. 



28 X Toolkit Intrinsics Programming Manual 



2.1.6.2 Methods 



What is called a method in traditional OOP is either a method or an action in Xt. In Xt, 
methods are a set of functions that are fixed for a particular class, triggered in fixed ways in 
response to Xt function calls made by the application (with one special case, the expose 
method, triggered directly by the Expose event). A widget s methods supply its most basic 
functions, such as the code needed to create a widget or to change its resources. Actions, on 
the other hand, are called in response to the events specified in a translation table, and are 
thus user configurable. Actions supply most of the features of widgets, and these features can 
be added to or replaced by the application, as demonstrated in Sections 2.4.2, 4.3, and 4.4. 



2.1.6.3 Messages 



In pure OOP, input to objects and communication between them are called messages. In Xt, 
however, the forms of communication are function calls, events, actions, and callbacks. As 
you have seen, applications can communicate with widgets using function calls, such as to 
set or get widget resources using XtSetValues and xtGetValues. Widgets also 
respond directly to events from the user. Widgets contact the application when certain things 
occur using callbacks or actions. Widgets pass data back and forth using special kinds of 
events. All these types of communication can be thought of as forms of messages. 



2.1.6.4 Encapsulation 



Objects are intended to be black boxes with documented inputs and outputs. In other words, a 
program that uses an object must not depend on the internal implementation of the object, but 
instead only on the known inputs and outputs. This is called code encapsulation. The advan 
tages of code encapsulation are that programmers can use the object without needing to 
understand its internal implementation (hiding details), and that the internal implementation 
of the object can be changed at any time because no other code depends on it. This can be 
stated in another way: it minimizes interdependencies. In large software projects, this one 
feature makes OOP worthwhile. 

This encapsulation is very effective in Xt. You should be able to get a long way toward com 
pleting an application without even needing to know what the code inside a widget looks 
like, let alone the details that implement a particular widget For that reason, in this book we 
don t show you what is inside a widget until Chapter 5, Inside a Widget. Even when you do 
know how widgets are implemented,, it is a good idea to "forget" while writing application 
code, so that you are not tempted to depend on implementation details. 

Each widget class has a public include file and a private include file. The application 
includes just the public include file, while the actual widget code includes the private (which 
happens also to include the public). The names of both include files are based on the class 
name of the widget, but the private include file adds the letter P to the end. For example, the 
Label widget s public include file isLabelh, while its private include file isLabelP.h. Appli 
cation code should include only the public include file, to maintain the desired encapsulation. 
It is tempting for beginning Xt programmers to include the private include file, because it 
allows you to take shortcuts, but you should resist the temptation.* 



*In a language designed for OOP, such as C++, these shortcuts are generally prevented by the compiler or by the lan 
guage itself. 



Introduction to the X Toolkit 



29 



2.2 Structure of X Toolkit Applications 

All Toolkit applications have the same basic structure, as follows: 

1. Include <X11 /Intrinsic. h> and <Xll/StringDefs.h>, the standard include files for Xt. 

2. Include the public include file for each widget class used in the application. (Each widget 
class also has a private include file, which is used in the widget code.) 

3. Initialize the Toolkit with the convenience function xtlnitialize. (Complex appli 
cations may need to use four separate calls, to xtToolkitlnitialize, xt- 
CreateApplicationContext, XtDisplaylnitialize, and XtApp- 
CreateShell.) 

4. Create widgets and tell their composite parent widget about them. This requires one call 
to xtCreateManagedWidget for each widget Separate xtCreateWidget and 
xtManageChildren calls can also be used to speed startup of applications with many 
widgets. 

5. Register callbacks, actions, and event handlers, if any, with Xt. 

6. Realize the widgets by calling xtRealizeWidget. This function has to be called 
only once for the entire application, on the shell widget returned by xtlnitialize. 
This step actually creates the windows for widgets and maps them on the screen. This 
step is separate from creating the widgets themselves, because it allows all interdepen 
dent widgets to work out their relative size and position before any windows are created. 
(More on this topic, called geometry management, in Chapter 11, Geometry Manage 
ment.) 

7. Begin the loop processing events by calling XtMainLoop. At this point, Xt takes con 
trol of your application and operates the widgets. If any widgets are to call functions in 
your application, you must have registered these functions with Xt before calling xt- 
MainLoop. 

The four steps (3 through 6 above) of initializing the Toolkit, creating widgets, registering 
application functions with Xt, and realizing widgets, comprise the setup phase of the applica 
tion. Your application should do as much of its work as possible in this phase, before calling 
XtMainLoop, in order to speed up the second phase of the application, which is the event 
loop. This policy improves the response time to user events.* As we will see in Chapter 5, 
Inside a Widget, this policy also applies to the code inside a widget It is basic to X, and 
indeed to any event-driven system. 



*In X protocol terms, the setup phase consists of requests to the server that are generally long, and often require im 
mediate replies, which tends to slow performance. The event loop phase, on the other hand, generally consists of 
short requests and very few "round-trip" requests. For a full description of this concept, see the introductory chapter 
to Volume Zero, X Protocol Reference Manual. 



30 X Toolkit Intrinsics Programming Manual 



2.3 A Simple X Toolkit Application 

Some application code that uses the X Toolkit will go a long way to illustrate the basic con 
cepts introduced above. 

Figure 2-11 shows the actual window created by a minimal "hello, world" Toolkit application 
xhello, and Example 2-1 shows the code for it xhello simply displays the string "hello" in a 
window. 




Figure 2-11. xhello: appearance on screen 

Some window managers may add a decorated border above or surrounding the window; it is 
not part of the application. Likewise, the placement of the widget on the screen depends on 
the window manager. Since no coordinates are specified as resources for the widget, uwm or 
twm will require the user to place it interactively. Another window manager might place it at 
some arbitrary default location. 



2.3.1 The Code 



Example 2-1 shows the code for xhello. c. 

Example 2-1. xhello.c: a minimal "helb, world" application 



I* 



* xhello.c - simple program to put up a banner on the display 
*/ 

/* 

* Include files required for all Toolkit programs 

*/ 

tinclude <Xll/Intrinsic.h> /* Intrinsics Definitions*/ 

tinclude <Xll/StringDefs.h> /* Standard Name-String definitions*/ 

/* 

* Public include file for widgets we actually use in this file. 

*/ 

#ifdef X11R3 

/* Athena Label Widget */ 
/* R4 or later */ 
/* Athena Label Widget */ 
/* X11R3 */ 



tinclude <Xll/Label .h> 

telse 

tinclude <Xll/Xaw/Label .h> 

tendif 

main(argc, argv) 

int argc; 

char **argv; 



Introduction to the X Toolkit 



31 



Example 2-1. xhello.c: a minimal "hello, world" application (continued) 

Widget topLevel, hello; 

topLevel = Xtlnitialize ( 

argv[0], /* Application name */ 

"XHello", /* Application class */ 

NULL, /* Resource Mgr . options */ 

0, /* number of RM options */ 

Sargc, /* number of args */ 

argv /* command line */ 
); 

hello = XtCreateManagedWidget ( 

"hello", /* arbitrary widget name */ 

labelWidgetClass, /* widget class from Label. h */ 

topLevel, /* parent widget*/ 

NULL, /* argument list */ 

/* arg list size */ 

); 

/* 

* Create windows for widgets and map them. 
*/ 

XtRealizeWidget (topLevel) ; 

/* 

* Loop for events. 
*/ 

XtMainLoop ( ) ; 

} 

Each of the four Xt Intrinsics calls in xhello do more than meets the eye: 

Xtlnitialize performs several important tasks. It reads the resource databases and 
merges in any arguments found on the command line so that Xt can use this information 
to configure widgets as they are created. It also opens a connection to the server, and cre 
ates a Shell widget that is designed to interact with the window manager and to be the 
parent for other widgets created in the application. 

The first and second arguments to Xtlnitialize are the name and class of the appli 
cation. Originally, the idea was that one might define classes of applications, such as 
"editor," of which various text editors might be considered instances. As it has turned 
out, though, the first argument is unused, and the Shell widget returned by Xt 
lnitialize obtains the application name from argv. The second argument specifies 
the name of the application-defaults file, in which default resource settings are esta 
blished. As mentioned above, by convention, this file has the same name as the applica 
tion, with the first letter capitalized, or if the application name begins with X, the first two 
letters capitalized. For the current application, we ve specified the first argument any 
way, for compatibility with future releases which might make use of it, and have specified 
the second argument as XHello. 

The third and fourth arguments are a pointer to and length of an array of application- 
specific command-line arguments (which we ll tell you how to construct in Chapter 3, 
More Widget Programming Techniques; here, these arguments are unused). The fifth and 
sixth arguments are the common argc and argv which Xtlnitialize parses for 



32 X Toolkit Intrinsics Programming Manual 



a variety of standard X Toolkit options (described in Chapter 3, More Widget Program 
ming Techniques, and on the Xt Initialize page in Volume Five, X Toolkit Intrinsic* 
Reference Manual). 

Xt Initialize removes all arguments it recognizes from argc and argv, except for 
the application name. The program can check if more than one argument remains, and if 
so, abort with an error message. 

The Shell widget returned by the call to Xt Initialize is used as the parent of all 
other widgets in the application (except pop ups, which receive their own pop-up shell 
parent) 

The xtCreateManagedWidget call both creates the Label widget and tells the par 
ent (the Shell widget) that the Label widget s geometry is to be managed. It is also pos 
sible to call XtCreateWidget and either xtManageChild or xtManage- 
Children separately, but this is usually done only if you want to create several widg 
ets, and then put them under parental management all at once. 

XtCreateManagedWidget is used for creating any class of widget The first argu 
ment is the instance name, which Xt uses to look up settings in the resource database. 
The second argument specifies the class of widget to create this variable comes from 
the include file for that widget, and should always be documented on the reference page 
for a widget The third argument is the parent, which in this case is the widget returned 
by xtlnitialize, but in a more complex example could be a composite widget 
deeper in a hierarchy of nested widgets. The fourth and fifth arguments, unused in this 
example, are for hardcoding widget resources. (More on this in the next section.) 

Notice that XtCreateManagedWidget and Xtlnitialize each return a value of 
type widget. This type is an opaque pointer that is used to refer to a widget instance. It 
is used anywhere in the application that you need to refer to a particular widget We 
sometimes refer to this as a widget ID, since even though it is a pointer to a structure, the 
individual fields in that structure should never be accessed from the application. 

The steps of initializing the Toolkit and creating widgets seem logical. However, what 
does it mean to realize a widget? xtRealizeWidget actually makes windows for the 
widgets, whereas creating the widgets simply creates and initializes various internal 
widget data structures.* Creation and realization of widgets are separate because some 
window geometries cannot be known until all the widgets are created and the composite 
widgets have determined their geometries. The realization step says "OK, all the widgets 
are created now; calculate their sizes and positions and make windows for them." How 
ever, note that it is acceptable to create additional widgets after calling xtRealize 
Widget as long as there is a good reason to do so (such as if it cannot be known whether 
the widget would be needed until a certain user event arrives). 

The realization step also maps all the widget windows. Mapping is an X concept, not 
something added by Xt. Mapping a window makes it eligible for display. For a window 
to actually become visible, all its ancestors must be mapped. Since 



*A widget is a client-side object It has no presence on the server other than as a normal X window. The Xt and 
widget set libraries running on the client side maintain the data that allow programs to work with the abstraction per 
ceived as a widget 



Introduction to the X Toolkit 33 



XtRealizeWidget is called for the widget created by Xtlnitialize, which is 
the ancestor of all widgets in the application, the end result is that the entire application is 
displayed.* 

XtMainLoop transfers control of the application to Xt. From this point on, Xt drives 
all the widgets in response to events, and it interacts with the application only at times the 
application has arranged ahead of time, xhello did not arrange any interaction with the 
widget, so Xt operates the Label widget completely without returning to xhello s code. 
Examples 2-3 through 2-8 will demonstrate how to make such arrangements. 

Xt programming is event-driven. XtMainLoop dispatches events to widgets and func 
tions in the order in which they occur. These events can be caused by user actions such 
as pressing a key or by window system actions such as displaying a new window. This is 
fundamentally different from procedural programming, where the application is in charge 
and polls for user input at certain points. 



2.3.2 Compiling the Application 

You can get the code for xhello.c and all the rest of the examples in this book via uucp or 
anonymous///? from either uunet.uu.net or expo.lcs.mit.edu, as described in the Preface. The 
code is also on the Release 4 distribution tape from MIT in the "contrib" section. It is a good 
idea to compile and run each example as it is presented. 

The example programs come with Imakefiles that should make building them easy if you 
have the X source. To do this you need the intake program (which should be in /usr/lib/Xll), 
and you need the configuration files in TOPImitlconfig, where TOP is the root of your X 
sources. An Imakefile is a system-independent makefile that is used by imake to generate a 
Makefile. This is necessary because it is impossible to write a Makefile that will work on any 
system. You invoke imake using the ximake.sh shell script also provided in the X sources. 
Complete instructions for compiling the examples using imake are provided in a README 
file in the example source. 



"There are several other conditions that can prevent or delay a window from becoming visible, described in Section 
2.2.5 of Volume One, Xlib Programming Manual (Section 2.2.4 in the 2nd edition of Volume One). These will not 
affect your Toolkit application as long as you draw into windows at the right time, using one of the techniques de 
scribed in Section 4.3 and Section 6.3. 



34 X Toolkit Intrinsics Programming Manual 



Is the X Toolkit Too Complex? 

An editorial aside 





Window systems may be simple to use, but they are very complex to program. The first 
thing that strikes the novice X programmer is how complicated everything is. Learning to 
program the X Window System, even with the help of the X Toolkit, is afar cry from learn 
ing say, the C programming language, where the very first page of the tutorial presents a 
complete running program. The program itself is trivial, but this, the "hello world" pro 
gram, has become a tacit benchmark ofprogrammability. The assumption is "if you can t 
write hello world simply, things are badly designed." 

In fact, "hello, world" is a pathological example for X; it is a case where the stylized scaf 
folding outweighs the functional code. You ve just seen an X Toolkit equivalent to "hello 
world," and it is nearly thirty lines long. But it is node-independent, does device- 
independent graphics, and can be customized by the user to control what font to use, and 
what color to use for the border, background, and text. 

The "hello world" example is indeed a good benchmark of language complexity, but it is 
not necessarily a good general benchmark for overall programming complexity. It is an 
especially poor measure for a system that encompasses a generalized distributed software 
environment, network communication, and device-independent graphics. Most people 
write complicated applications, not trivial programs like "hello, world," and it is the ease 
with which a complicated program can be written that is the true test of a language. 

For example, consider the difference in the number of lines of code between "hello world" 
and a text editor. Kernighan & Ritchie s C Programming Language, where "hello world" 
was first introduced, doesn t present an editor. However, Kernighan and P laugher s Soft 
ware Tools, an equally sacred reference from the same era, presents a text editor that con 
tains well over one thousand lines. Furthermore, the editor is line-oriented, not screen- 
oriented. By comparison, because of the modular design of the Toolkit, and the develop 
ment of widgets as reusable user-interface components, a programmer can construct a 
simple screen editor using the Athena Text widget in about 170 lines of code. This editor is 
user-configurable, device-independent, and based on a ready-made component that can 
easily be incorporated into any program needing to provide text-editing capabilities. 

This is not to invite absurd comparisons of incommensurate programming tools, but to 
emphasize that the complexity ofX is the outgrowth of added functionality , not unneces 
sary convolutions of straightforward algorithms. What really matters is what features are 
provided, how difficult is it to write the kind of application you want to write, and what 
performance can be achieved. 

Marie Langley 



Introduction to the X Toolkit 35 



To compile any of the examples on a UNIX system without using imake, use the following 
command line: 

cc -o filename filename. c -IXaw -IXmu -IXt -1X11 -DX11R3 

The order of the libraries is important. Xaw relies on Xmu (miscellaneous utilities), and both 
rely on Xt. Both Xmu and Xt in turn depend on Xlib (the -1X11 link flag specifies Xlib). 

Since XI 1 Release 4 may be available to some but not all readers, the examples use #if def 
for various elements different between Release 3 and Release 4, so that the examples will 
compile under either release. If you are running Release 4, the -DX11R3 flag should not be 
specified. 

2.3.3 The Application-defaults File 

As mentioned above, the resource mechanism allows widgets and applications to be custom 
ized. Resources may be declared by either a widget or an application, and can be set from 
any one of several sources, including a user s resource file, the command line, or an 
application-specific defaults file. 

Each resource of a widget has a default value determined by the widget class that declared 
the resource. However, in many cases, the application wants a different default value, but 
still wants the user to be able to change the value of that resource. 

The Label widget is a case in point. Example 2-1 (xhello) set the default string displayed in 
the Label widget, "hello," by naming the widget hello in the call to xtCreate- 
Managedwidget. It just so happens that the Label widget uses its widget name as the 
string to be displayed if no other string has been specified in the resource database. However, 
this trick doesn t exist for the other resources of Label or of other widgets. 

In general, the application can t easily provide a default value for resources by hardcoding 
them in the application source file. Even if it could, changing these settings would require 
recompiling the source. Xt provides a better way. 

To provide defaults, applications should always create an "application-defaults" resource file, 
which on UNIX systems is usually stored in the directory lusrlliblXlllapp-defaults. For any 
application, the name of this file should be the same as the classname argument to xt- 
Initialize. By convention, this string is the same as the name of the application, with 
the first letter capitalized. If the application name begins with X, the first two letters should 
be capitalized. For xhello this is XHello* 

Example 2-2 shows the contents of the application-defaults file necessary to make xhello dis 
play the string "Hello, World!" instead of the default "hello." 



*Note that existing applications do not always follow this latter convention. For example, the application -defaults 
file for xmh is called Xmh, not XMh. 



36 X Toolkit Intrinsics Programming Manual 



Example 2-2. XHello: the application-defaults file 
*hello. label: Hello, World! 

The name of the widget instance whose string we are setting is hello, and the Label 
widget s resource that sets the string is label. After the colon is the string we want the 
widget to display. The string should not be quoted. White space after the colon is ignored. 

The application-defaults file has the same format as all other resource database files. In brief, 
there are two types of resources: application resources and widget resources. The syntax for 
specifying application resources is simple: 

application _name .resource _name: value 

Widget resources are more complicated, since there may be multiple instances of the same 
widget in an application. As a result, you must specify the name not only of the widget, but a 
pathname starting with the application name and containing the name of each widget in the 
widget hierarchy leading to the desired widget. For example, in the application xhello, the 
complete resource specification for the resource called label for the Label widget called hello 
would be: 

xhello. hello. label: Hello, World! 

To simplify resource specifications, a wildcard syntax may be used, specifying an asterisk 
instead of a dot, and omitting one or more terms of the fully qualified name. For example, as 
we ve shown above: 

*hello. label: Hello, World! 

or since there is no other Label widget in the application, perhaps even: 

*label: Hello, World! 

One possible source of confusion is that the shell widget instance returned by xt- 
Initialize should not be named in resource specifications; part of the behavior of this 
widget class is that it makes its resource name the same as the name of the application (speci 
fied on the command line). If you were to include the widget name: 

xhello. topLevel. hello. label: Hello, World! 

your resource specification would be ignored. Note that the Resource Manager provides no 
error messages, and silently ignores resource specification errors (including syntax errors), so 
they can be difficult to track down. 

You should also be aware that resources, like widgets, have both instances (usually referred 
to simply as their "names") and classes. Class names are often the same as the corresponding 
resource name, but with the first letter of the resource name capitalized. For example, the 
color resource foreground has the class Foreground. In addition, there may be other 
resources (such as the cursor color, border color, and so on) that may also have the class 
Foreground. 

A resource class name applies to all instances of the resource. For example, all resources of 
class Foreground, regardless of where in the application or widget they were found, could 
be set by specifying: 

*Foreground: blue 



Introduction to the X Toolkit 37 



Or the foreground resource in all widgets of the Command widget class could be set by using 
the widget class name in place of the instance name: 

*Command. foreground: blue 

Because resource "instance" names take precedence over class names, however, the devel 
oper could override the class setting with a specific setting for an individual widget resource. 

Note that all resource specifications are given as strings, even though the data required for 
the resource may be of a different type. Xt automatically converts the string found in the 
resource database files into the appropriate destination type. For example, colors are speci 
fied as color names, which are automatically converted to pixel values used to look up the 
closest color available in the colormap for the window. You can also write and add converter 
routines for your own special types. (For example, you might define a "menu" data type, so 
the user could specify the contents of a menu via a resource setting.) Note also that while in 
resource files, users specify the resource name or class as shown above; in any Xt calls from 
source code, you always use symbolic constants of the form 1 xttJresourceName or xtCclass- 
Name (e.g., XtNf oreground or XtCForeground). We ll explain the reason for that 
shortly. 

The complete list of sources for resource database settings, the precedence rules the resource 
manager uses for establishing the actual resource value when there are conflicting settings in 
different database sources, and the mechanics of type conversion, are described in detail in 
Chapter 9, Resource Management and Type Conversion. (See also Chapter 9 in Volume 
Three, X Window System User s Guide.) We ll also be returning to the topic of resources 
with each new example. 



2.3.4 To Hardcode or Not to Hardcode 

There are pros and cons to applications that can be radically customized by the user through 
resources. The pros are quite clear: a flexible application will meet the needs of a wider 
audience. Some of the cons are that a user may make a mistake in the configuration that 
makes the application inoperable in some way. Documentation and technical support 
become much more difficult. A partial solution is to document the default resource specifica 
tions and require that users reinstall those default specifications before a technical support 
person tries to solve their problems. In some cases, dialog boxes can be added that require 
the user to confirm any irreversible actions. 

In any case, you may eventually want to hardcode certain resources in the application so that 
they are not user configurable. This would be done for resources that, if set incorrectly, 
would make your application operate in an unsafe fashion. Hardcoding a resource is done by 
creating an ArgList structure and using it as an argument to the call that creates a widget. 
(This is the function of the two arguments of xtCreateManagedwidget mentioned in 
Section 2.3.1 as unused in xnello.c.) 

This technique is demonstrated later, because you won t need it until the final stages of 
releasing your application. While an application is under development, it is better to leave 
all resources configurable, because this allows you to change them in the application-defaults 



38 X Toolkit Intrinsics Programming Manual 



file without recompiling the source. When the code is stable and almost ready for release, 
then it s time to determine which resources need to be hardcoded. 



2.4 Connecting Widgets to Application Code 

The Toolkit is designed so that the code that implements the user interface and the code that 
implements application features can be kept separate. This is an advantage, because it allows 
either part to be modified without affecting the other. However, these two pieces of code 
need to be intimately connected, because the user interface must drive the application code. 

This section describes the two basic ways of making this connection, using callbacks and 
actions. As mentioned earlier, the general idea of both methods is that the application regis 
ters functions to be called in sequence in response to occurrences within certain widgets. 

The two techniques differ in the way that the registered function is invoked. For callbacks, 
the trigger is an abstract occurrence defined by the widget, which may or may not be event 
related. The routines on a widget s callback list(s) are invoked by the widget code, using a 
call to xtCallCallbacks. Actions, on the other hand, are invoked directly by Xt, as the 
result of an event combination specified by the translations mechanism. 

The two mechanisms also differ in the way they are added to a widget. The application can 
add a callback routine to a widget using xtAddCallback or xtAddCallbacks only if 
the widget has declared a callback list as a resource. Actions, on the other hand, can be 
added to a widget using xtAddActions without the widget s knowledge or consent. 

Despite their differences, it is easy for a beginner to confuse the use of the two mechanisms, 
especially since callbacks are often invoked by widgets from within action routines. For 
example, the Command widget defines a callback resource called xtNcallback and sev 
eral action routines, one of which (notify) simply calls the function pointed to by the Xt 
Ncallback resource. 

When callbacks are called from within predefined widget actions, the most obvious benefit of 
actions, namely access to the high-level syntax of the Translation Manager, also accrues to 
callbacks. This overlap in the use of these two mechanisms can obscure the fundamental dif 
ference in their purpose. 

Callbacks allow widgets to provide hooks for applications to add specific functions. Call 
backs should be used when the widget class has a callback resource for the particular occur 
rence that you want to trigger your function. For example, the Athena Scroll widget defines a 
scrollProc callback to be invoked when the pointer is clicked in the scrollbar, and a 
thumbProc callback to be invoked when the user drags the thumb with the pointer. 

Actions have many uses in the design of widgets, but for applications, their main purpose is 
to add behavior that a widget does not already provide. As noted earlier, though, when work 
ing with a widget set such as Motif or OPEN LOOK that has clearly-defined user-interface 
conventions, adding new behavior to a widget may not be an appropriate thing to do. In 
addition, using actions is somewhat more complex than using callbacks, and actions have no 
advantages over callbacks when an appropriate callback is available. 



Introduction to the X Toolkit 39 



2.4.1 Callbacks 



To illustrate the use of callbacks from the application, we will write an application that uses 
the Athena Command widget This type of widget is also known as a pushbutton; some 
analogue will be present in every widget set. It contains a string or picture, and executes a 
command when a pointer button is clicked on it 

A Command widget calls an application function when you press and release the first pointer 
button (by default) in its window. It also highlights the window border of the Command 
widget when you move the pointer into it When you press and hold the pointer button in the 
Command widget s window, the Command widget redraws the window in reverse video. 
Moving the held button out of the window resets the widget without executing the command. 

The xgoodbye program creates a single Command widget It is very similar to xhello, but 
takes advantage of the callback provided by the Command widget Clicking on the "Good 
bye, Cruel World" button exits the program. 

Figure 2-12 shows the window that xgoodbye creates if you have installed the suggested 
application-defaults file (otherwise, it will display "goodbye"). It is suggested that you com 
pile and run xgoodbye. c, testing its response to moving the pointer in and out of its window, 
and clicking the various pointer buttons on its window. 



I Goodbye, Cruel World!) 



Figure 2-12. The appearance of xgoodbye when the pointer is in the window 

This example is not as frivolous as it seems. Many applications use code identical to this to 
implement their "Quit" button. 

The code forxgoodbye.c is shown in Example 2-3. 

Example 2-3. xgoodbye.c: complete code 

/* 

* xgoodbye.c - simple program to put up a banner on the display 

* and callback an application function. 
*/ 

finclude <stdio.h> 
/* 

* Include files required for all Toolkit programs 
*/ 

finclude <Xll/Intrinsic .h> /* Intrinsics Definitions */ 

#include <Xll/StringDef s .h> /* Standard Name-String definitions */ 

/* 

* Public include file for widgets we actually use in this file. 
*/ 

lifdef X11R3 



40 X Toolkit Intrinsics Programming Manual 



Example 2-3. xgoodbye.c: complete code (continued) 



/* Athena Command Widget */ 

/* R4 or later */ 

/* Athena Command Widget */ 

/* X11R3 */ 



#include <X11 /Command. h> 

telse 

tinclude <Xll/Xaw/Command.h> 

#endif 

/* 

* Quit button callback function 

*/ 

/* ARGSUSED */ 

void Quit (w, client_data, call_data) 
Widget w; 
caddr_t client_data, call_data; 

fprintf (stderr, "It was nice knowing you.Xn"); 
exit (0) ; 



main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, goodbye; 

topLevel = Xtlnitialize ( 
argv[0] , 
"XGoodbye", 
NULL, 
0, 

Sargc, 
argv 



/* Application name */ 

/* Application class */ 

/* Resource Mgr . options */ 

/* number of RM options */ 

/* number of args */ 

/* command line */ 



goodbye = XtCreateManagedWidget ( 

"goodbye", /* arbitrary widget name */ 

commandWidgetClass, /* widget class from Command. h */ 
topLevel, 
NULL, 



parent widget*/ 
argument list */ 
arg list size */ 



XtAddCallback (goodbye, XtNcallback, Quit, 0) ; 

/* 

* Create windows for widgets and map them. 

*/ 

XtRealizeWidget (topLevel) ; 

/* 

* Loop for events. 

*/ 
XtMainLoopO ; 

} 

And here isxgoodbye s application-defaults file: 



Introduction to the X Toolkit 



41 



Example 2-4. XGoodbye: the application-defaults file 
*goodbye . label : Goodbye, Cruel World! 

The differences between xgoodbye and xhello all apply to adding a callback function. In this 
example we have some application code (the Quit function) that we register with Xt as a 
callback function for the widget called goodbye using the xtAddCallback call. 

The Quit function is defined before main, so that we can use the function pointer Quit in 
the XtAddCallback call. It is also possible to declare Quit as a function pointer early in 
the application, but actually to define it further down in the source code. 

The XtAddCallback call used to register Quit as the Command widget s callback is as 
follows: 

XtAddCallback (goodbye, XtNcallback, Quit, 0) ; 

The first argument, goodbye, is the widget that is to trigger the callback. The second argu 
ment, XtNcallback, is a symbolic constant that identifies which of the widget s callback 
resources is being set (This constant, like most resource names defined by Xt, is defined in 
the file <XlllStringDefs.h>. Additional resource names are often defined by an individual 
widget s public include file.) In this particular case, the name XtNcallback does not shed 
any light on the real purpose of the callback. A better name would have been xtNnot if y- 
Callback or XtNcommandCallback. All widgets also have the callback xt- 
NdestroyCallback, which is called when the widget is destroyed. Scroll widgets often 
have at least two callbacks in addition to xtNdestroyCallback; in the Athena set these 
are called xtNscrollProc and xtNthumbProc, and they are called, respectively, 
when the user clicks in the scroll area or drags the thumb. 

The third argument of XtAddCallback is the function the widget is to call, and the last 
argument is any data to be passed to the callback function. No data is to be passed to Quit. 

The Quit function itself, like all callback functions, takes three arguments: 
void Quit(w, client_data, call_data) 

The first argument is the widget that triggered the callback, as specified as the first argu 
ment in XtAddCallback. You would use the value of this argument in your callback 
function if you registered the same function as a callback for two different widgets, and if 
you wanted to distinguish in the callback which widget called it 

The second argument, client_data, is the value passed as the last argument of Xt 
AddCallback. This can be any data that you need in the callback function. 

The third argument, call_data, is a piece of data passed from the widget. Some 
classes of widget set this argument, but others do not The documentation for the widget 
will specify the contents of this data if it is used. The Command widget doesn t provide 
any call_data, but the Scroll widget, for example, passes back the current position of 
the thumb. 

If you are intentionally not going to use one or more of these arguments, you should place the 
comment /*ARGSUSED*/ on the line before the function. This prevents the C program 
checker lint from complaining about the unused arguments. See the Nutshell Handbook 
Checking C Programs with lint for more details. By convention, callback function names 



42 X Toolkit Intrinsics Programming Manual 



(and as you will see, action function names as well) are capitalized. This lessens the chance 
of collision with other variables names because callback functions are global in the source 
file. The most common collision is between callback functions and widget IDs of type 
widget. It is tempting to call the quit callback function quit, and also to call the quit 
widget quit, but this will result in mysterious errors or a core dump. If you follow the con 
vention that callback functions are given a capitalized name, such as Quit, you avoid this 
problem. 



2.4.2 Actions 



The second way of connecting an application with a widget is using actions. Actions are 
most appropriate for adding minor features to an existing widget when the widget does not 
provide a callback that you want, or for building an application window by adding features to 
a Core widget.* 

A simple example that shows the power of actions is to replace the Quit callback function 
shown in Example 2-2 with two separate quit actions, one of which prompts the user for con 
firmation, the other of which does not As separate actions, these functions can be configured 
to respond to different events. Ideally, we d like to emulate the Macintosh user-interface 
semantic, which allows a single click to select a button, which is then confirmed by a carriage 
return in response to a dialog box, while a double click performs the button s action right 
away, without confirmation. However, the way the Translation Manager interprets event 
sequences, you cannot specify both a single and double click for the same widget if you want 
them to execute mutually exclusive functions (i.e., unless you don t mind the single-click 
action being executed in addition to the double-click action whenever you double click). 

Instead, we ll have the confirm action respond to a click of the first pointer button, and quit 
without confirmation in response to the second. 

Here s the complete code for xfarewell.c. 

Example 2-5. xfarewell.c: complete code 

/* 

* xfarewell.c - simple program to provide a Command widget that 

* performs a different action in response to a 

* click of the first and second pointer buttons. 
*/ 

tinclude <stdio.h> 



* Usually, when a widget does not provide a certain callback, it also does not provide various other characteristics that 
you want For example, to make the Label widget work like Command (assuming the Command widget didn t al 
ready exist), you would have to make it accept more kinds of input, add the drawing code to highlight the border and 
draw the text in reverse video, and add the ability to call an application function. All this can be done with actions, 
but it would take a lot of work. What makes it difficult is that your code may interact with the widget s code in un 
pleasant ways. When the changes are so major, it makes more sense to create a new widget subclass, which shares 
some characteristics and code with its superclass. As we will see, that is exactly how Command is implemented, as a 
subclass of Label. The Core widget, on the other hand, has no input or output semantics at all, and therefore is 
simpler to add actions to without conflict We ll demonstrate a simple feature addition here, and demonstrate the use 
of the Core widget in Chapter 4, An Example Application. 



Introduction to the X Toolkit 



Example 2-5. xfarewell.c: complete code (continued) 

/* 

* Include files required for all Toolkit programs 
*/ 

#include <Xll/Intrinsic .h> /* Intrinsics Definitions */ 

tinclude <Xll/StringDef s .h> /* Standard Name-String definitions */ 

/* 

* Public include file for widgets we actually use in this file. 
*/ 

tifdef X11R3 

finclude <X1 I/Command. h> /* Athena Command Widget */ 

#else /* R4 or later */ 

#include <Xll/Xaw/Command.h> /* Athena Command Widget */ 

#endif /* X11R3 */ 

/* 

* Confirm action 
V 

/*ARGSUSED*/ 

static void Confirm (w, event) 

Widget w; 

XButtonEvent *event; 

/* following action args not used: 

* String *params; 

* Cardinal *num_params; 
*/ 

{ 
/* 

* Once we show how to do it, we could pop up a dialog box to do this. 

* Since we haven t yet, simply print a message to stderr. 
*/ 

fprintf (stderr, "Are you sure you want to exit?\n\ 

Click with the middle pointer button if you re sure.Xn") 
} 

/* 

* Quit action 
*/ 

/*ARGSUSED*/ 

static void Quit (w, event, params, num_params) 

Widget w; 

XButtonEvent *event; 

String *params; /* unused */ 

Cardinal *num_params; /* unused */ 

{ 

fprintf (stderr, "It was nice knowing you.\n"); 

exit (0) ; 
} 

main (argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, farewell; 

static XtActionsRec two_quits [ ] = { 
{"confirm", Confirm}, 
{"quit", Quit}, 



44 X Toolkit Intrinsics Programming Manual 



Example 2-5. xfarewell.c: complete code (continued) 



}; 

topLevel = Xtlnitialize ( 

argv[0], / 

"XFarewell", / 

NULL, / 

0, / 

&argc, / 

argv / : 



Application name */ 
Application class */ 
Resource Mgr . options 
number of RM options 
number of args */ 
command line */ 



farewell = XtCreateManagedWidget ( 



} 



"farewell", 

commandWidget Class, 

topLevel, 

NULL, 





/* arbitrary widget name */ 

/* widget class from Command. h */ 

/* parent widget*/ 

/* argument list */ 

/* arg list size */ 



XtAddActions (two_quits, XtNumber (two_guits) ) 

/* 

* Create windows for widgets and map them. 
*/ 

XtRealizeWidget (topLevel) ; 

/* 

* Loop for events. 
*/ 

XtMainLoop ( ) ; 



In Example 2-3 above, we have dispensed entirely with the use of the Command widget s 
callback. Instead, we have implemented two separate application functions, Confirm and 
Quit, that will be registered as actions of the Command widget. To make the actions avail 
able, you must declare an actions table, which maps function pointers to strings that the user 
can reference in a translation table. 

You must register the actions table with Xt by calling XtAddActions. (The XtNumber 
call counts the number of entries defined in the actions table you will see this macro often.) 
You should also create a default translation table and store it in the application-defaults file. 

2.4.2.1 The Actions Table 

The format of an Actions Table is defined as follows: 

typedef struct _XtActionsRec { 

char *string; 

XtActionProc proc; 
} XtActionsRec; 

By convention, the string and the function name are identical, except that the function name 
should begin with an upper-case letter, as in the following example: 



Introduction to the X Toolkit 



45 



static XtActionsRec two_quits [ ] = { 

{"confirm", Confirm}, 

{"quit". Quit}, 
}; 

This mapping from strings to function pointers is necessary to allow translation tables to be 
specified in resource files, which are made up entirely of strings. 

2.4.2.2 Format of an Action Procedure 

An xt Action? roc is just a function with four arguments: a widget, an event, a string con 
taining any arguments specified for the action, and the number of arguments contained in the 
string. The purpose of the last two arguments will be described later. When you don t pass 
any arguments, you can call your action function with only the first two arguments, as shown 
in Example 2-6. 

Example 2-6. An XtActionProc with widget and event arguments 

/*ARGSUSED*/ 

static void Confirm (w, event) 

Widget w; 

XButtonEvent *event; 

{ 

/* 

* Once we show how to do it, we can pop up a dialog box to do 

* this. Since we haven t yet, simply print a message to stderr. 

II */ 

fprintf (stderr, "Are you sure you want to exit?\n\ 

Click with the middle pointer button if you re sure.\n"); 
} 

If the additional arguments are declared, but not used, you should be sure to include the lint 
comment /*ARGSUSED*/. 

One major difference between an action function and a callback function is that action func 
tions are called with an event as an argument, while actions do not have the client_data 
or call_data arguments present for callback functions. This means the only way to pass 
application data into an action function is through global variables. The presence of the 
event argument means that you can use the contents of the event structure in the action func 
tion. However, be aware that if you are allowing user configuration of the translation table, 
an action may be called with different kinds of events. You should at least check the event 
type in the action routine and print an appropriate message if the user has arranged to call the 
action with the wrong type of event We ll show how to do this in Chapter 7, Events, Trans 
lations, and Accelerators. 



46 X Toolkit Intrinsics Programming Manual 



2.4.2.3 The Translation Table 

Actions are global to an application. But even so, a widget uses actions only when config 
ured to do so, using a translation table resource, XtNtranslations. 

Every widget that has actions also has a translation table that maps event combinations into 
those actions. The application can override, augment, or replace this table to make a widget 
call application-registered actions instead of or in addition to the widget s own actions. Reg 
istering actions with xtAddActions makes them eligible for inclusion in translation 
tables. 

Each line of a translation table maps a sequence of events to a sequence of actions. The 
entire translation table is simply a string consisting of one or more event specifications in 
angle-brackets, with optional modifiers, followed by a colon and a function name string 
defined in an action table. Multiple translations are specified as part of the same string. By 
convention, the string is continued on several lines, one for each translation, with each line 
except the last terminated with a linefeed (\n) and a backslash (\). 

We ll describe the details of event specification and other aspects of translation table syntax 
in Chapter 7, Events, Translations, and Accelerators. For now, an example should get the 
point across quite clearly. 

The default translations for the Command widget are as follows: 

<EnterWindow>: highlight () \n\ 

<LeaveWindow> : reset () \n\ 

<BtnlDown>: set() \n\ 

<BtnlUp>: notify () unset () 

That is to say, when the pointer enters the widget, the widget s highlight action will be 
called (this function darkens the border of the widget); when the pointer leaves the window, 
the widget will be reset to its original state. On button 1 (the left-most pointer button) 
being pressed, the widget s set action displays it in reverse video; on button up, the 
widget s notify action (which simply calls the application function pointed to by the xt- 
Ncallback resource) will be activated, and the unset action will return the widget to its 
normal appearance. Note that unset () and notify () are both called on the last line: 
more than one action can be called in response to a single event or event combination. 

Example 2-7 shows the application-defaults file for xfarewell, which modifies this default 
translation table. 

Example 2-7. XFarewell: the application-defaults file 

*farewell . label : Click on me. 
*farewell .translations : #override\n\ 

<BtnlDown>, <BtnlUp> : confirm ( ) \n\ 

<Btn2Down>: set()\n\ 

<Btn2Down>,<Btn2Up>: quit() 

The resource set here is translations. (This resource has the same name for all widg 
ets.) The string-to-translation-table resource converter recognizes one of three directives, 
beginning with # on the first line, which tells how to handle existing translations (either set as 
widget defaults, or in other resource database files): 



Introduction to the X Toolkit 47 



# replace (the default if no directive is specified) says simply to replace the old trans 
lations with the current table. 

# augment says to merge the new translations into the existing translation table, but not 
to disturb any existing translations. If a translation already exists for a particular event, 
the conflicting translation specification in a table beginning with #augment is ignored. 

# over ride says to merge the new translations into the existing translation table, 
replacing old values with the current specifications in the event of conflict. 

We used ^override because this allows us to keep the translations for <EnterWindow> 
and <LeaveWindow> events in place. In addition, the Command widget s set and 
unset actions will also remain in effect for <BtnlDown> and <BtnlUp>. (For more 
details on why these aren t overridden by the new translations, see Chapter 7, Events, Trans 
lations, and Accelerators.) 

The translation: 

<BtnlDown>,<BtnlUp>: confirm () 

specifies that the confirm action should be called in response to a pair of events, namely a 
button press followed by a button release, with no other events intervening. 

The translations: 

<Btn2Down> : set ( ) \n\ 

<Btn2Down>,<Btn2Up>: quit{) 

specify that the Command widget s internal set action should be invoked by pressing but 
ton 2, and that our own quit action should be invoked by clicking button 2. Note that we 
don t bother to bind the Command widget s unset action to <Btn2Up>, since the 
application will disappear as a result of the quit action. (The unset action is still used 
when the user presses button 2 and then moves the pointer outside the widget before releas 
ing button 2. This is one of Command s default bindings that we have not overridden.) If we 
were using the widget for any other purpose, we would map <Btn2Up> to unset, so that 
the widget was restored to its normal appearance when our own action was completed. 

2.4.2.4 Hardcodlng Translations 

There are cases in which an application may want not only to specify translations in an 
application-defaults file, but also to hardcode them into the application. When you specify 
translations only in the application-defaults file, the user has unlimited configurability; if the 
default translations are deleted or changed beyond recognition, the application may no longer 
work. 

Three Xt functions are used for setting translation tables from the application code: 

xtParseTranslationTable is used to compile a string translation table into the 
opaque internal representation XtTranslations. (For translations specified in 
resource files, this conversion is performed automatically by a resource converter.) 

Xt Augment Translations is used, like the #augment directive in a resource file, 
to nondestructively merge translations into a widget s existing translations. 



48 X Toolkit Intrinsics Programming Manual 



XtOverrideTranslations is used, like the #override directive in a resource 
file, to destructively merge translations into a widget s existing translations. 

Both XtAugmentTranslations and XtOverrideTranslations take as argu 
ments a widget and a compiled translation table returned by xtParseTranslation- 
Table. 

There is no function to completely replace a widget s translations; however, you can do this 
by calling xt Set Values, the general routine for setting resources (whose use is demon 
strated later in this chapter) to set the value of a widget s xtNtranslations resource to 
a compiled translation table returned by xtParseTranslationTable. 

To set the same translations specified in the application-defaults file from the application 
itself, we would have used the following code: 

Example 2-8. Code Fragment: specifying translations in the program 

static char defaultTranslations [ ] = "#override\n\ 
<BtnlDown>, <BtnlUp> : confirm ( ) \n\ 
<Btn2Down>: set()\n\ 

<Btn2Down>,<Btn2Up>: quit() n ; 

XtTranslations mytranslations; 



mytranslations = XtParseTranslationTable (defaultTranslations) ; 
XtOverrideTranslations (farewell, mytranslations) ; 

As mentioned earlier, you will find it more convenient to place the translation table in the 
application-defaults file until the last minute, because this allows changes without recompil 
ing the source. 



2.5 More About Resources 

You now have read about enough techniques to construct an application that uses widgets for 
its user interface and connects the widgets to application code. However, in order to really 
take advantage of any widget class, you have to learn about its resources, so that you can set 
the desired resources in the application-defaults file. 

A class defines its own resources, and also inherits the resources of all its superclasses. For 
example, Command supports not only its own resources but also the resources of its super 
classes, Label and Core. The documentation for a widget class may describe only the 
resources for that class and list the name of the superclass (which you can then look up), or it 
may list all the resources of that class and all superclasses. 



Introduction to the X Toolkit 



2.5.1 Setting and Getting Resources from the Application 

The application can change resources of existing widgets. This can be very useful, but you 
should be aware that setting a resource from the application wipes out the user-specified 
value for that same resource (if any), unless you first query the resource, and then set it based 
on its earlier value. This section describes first how to set resources and then how to get 
them. 

To set and get resources, you use the Xt functions xtSet Values and xtGetValues. 
Each of these functions takes three arguments: a widget, an array of Arg structures in which 
the resource name/value pair are stored, and a count of the number of argument pairs in the 
array. 

Setting resources is often used for resetting strings in Label widgets. Example 2-9 shows the 
code needed to change the string of a Label widget this will work any time after the widget 
has been created, either before or after the widget is realized. 

Example 2-9. Code fragment to set a widget resource 

Arg arg; 

static String new_label = "Hi there." 



XtSetArg(arg, XtNlabel, new_label) ; 
XtSetValues (w, &arg, 1); 

There are several things in this code segment likely to be new to you. The types Arg and 
String are defined in <X11 /Intrinsic. h>. String is defined as char *, and Arg is 
defined as a structure containing the name and value pair that defines a resource: 

typedef struct { 

String name; 

XtArgVal value; 

} Arg, *ArgList; 

The definition of XtArgVal differs depending on architecture its purpose is precisely to 
make code portable between architectures with different byte sizes. Its use in application 
code will be demonstrated in Section 3.7.1. xt Set Arg is a macro that makes it more con 
venient to set the two members of the Arg structure. If desired, you can also set the Arg 
structure members like any other C structure by using the . or -> syntax. 

Note that the first member of Arg is of type String, yet in Example 2-9 that string was 
specified in xt Set Arg using the symbolic constant XtNlabel. The resource name and 
class are stored in symbolic constants to improve compile-time checking. If you misspell a 
symbolic constant, the compiler will note the error. If you misspell a string, on the other 
hand, the error would go unnoticed by the compiler and cause a run-time error such as a core 
dump. Therefore, all resource names are specified using constants of the form xtN/iame, 
where name is the resource name. The include file <XlllStringDefs.h> and the public 
include files for each widget (such as <X1 II Label. h>) contain the resource name constant 
definitions. 



50 X Toolkit Intrinsics Programming Manual 



xtSetValues is the call that actually changes the widget resource. You pass it the widget 
to be reconfigured, a list of Arg structures, and the length of the list. Example 2-9 sets only 
one resource, so the list length is 1. 

XtSetValues can set any number of resources of a single widget instance. Example 2-10 
shows the code necessary to set two resources. 

Example 2-10. Code fragment to set multiple resources of a widget 

static String new_label = "Hi there." 
Arg args [3] ; 
int i; 



i = 0; 

XtSetArg(args[i] , XtNwidth, 100); 
XtSetArg(args[i] , XtNlabel, new_label) 
XtSetValues (w, args, i); 

Note that the counter i cannot be incremented inside the xt Set Arg macro, because that 
macro references its first argument twice. Therefore, it is customarily incremented on the 
end of the same line, so that additional resource settings can easily be added. 

It is also useful to be able to get the current value of a widget resource. Perhaps the most 
common use of this is to get the current size or position of a widget Another use is in finding 
out what value the user has specified for a particular resource. Because C-language argu 
ments are passed by value, and some resource values are not single values but strings or func 
tion pointers, it is a little more difficult to get widget values than to set them. Example 2-11 
shows how to get a pointer to the current string in a Label widget 

Example 2-11. Code fragment to get a widget resource 
tdefine MAXLEN 256 



Widget hello; 

Arg arg; 

char userstring [MAXLEN] ; 

char *p; 



/* Label widget named hello created here. */ 
XtSetArg(arg, XtNlabel, &p) ; 
XtGetValues (hello, &arg, 1); 
strcpy (userstring, p) ; 

The Xt Set Arg call sets the XtNlabel argument in the argument list to a pointer to the 
application variable p (which itself is a pointer), and then XtGetValues is called, which 
sets the pointer p to point to the widget s resource. The result is that the application knows 
the value of p and p points to the resource. 



Introduction to the X Toolkit 5 1 



This code may seem nonintuiti ve. However, since this method is the same for any resource, 
you can just remember it or look it up even if you don t understand it 

Note however that some resources are not designed to be queried. For example, translation 
tables and callbacks are compiled into an internal representation, so it is pointless to try to 
read them. 



2.5.2 Core Resources 



All widgets are subclasses of Core. Therefore, the resources of the Core class are available 
for all widgets. Table 2-1 shows the Core resources. 

For each resource, both name and class strings are defined. Class strings are often the same 
as the corresponding resource name string, but with the prefix xtc instead of xtN, and with 
the first letter of the resource name capitalized. 

The use of resource classes allows the user or the application programmer to specify that all 
resources of a particular type be given the specified value. 

Table 2-1. Core resources 



Name 


Class 


Type 


Default 


XtNx 


XtCPosition 


Position 





XtNy 


XtCPosition 


Position 





XtNwidth 


XtCWidth 


Dimension 





XtNheight 


XtCHeight 


Dimension 





XtNscreen 


XtCScreen 


Pointer 


from 








DISPLAY 


XtNcolormap 


XtCColormap 


Pointer 


from 








parent 


XtNdepth 


XtCDepth 


int 


from 








parent 


XtNbackground 


XtCBackground 


Pixel 


White 


XtNbackgroundPixmap 


XtCPixmap 


Pixmap 


NULL 


XtNborderWidth 


XtCBorderWidth 


Dimension 


1 


XtNborderColor 


XtCBorderColor 


Pixel 


Black 


XtNborderPixmap 


XtCPixmap 


Pixmap 


NULL 


XtNtranslations 


XtCTranslations 


Xt Translations 


NULL 


XtNaccelerators 


XtCAccelerators 


Xt Translations 


NULL 


XtNmappedWhenManaged 


XtCMappedWhenManaged 


Boolean 


TRUE 


XtNdestroyCallback 


XtCCallback 


Pointer 


NULL 


XtNsensitive 


XtCSensitive 


Boolean 


TRUE 


Xt Nance storSensitive 


XtCSensitive 


Boolean 


TRUE 



The fact that size and position are resources of all widgets means that your application- 
defaults file can control the layout of the application. You should always resize widgets by 



52 



X Toolkit Intrinsics Programming Manual 



setting these resources never resize or move a widget s window using Xlib calls since this 
would make Xt s knowledge of window geometries inaccurate. Nor should you use the Xt 
functions XtConf igureWidget, XtMoveWidget, or XtResizeWidget from the 
application. These routines are intended to be used only by geometry-managing composite 
widgets. 

The XtNscreen, XtNcolormap and xtNdepth resources hold the default screen, 
colormap, and depth (the number of bits per pixel used for indexing colors in the colormap). 
The top-level shell widget gets the screen from the DISPLAY environment variable or 
-display command line option; other widgets inherit that value and cannot change it. The 
top-level shell widget gets the root window s depth and default colormap; other widgets 
inherit their parent s depth and colormap, so unless an intervening widget has set a different 
depth or colormap, a widget should have the root window s depth and colormap by default. 

The XtNbackground, XtNbackgroundPixmap, XtNborderWidth, Xt- 
NborderColor, xtNborderPixmap widget resources control the background and bor 
der of the window created by a widget The background and border of a window are main 
tained by the X server, and setting these resources causes an immediate change in the win 
dow on the screen. You can set either a background color or a background pixmap, but not 
both. Whichever is set later takes priority. The same applies to the border. 

A pixmap is similar to a window but is off-screen. It is an array of pixels. When used as a 
background or border, a pixmap is tiled by laying out multiple copies of it side by side, for 
the purpose of patterning. Pixmaps are also used for icon patterns, in drawing, and as a tem 
porary drawing surface later copied to a window. 

The XtNbackground and xtNborderColor resources can be set using either a color 
name string or a hexadecimal color specification. (See Appendix C, Specifying Fonts and 
Colors, for more information on acceptable forms of color specification.) 

The value of the XtNbackgroundPixmap and XtNborderPixmap resources should 
be a pathname to a file containing the bitmap, or to a bitmap created in your program. On 
UNIX systems, standard X bitmaps are stored in the directory /usr/include/XU /bitmaps. See 
Appendix F in Volume Three, X Window System User s Guide, for information on these stan 
dard bitmaps. 

xtNtranslations is the resource that contains the translation table described in Section 
2.4.2 above. As we demonstrated there, by setting this resource you can change the events 
that trigger a widget s actions or the actions your application has registered, xt- 
Naccelerators contains an accelerator table. (Accelerators are an extended form of 
translations that allow events in one widget to be bound to actions in another.) 

xtNmappedWhenManaged is a resource used by geometry-managing widgets to specify 
whether a widget should be eligible for display (i.e., mapped to the screen) as soon as it is 
placed under parental geometry management, or whether this should not happen until some 
later time. We ll talk more about this concept in Chapter 11, Geometry Management. 

The xtNdestroyCallback resource, as described in Section 2.4.1 above, lets you pro 
vide an application function to be called when a widget is destroyed. This is infrequently 
used, since the Toolkit normally handles the job of freeing widget data structures and any 
server resources. 



Introduction to the X Toolkit 53 



The xtNsensitive resource controls whether a widget responds to user input. This 
allows you to turn on or off user input in a certain widget at will. For example, if you have a 
Command widget whose command is not allowed at certain times, you would set xt 
Nsensitive to FALSE during the period the command is not allowed. The Command 
widget changes its own look to indicate that it is invalid. 

The XtNancestorSensitive resource specifies whether the widget s parent (or earlier 
ancestor) is sensitive. Sensitivity is propagated downward, such that if any ancestor is insen 
sitive, a widget is insensitive. This resource will often be hardcoded by the application, since 
if set incorrectly by the user, it could make the application inoperable. 

2.5.3 Other Inherited Resources 

Besides the resources inherited from Core, a widget inherits resources from each of its super 
classes. For example, the Command widget used in xfarewell inherits resources from the 
Label widget class. As shown in Table 2-2, these include, in addition to the label itself, a 
font, a foreground color, spacing above and below the string, and a value specifying how the 
string should be placed in the widget (Note that this list is not complete. There are other 
resources not shown.) 

Table 2-2. Label resources 



Name 


Class 


Type 


Default 


XtNfont 


XtCFont 


XFontStruct* 


XtDefaultFont 


XtN foreground 


XtCForeground 


Pixel 


Xt Default Foreground 


XtNinternalHeight 


XtCHeight 


Dimension 


2 


XtNinternalWidth 


XtCWidth 


Dimension 


A 


XtNjustify 


XtCJustify 


XtJustify 


XtJustifyCenter 


XtNlabel 


XtCLabel 


String 


NULL 



It is a worthwhile exercise to experiment with the resources available to an application 
through its widgets, even with such a simple example as xgoodbye or xfarewell . For 
example, consider the resource settings for xfarewell shown in Example 2-12.* 

Example 2-12. Alternate resource settings for xfarewell 

i 

! Core resources 
i 

! The following two lines don t work, but demonstrate a point 
*farewell.x: 100 
*farewell.y: 100 

! Even though it syntactically applies to all widgets in the 
! application, the borderWidth resource is only used by the 



*See Appendix C, Specifying Fonts and Colors, for more information on the font resource specification shown in the 
example. 



54 



X Toolkit Intrinsics Programming Manual 



Example 2-1 2. Alternate resource settings for xfarewell (continued) 

! Shell widget, 
t 

*borderWidth: 10 

*farewell. width: 200 

*farewell. height : 100 

* farewell. background? ixmap: /usr/include/Xll/bitmaps/root_weave 

*f arewell . translations : #override\n\ 

Shift <BtnlUp>: quit()\n\ 

<BtnlDown>,<BtnlUp>: confirm () 

! Label resources 
i 

*f arewell . foreground: white 

*farewell.font : helvB024 

*f arewell. label: Click on me. 

Note that an exclamation point (!) in column zero begins a comment line in a resource file. 

These settings can either be placed in an Xdefaults file in your home directory, or you can 
save them in any file you like and load them into the server using the xrdb client, as follows: 

xrdb -merge resource_file 

(If you want to repeat the experiment with different values, you should be aware that once 
resources are set with xrdb, they remain in effect. Subsequent invocations of xrdb -merge 
will replace settings for the same resources, but won t remove any others that were set 
before. To start with a clean slate, use xrdb -load instead. Note, however, that this will 
replace all of your resource settings, including those for other applications. See Chapter 9 of 
Volume Three, X Window System User s Guide, for more information on using xrdb. See 
Chapter 9 of this book for more information on other possible sources of resource settings.) 

The window that results when you run xfarewell with these resource settings is shown in Fig 
ure 2- 13. 

If you spend some time playing with different resource settings, you will find some unex 
pected behavior. For instance, setting the value of the x and y resources has no effect. 
Regardless of their value, the xfarewell application is simply placed at the current pointer 
position. 

The reason for this is that these resources set the widget position relative to its parent, and 
since the farewell widget is a child of an identically sized Shell widget, they are mean 
ingless. In its geometry-management policy, the shell widget ignores the value of these 
resources. 

If instead you use the x and y resources to try to set the position of the application: 

xfarewell.x: 100 
xfarewell.y: 100 

they are ignored also, for a similar reason. It is customary for the window manager to assert 
control over the position of the main application window (in this case the farewell 
widget), and take the value of these resources, whether set by the application or by the user, 
simply as "hints" to the desired behavior. There is no guarantee that the window manager 
will honor these hints. The application is generally free to move widgets within its own 



Introduction to the X Toolkit 55 




Figure 2-13. xfarewell run with new resource settings 

window, but not to move itself. The basic X philosophy is that the user (through the window 
manager), not the application, should be in control. (Kill the window manager, or run a win 
dow manager than honors application position hints, and the resource specifications shown 
just above will work.) 

Likewise, you will find that specifying: 

*farewell.borderWidth: 10 

has no effect, while: 

*borderWidth: 10 

does. The reason for this behavior is that while the Command widget inherits the border- 
width resource, it does nothing with its value. Only top-level shell widgets use the 
borderwidth resource to set the border width of their window. Just because a resource is 
inherited by a widget does not mean that the widget s methods do anything to use its value. 

Another surprising fact is that once you set the foreground resource to white, the Com 
mand widget s set action, which highlights the widget s border, no longer appears to work. 
This is because the highlighting is done by drawing in the foreground color (now white), 
while the unhighlighting is drawn in the background color (also still white, despite the use of 
the background pixmap for the body of the window). To make highlighting work, you must 
make sure that the foreground and background colors are different. Adding the line: 

*farewell .background: black 
will do the trick. 



56 



X Toolkit Intrinsics Programming Manual 



The cautionary point is that there may be unexpected interactions between resources in 
widget code. Like programs in general, widgets do what you say, not what you mean. A 
well-designed widget will minimize ill effects, but given the amount of customization that is 
possible, it may take some time to uncover all the possible pitfalls. Unfortunately, the docu 
mentation for most existing widgets doesn t always do a good job of explaining how 
resources are used inside the widget. 



Introductbn to the X Toolkit 



57 



3 



More Widget 
Programming Techniques 



This chapter describes how to use some of the more complex widgets found 
in applications, including composite widgets, constraint widgets, and pop ups. 
It also describes how to define application resources and command-line 
options, and how to hardcode the value of widget resources when you create 
a widget. 

In This Chapter: 

Using Composite Widgets 61 

Setting Resources for an Instance Hierarchy 63 

Geometry Management in Practice 65 

Using Constraint Widgets 67 

Using Pop Ups 70 

More About Callbacks 77 

Passing Data to Callback Functions 77 

Callback Lists 79 

Application Resources 80 

The Application Data Structure 81 

The Resource List 81 

Getting the Resources 85 

Command-line Options 86 

Standard Command-line Options 86 

Defining Your Own Command-line Options 88 

Preventing User Customization of Widget Resources 91 

The Argument List 92 

Another Way to Set Arguments 93 

Merging Argument Lists 95 

The Varargs Interfaces 95 

Application Contexts 97 

Xtlnitialize Equivalents 98 



3 

More Widget Programming Techniques 



The techniques described in Chapter 2, Introduction to the X Toolkit, will get you started on 
the path to writing applications. But there are more tools at your disposal. This chapter 
describes the following techniques: 

How to use composite widgets to create a hierarchy of widgets in an application. This 
section describes how to use different kinds of composite widgets so that the application 
can be resized and still look good. It also shows how to set resources for a widget hier 
archy in the application defaults file. 

How to use pop-up widgets such as dialog boxes and menus. 

How to use callback lists (instead of single callback functions), and how to pass data to 
callback functions. 

How to make your applications easier for the user to customize by defining application- 
specific resources and command-line arguments. 

How to hardcode the value of resources when you create a widget. 

How to use application contexts, which you must use to make applications portable to 
some systems. 



3.1 Using Composite Widgets 

The examples in Chapter 2, Introduction to the X Toolkit, were atypical because they con 
tained only one widget. Any real application has several widgets, and therefore needs some 
way of laying them out in case the application is resized. Therefore, the first widget you cre 
ate after calling xt Initialize is usually a composite widget, whose job it is to manage 
the layout of a group of child widgets. The parent of this composite widget is the Shell 
widget created by xtlnitialize, usually called topLevel. 

Example 3-1 shows a small application, xboxl, that creates two Command widgets contained 
in a Box widget. 



More Widget Programming Techniques 



Example 3-1. xboxl.c: complete code 

/* 

* xbox.c - simple button box 
*/ 

/* 

* So that we can use fprintf: 
*/ 

#include <stdio.h> 

/* 

* Standard Toolkit include files: 
V 

#include <Xll/Intrinsic ,h> 
#include <Xll/StringDef s ,h> 

/* 

* Public include files for widgets used in this file. 
*/ 

#ifdef X11R4 

tinclude <Xll/Xaw/Command.h> 

#include <Xll/Xaw/Box.h> 

#else 

tinclude <X1 1 /Command .h> 

#include <Xll/Box.h> 

tendif /* X11R4 */ 

/* 

* quit button callback function 
*/ 

/*ARGSUSED*/ 

void Quit (w, client_data, call_data) 

Widget w; 

caddr_t client_data, call_data; 

{ 

exit (0) ; 
} 

/* 

* "Press me!" button callback function 
*/ 

/*ARGSUSED*/ 

void PressMe(w, client_data, call_data) 

Widget w; 

caddr_t client_data, call_data; 

{ 

fprintf (stderr, "Thankyou ! \n") ; 
} 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget box, quit, pressme, topLevel; 

topLevel = Xtlnitialize ( 

argv[0], /* application name */ 

"XBoxl", /* application class name */ 

NULL, /* application resources (not used) */ 

0, /* application resource count */ 

Sargc, /* command line argument count */ 



62 X Toolkit Intrinsics Programming Manual 



Example 3-1. xboxl.c: complete code (continued) 

argv) ; /* command-line string */ 

box = XtCreateManagedWidget ( 

"box", /* widget name */ 

boxWidgetClass, /* widget class */ 

topLevel, /* parent widget*/ 

NULL, / 

/: 



argument list*/ 
arglist size */ 



quit = XtCreateManagedWidget ( 

"quit", /* widget name */ 

commandWidgetClass, /* widget class */ 
box, /* parent widget*/ 

NULL, / 

/ 



argument list*/ 
arglist size */ 



pressme = XtCreateManagedWidget ( 



"pressme", 
commandWidget Class , 
box, 

NULL, 




/* widget name */ 

/* widget class */ 

/* parent widget*/ 

/* argument list*/ 

/* arglist size */ 



XtAddCallback (quit, XtNcallback, Quit, 0) ; 
XtAddCallback (pressme, XtNcallback, PressMe, 0); 

XtRealizeWidget (topLevel) ; 
XtMainLoop ( ) ; 

Example 3-1 creates a Box widget called box as a child of topLevel, and then creates 
each Command widget as a child of box. Notice how the parent argument of each genera 
tion of widgets is used. Also notice that the Shell widget topLevel is exactly the same 
size as box and therefore is not visible. 

If your application creates many children for a single widget, it may be preferable to create 
the children with xtCreateWidget, and then manage all the children of that parent with 
a single call to XtManageChildren (instead of calling XtCreateManagedWidget 
for each child). 



3.1.1 Setting Resources for an Instance Hierarchy 

You have already seen how an application-defaults file can set the string for a Command 
widget However, xboxl contains two Command widgets, and a widget instance hierarchy 
that also includes a Box widget It is worth seeing how to set the Command widget labels in 
this new situation. (We will be returning often to the subject of setting resources, because it 
is so important to Toolkit programming. Each time, new ideas will be presented.) 



More Widget Programming Techniques 



63 



Example 3-2 shows an application-defaults file forxboxl. 

Example 3-2. XBoxl: application-defaults file 

*pressme*label : Press Me 

*quit*label: Quit 

*Command*background: green 

! The following entry would place the buttons side by side, regardless 

! of font. No setting makes the box wider than all children side by 

! side or narrower than the widest child. 

!*box. width: 1000 

Figure 3-1 shows how the application looks on the screen. 



Quit 






Press Me 



Figure 3-1. xboxl: appearance on the screen 

When an application contains multiple widgets of the same class, resource specifications can 
either identify individual widget instances by name or can use wildcards or widget class 
names to reference more than one widget The first two entries in the example identify the 
pressme and quit widgets by instance name. The third entry uses the class name Com 
mand to set the background of both Command widgets (but not the Box widget) to the color 
green. This line shows that resources of groups of widgets can be set at the same time. (The 
second asterisk in each specification is equivalent to a dot, because an asterisk matches zero 
or more intervening instances or classes.) Because we ve used the class name, the back 
ground color of all Command widgets in the application, even ones we add later, will be 
green. To make the Box widget green as well, we could have used an even more general 
specification such as *background: green. 

Note that you need to know the instance name for each widget in the application in order to 
set its resources individually. This is true for all resource files, including the ones customized 
by the user. Therefore, in the documentation for your application, be sure to include the 
name and class of each widget in your instance hierarchy. To be thorough, also include a 
description of the resources of each class, and specify which resources the user can custom 
ize. 

The first argument of each xtCreateManagedWidget call is the widget instance name. 
This name can be used to set resources for this widget from the resource databases. This is 
often the same name as the variable of type widget that holds the widget ID. This lexical 
connection is not mandatory, but it reduces confusion by helping you to remember the con 
nection between entries in the application-defaults file and the widget instances in the appli 
cation. 



64 



X Toolkit Intrinsics Programming Manual 



3.1.2 Geometry Management in Practice 

Build and run xboxl as described in Section 3.1, then try resizing it to see how the Box 
widget deals with various geometries. The two possibilities are shown in Figure 3-2. 



Quit 






Press Me 



Quit 




Press Me 



Figure 3-2. Two configurations of xboxl 

When you resize the xboxl application, you may notice that although the Box widget initially 
places the widgets one above the other, upon resizing it places them side by side if there is 
room. To have the buttons placed side-by-side by default, set the width of the button box to a 
value greater than the sum of the widths of the enclosed Command widgets. The com- 
mented-out entry in Example 3-2 would do the trick. 

Notice also that the effects of resizing from the window manager and resizing by setting the 
xboxl. box. width resource are quite different. Using the window manager, you can 
resize the box to be smaller than the buttons, causing them to be clipped, or to be far larger 
than needed, so that they sit at the upper-right corner of a large window. Using resource 
specifications, you can make the box large enough to hold the buttons side-by-side, but no 
larger. You cannot make it narrower than the width of the widest button, or shorter than the 
height of a button. 

Every widget s size and position is ultimately under the control of the window manager. A 
box widget may do some basic sanity checking on values specified in the resource files 
before it uses them. But the window manager can override anything the widget or the appli 
cation does. 

What happens when the user resizes an application is only part of the picture. The applica 
tion itself may need to resize one of its widgets in order to display more widgets. Or the 
application may tell a widget to display more data and the widget will have to ask its parent 
to be resized. 

For example, what happens when the application changes the string in one of the Command 
widgets while the application is displayed? 

The Command widget attempts to resize itself to display the current string, by asking its par 
ent for permission. Whether this request is granted depends on the position of the widget in 
the instance hierarchy, the resizing policy imposed by each composite widget in the hier 
archy, and the window manager. This is because each widget, from the Command widget on 
up, negotiates with its parent when the Command widget requests a new size. If the Com 
mand widget already has enough space, it changes the string and no geometry change is nec 
essary. But if the Command widget tries to change size to accommodate the new string 




More Widget Programming Techniques 



65 



(larger or smaller), the Box widget must approve this change. Since the Box widget is 
already the same size as the Shell widget, Box can t get any larger without asking Shell. The 
Shell widget is responsible for negotiating with the window manager. Most window manag 
ers will not allow an application to resize itself, because windows should be resized only in 
response to a user request through the window manager. Therefore, the Box widget will 
reject the resize request unless it makes the Command widget smaller. 

Fortunately, all this negotiation is done by the widgets themselves. The application doesn t 
need to do anything. However, you should be aware that any widget resource change that 
results in a size change won t work unless there is enough room in the application for the 
change to be granted without resizing the top-level window. 

Overall, the Box widget is useful for managing Command widgets, because its simple rules 
work nicely when the children are similarly sized widgets.* However, it can t cope with 
widgets that are of radically different geometries. Box s decisions about where to place the 
widgets are inappropriate. Figure 3-3 shows the results upon resizing of a Box widget that is 
attempting to manage two Scroll widgets and a BitmapEdit widget t 

Because geometry management is so complex, there are several different types of composite 
widgets in most widget sets, each with different rules about how it places children. Many 
widget sets have a widget specifically designed to place scrollbars next to a main window. 

Of course, applications are not limited to using only one composite widget It is quite com 
mon for the application s main window to be a large composite widget which contains sev 
eral smaller composite widgets, each of which in turn contains certain groups of related 
widgets. Figure 3-4 shows the xmh application and the instance hierarchy used to create it. 
The top composite widget in xmh is of the Athena VPaned class (renamed Paned in Release 
4). The VPaned widget creates several horizontal panels, or panes, one for each child, with a 
Grip widget positioned on the line between each pane. This Grip is used to change the rela 
tive size of the pane. Each pane contains a different functional area of the application. The 
panes that appear to contain Command widgets actually each contain a single Box, which in 
turn contains Command widgets. You ll need to design the layout of widgets in your applica 
tion, decide where in the instance hierarchy to place composite widgets, and experiment to 
find out which composite widgets provide the best appearance when the application is 
resized. 

One of your tools in arranging child widgets is a subclass of composite widgets called con 
straint widgets. 



*From a user-interface point of view, however, one weakness of any widget like Box is that resizing leaves the Com 
mand widgets in new locations where the user may not expect to find them. It is annoying to have to search a box of 
buttons for the button you want 

tThe BitmapEdit widget is not pan of the Athena widget set It is used in Chapter 4, An Example Application, and 
written from scratch in Chapter 5, Inside a Widget and Chapter 6, Basic Widget Methods. 



66 X Toolkit Intrinsics Programming Manual 



Print arraij"||Quit 




Figure 3-3. Results upon resize of Scroll widgets inside a Box widget 

3.2 Using Constraint Widgets 

Constraint widgets, like composite widgets, manage the layout of children. The difference is 
that constraint widgets let the application provide layout information for each child. This is a 
more powerful way to arrange children because it allows you to provide different rules for 
how each child will be laid out 



More Widget Programming Techniques 



67 



Folder | [Table of Contents] [jjessagej [Sequence] [Vieu] | OptionsJ 



protocol 1 1 xl ib 1 1 xl ibbook | [xneus] 




inboxtall 



inbox:2 



Date: Mon, 27 Nov 89 16:19:53 EST 
[From: adnan (fldrian Nye> 
Message- Id: <8911272120 . Afl07404@sp i ke> 
I To: adnan 
Subject: test message 

This is a test of the emergency mail handling system. 
This is only a test. If this had been a real emergency, 
I it would not have uorked. 



Shell 




Box 




Label Box 


Text Text 


Label Text 




~T 






J 










1 


I 


\ Command 


| Command 








Command 


| Command 



Figure 3-4. The xmh application and its instance hierarchy 

In an application, you create a constraint widget just as you would any other widget. But you 
don t set resources of the constraint widget to specify how each child is laid out. Instead, you 
set resources of each child of the constraint widget Once any child widget is placed under 
the management of a constraint widget, the child suddenly has the set of resources defined by 
the constraint widget, which controls its layout As usual, these resources can be set from the 
application-defaults file, from any other resource database file, by hardcoding resources in 
the application as described in Section 2.3.4, or by using Xt SetValues. 

We ll demonstrate how constraint widgets work by replacing the Box widget in xboxl 
(Example 3-1) with an Athena Form widget (a constraint widget). This example is called 
xbox2 in the source code. We won t show this code, because the differences from xboxl are 
slight. The only change is that all occurrences of Box and box are changed to Form and 
form, respectively. The real difference between xbox2 and xboxl lies in the setting of 
resources in the application-defaults file. 

The Form widget defines a number of constraint resources, which to the user appear to be 
resources of the child widgets managed by the Form. Looking at these resources gives you a 
good idea of the kinds of things that can be done with constraints. 

The resources xtNhorizDistance and xtNf romHoriz specify the widget posi 
tion in terms of a specified number of pixels horizontally away from another widget in the 



68 



X Toolkit Intrinsics Programming Manual 



form. As an example, xtNhorizDistance could equal 10 and xtNf romHoriz 
could be the widget ID of another widget in the Form. The new widget will always be 
placed 10 pixels to the right of the widget defined in xtNf romHoriz, regardless of the 
size of the Form. If XtNf romHoriz equals NULL, then XtNhorizDistance is 
measured from the left edge of the Form. 

Similarly, the resources xtNvertDistance and XtNf romVert specify the widget 
position in terms of a specified number of pixels vertically away from another widget in 
the Form. If xtNf romVert equals NULL, then XtNvertDistance is measured 
from the top of the Form. 

When set in the application, the values for xtNf romHoriz and xtNFromVert must 
be widget IDs. But in the resource database, widget names are used instead, since the 
user has no way of knowing the actual widget ID. This is an example of the automatic 
type conversion built into the resource manager. Resource conversion is described in 
Chapter 9, Resource Management and Type Conversion. 

The XtNtop, XtNbottom, xtNlef t, and XtNright resources tell the Form where 
to position the child when the Form is resized. The values of these resources are speci 
fied by the enum XtEdgeType, which is defined in <XlllForm.h>. 

The values XtChainTop, XtChainBottom, XtChainLeft, and XtChain- 
Right specify that a constant distance is to be maintained from an edge of the child to 
the top, bottom, left, and right edges, respectively, of the Form. 

The value xt Rubber specifies that a proportional distance from the edge of the child to 
the left or top edge of the Form is to be maintained when the Form is resized. The pro 
portion is determined from the initial position of the child and the initial size of the Form. 
Form provides a StringToEdgeType conversion to allow the resize constraints to be 
easily specified in a resource file. 

The default width of the Form is the minimum width needed to enclose the children after 
computing their initial layout, with a margin of xtNdef aultoistance at the right and 
bottom edges. If the Form is assigned a width and height that are too small for the layout, the 
children will be clipped by the right and bottom edges of the Form. 

Example 3-3 shows the application-defaults file fotxbox2. 

Example 3-3. XBox2: application-defaults file 

*pressme*label : Press Me 
*quit*label: Quit 
*Command*background: green 
*pressme*f romHoriz : quit 

Notice that since the instance names are unchanged from xboxl (Example 3-1) with the 
exception that box has been changed to form, the first three entries in the application- 
defaults file are also the same. But the next entry, although appearing to affect a resource of 
the pressme Command widget, is actually an instruction for the Form widget about where 
to place the pressme widget relative to the quit widget The effect of this resource set 
ting is shown in Figure 3-5. Note that both the widgets referenced in a constraint must be 
child widgets of the same constraint widget, in this case the Form widget 



More Widget Programming Techniques 69 



If you run this program you can compare its behavior on resize with the behavior of xboxl , 
and you can experiment with different resource settings for the Form widget 



horizDistance 




Press Me 



*pressme.fromHoriz: quit 



Figure 3-5. Effect of the Form XtNfromHoriz resource 

One thing you will notice is that the Form widget is able to resize the Command widgets in 
addition to or instead of moving them as Box did. This is not a difference between composite 
and constraint widgets, but simply between Box and Form. Both composite and constraint 
widgets are allowed to both resize and move their children, but it is up to the design of each 
widget class whether they actually do so. 

Another thing to note is that if you make an error in setting the constraints, it is quite possible 
to end up with one widget on top of another. Sometimes this can make it appear that one of 
the widgets has completely disappeared! 



3.3 Using Pop Ups 

Pop ups are widgets that are not visible until a certain user command is given, or a situation 
arises in which the program requires user input, and even then are visible for only a short 
period. The most common examples of pop ups are dialog boxes and menus. In general, a 
pop up gets information from the user and then goes away. 

Pop ups are not a kind of widget, but rather a way of using widgets. Any widget can be used 
as a pop up. You first create a special parent widget called a TransientShell as a child of 
topLevel. Then you create the widget to appear in the pop up, which may be a simple 
widget or a composite widget with children. However, the TransientShell widget, like top 
Level, must have only one child. 



70 



X Toolkit Intrinsics Programming Manual 



This process sets up the pop-up widget, but does not put it on the screen. Somewhere in your 
code you need to call xt Popup to pop up the widget, and xtPopdown when you want to 
make it invisible again. This is typically done in callback or action routines. 

The xbox3 application shown in Example 3-5 adds a pop-up dialog box to xboxl. The actual 
widget popped up is an Athena Dialog widget. The Dialog widget is a widget designed to 
prompt for auxiliary input from a user. For example, you can use a Dialog widget when an 
application requires the user to enter some information such as a file name. A Dialog widget 
is actually just a special case of the Form widget. It provides a convenient way to create a 
"preconfigured form" useful for dialog boxes. 

The typical Dialog widget contains three areas. The first line contains a Label widget provid 
ing a description of the function of the Dialog widget, for example, the string "Filename:". 
The second line contains a Text widget into which the user types input. The third line can 
contain one or more Command widgets that let the user confirm or cancel the Dialog input. 
The class variable for the Dialog widget is dialogWidgetClass. 

Figure 3-6 shows the appearance of xbox3 when the Dialog widget is popped up. 



Quit 



Pres; 



Enter Text Below: 



Dialog Done 



Figure 3-6. xboxS: popping up a Dialog widget 

Note that without proper resource settings in the application-defaults file, the text entry 
widget will not appear, and the buttons will have different text in them. Example 3-4 shows 
the required application-defaults file. 

Example 3-4. xbox3: application-defaults file 

*value: 

*pressme*label: Press Me 

*quit*label: Quit 

*dialog*label: Enter Text Below: 

*dialog*Command* label: Dialog Done 



More Widget Programming Techniques 



71 



The * value : resource setting tells the Dialog widget to provide a text entry widget but to 
give it no initial text 

Implementing xbox3 requires five steps: 

1. Creating the pop-up shell widget 

2. Creating the Dialog widget 

3. Creating a Command widget as a child of the Dialog widget (This Command widget is 
used to pop down the dialog box.) 

4. Changing the callback function invoked by the "Press Me" button so that it pops up the 
widget 

5. Writing the callback that pops down the widget 
Example 3-5 shows the code added to xboxl to develop xboxS. 

Example 3-5. Creating a pop-up dialog box 



/* Needed for creating popup shell */ 
tinclude <Xll/Shell .h> 

/* 

* Public include files for widgets used in this file. 
V 

tifdef X11R3 

tinclude <Xll/Dialog.h> 

#else /* R4 and later */ 

tinclude <Xll/Xaw/Dialog.h> 

#endif /* X11R3 */ 

/* 

* Both dialog and pshell are needed in the dialogDone callback, 

* and both can t be passed in without creating a structure. 

* So we chose to pass dialog in, and make pshell global. 

* pressme and quit are needed in both callbacks, so they are 

* declared global as well. 
*/ 

Widget pshell, pressme, quit; 

/* 

* dialog button 
*/ 

void PopupDialog(w, topLevel, call_data) 

Widget w; 

Widget topLevel; /* client_data */ 

caddr_t call_data; 

{ 

Position x, y; 

Dimension width, height; 

Arg arg [2] ; 

int i; 

/* 

* get the coordinates of the middle of topLevel widget. 



72 X Toolkit Intrinsics Programming Manual 



Example 3-5. Creating a pop-up dialog box (continued) 

*/ 

i = 0; 

XtSetArg(arg[i] , XtNwidth, swidth) ; 
XtSetArg(arg[i] , XtNheight, Sheight) ; 
XtGetValues (topLevel, arg, i) ; 

/* 

* translate coordinates in application top-level window 

* into coordinates from root window origin. 
*/ 

XtTranslateCoords (topLevel, /* Widget */ 
(Position) width/2, /* x */ 
(Position) height/2, /* y */ 
&x, &y) ; /* coords on root window */ 

/* move popup shell to this position (it s not visible yet) */ 

i = 0; 

XtSetArg(arg[i] , XtNx, x) ; 

XtSetArg(arg[i] , XtNy, y) ; 

XtSetValues (pshell, arg, i) ; 

/* 

* Indicate to user that dialog popup button 

* is invalid while dialog is already popped up... 
*/ 

XtSetSensitive (pressme, FALSE); 

XtPopup (pshell, XtGrabNonexclusive) ; 

} 

/* 

* dialog done button 

*/ 

void DialogDone (w, dialog, call_data) 
Widget w; 

Widget dialog; /* client_data */ 
caddr_t call_data; 
{ 

String string; 

XtPopdown (pshell) ; 
XtSetSensitive (pressme, TRUE) ; 

fifdef X11R3 

string = XtDialogGetValueString (dialog) ; 
telse /* R4 and later */ 

string = XawDialogGetValueString (dialog) ; 
tendif /* X11R3 */ 

printf ("User typed: %s\n", string); 
} 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget box, topLevel, dialog, dialogDone; 



More Widget Programming Techniques 73 



Example 3-5. Creating a pop-up dialog box (continued) 

/* Xtlnitialize, create Box widget, etc. */ 

pressme = XtCreateManagedWidget ( 

"pressme", /* widget name */ 

commandWidgetClass, /* widget class */ 

box, /* parent widget */ 

NULL, /* argument list */ 

/* arglist size */ 
); 

pshell = XtCreatePopupShell ( 
"pshell 11 , 

transient ShellWidgetClass, 
topLevel, 
NULL, 

); 

dialog = XtCreateManagedWidget ( 

"dialog", /* widget name */ 

dialogWidgetClass, /* widget class */ 

pshell, /* parent widget */ 

NULL, /* argument list */ 

/* arglist size */ 
); 

dialogDone = XtCreateManagedWidget ( 

"dialogDone", /* widget name */ 

commandWidgetClass, /* widget class */ 

dialog, /* parent widget */ 

NULL, /* argument list */ 

/* arglist size */ 
); 

XtAddCallback (quit, XtNcallback, Quit, 0) ; 

XtAddCallback {dialogDone, XtNcallback, DialogDone, dialog); 
XtAddCallback {pressme, XtNcallback, PopupDialog, topLevel); 
XtRealizeWidget (topLevel) ; 

XtMainLoopO ; 

} 

The pop-up shell widget is created by a call to XtCreatePopupShell rather than Xt 
CreateManagedWidget. The widget class is specified as transientShell- 
WidgetClass for dialog boxes, and overrideShellWidgetClass for menus. 

Note that you must include <X1 II Shell. h> to create a TransientShell or OverrideShell widget. 
The Shell class actually has several subclasses, each with slightly different characteristics. 
For convenience, all of Shell s subclasses use the same include file. The other subclasses of 
Shell are less frequently used than the top level shell returned by Xtlnitialize and the 
TransientShell used for pop ups and are described in Section 13.7. 

It is often helpful for some or all of the widget IDs involved in pop ups to be global variables 
in the application. As we will see in the discussion of passing data to callback functions, it is 



74 X Toolkit Intrinsics Programming Manual 



awkward to pass more than one piece of data into any one callback function (one has to cre 
ate a structure containing them and pass the pointer to the structure). When two or more 
widget IDs are used in any callback, it is simplest to declare one or more of them global. In 
Example 3-5, pshell, pressme, and quit are declared global. 

The Dialog widget is a compound widget it creates its own widget children in addition to 
letting the application add children. Its purpose is to make it easier to combine existing 
widgets in a standard, useful way. It is really a subclass of the Form widget, to which a Label 
widget child is added to tell the user the purpose of the box and, with certain resource values, 
an Athena Text widget child is added for text entry. Ideally, the Text widget should provide a 
callback (which could be used to provide the data the user entered and popdown the dialog 
box) when the user types the Return key. Many applications add this missing feature by 
overriding the translation for the Return key in the Text widget, or by displaying a Command 
button to provide the callback. 

The Label widget and Text widget are automatically created as part of the Dialog widget. 
However, you have to explicitly create the Command widget as a child of the Dialog widget. 
The Dialog widget does automatically set the constraint resources that Form uses to place 
and size the Command widget The callback function called by this Command widget is 
called DialogDone. 

The pressme Command widget s callback function is called PopupDialog. Most of its 
code places the pop-up widget, because pop ups appear at the top left corner of the screen by 
default. This example centers the corner of the pop up in the top level widget of the applica 
tion. Since pop up coordinates are relative to the corner of the root window, centering is a 
three-step process: 

1. Get the width and height of top-level window with xt Get Values. 

2. Translate the center point into root window coordinates with xtTranslateCoords. 

3. Move the pop-up shell there by setting the xtNx and XtNy resources with xtSet- 
Values. 

When you pop up a widget from an action instead of a callback, you can use the content of 
the event to place the pop up and avoid the last two steps. 

Pop-up windows appear at the corner of the screen by default because their windows are chil 
dren of the root window, not children of the top-level window of the application. This allows 
the pop up to extend beyond the border of the application, as was shown in Figure 3-5. 
Pop-up windows are the only difference between the widget hierarchy created by an applicaT 
tion and its X window hierarchy. Figure 3-7 shows the two hierarchies forxbox3. 

The PopupDialog callback function sets the Command widgets in the application to 
insensitive mode with xtSetSensitive* just before it pops up the dialog box. This is 
done to indicate to the user that the data asked for in the callback function must be provided 
before executing any other application command. When the data is furnished, the applica 
tion must turn sensitivity back on again. 



"This could also be done by setting the widgets XtNsensitive resource with XtSetValues. Calling Xt 
SetSensitive is slightly faster. 



More Widget Programming Techniques 75 



Instance hierarchy 



xbox- 



Shell 
XT 



box 



pTransientShell \- p she 11 
1 



quit j Command pressme -| Command) [Dialog [ dialog 



Window hierarchy 




TransientShell 
Dialog ; 



Figure 3-7. The widget instance and X window hierarchies are different only for pop ups 

The DialogDone callback function pops down the pop-up shell, sets the application s 
Command widget back to sensitive mode, gets the value the user typed, and prints it 

If you have a pop-up widget that might never be used, or whose characteristics are not known 
until just before it is popped up, you can create the pop-up shell and widget just before pop 
ping it up, in the callback function or action that pops up the widget This makes the startup 
time of the application marginally faster, but slows the pop-up time the first time the pop up 
is used. 

Pop ups, and menus in particular, will be described in much more detail in Chapter 12, 
Menus, Gadgets, and Cascaded Pop Ups. 



76 



X Toolkit Intrinsics Programming Manual 



3.4 More About Callbacks 

As you may recall, a callback is a function that your application wants called in response to a 
specified occurrence in a certain widget. The application simply declares the callback func 
tion and then calls XtAddCallback. While Chapter 2Jntroduction to the X Toolkit, dis 
cussed the concept of callbacks and demonstrated the most common use, it did not com 
pletely describe all the useful tricks. You can pass application data to callback functions. 
You can arrange for more than one callback function to be called (in a particular order) when 
the callback is triggered, and add and remove functions from this list at will. You can declare 
callbacks statically using a callback list instead of calling XtAddCallback. 



Passing Data to Callback Functions 

A callback function is called with three arguments: widget, client_data, and 
call_data. 

The application determines the use of the client_data argument, while the widget deter 
mines the use of the call_data argument As described earlier, the widget argument is 
necessary if you have registered the same callback function for two widgets, and you need to 
know which widget called the function. It also may be used in routine ways, such as for the 
argument of macros. The call_data argument is passed in from the widget itself. This 
argument s value is defined by the widget, and is described in the documentation for the 
widget unless it is not used. Few of the Athena Widgets use the call_data argument, but 
other widgets do use it occasionally. 

You may pass a single piece of data as the clien t_da ta argument, or a pointer to a struc 
ture containing several pieces of data. You may ask, "Why bother with passing data to a call 
back when I can just declare a global variable?" For one thing, it is a general principle of 
good C coding to use a global variable only where the variable is needed in several functions 
and the arguments would otherwise prove unwieldy. Secondly, using the client_data 
argument makes clear the purpose of your variable, whereas it is difficult to trace where a 
global variable is set or referenced. However, if you find it necessary to change the 
client_data argument in a number of functions in the application, you will need a global 
variable anyway, and there is nothing that says you must use client_data (but be sure to 
document what you are doing!). 

Example 3-6 demonstrates how to pass a single piece of data into a callback function. 
Example 3-6. Passing a single value to a callback function 

/*ARGSUSED*/ 

void PressMe(w, client_data, call_data) 

Widget w; 

caddr_t client_data, call_data; 

{ 

fprintf (stderr, "%s\n", client_data) ; 

} 

main(argc, argv) 
int argc; 



More Widget Programming Techniques 




Example 3-6. Passing a single value to a callback function (continued) 
char **argv; 

Widget pressme; 

/* Xtlnitialize, create pressme widget */ 

4 

/* last argument is client_data */ 

XtAddCallback (pressme, XtNcallback, PressMe, "Thanks") 



Example 3-7 demonstrates passing a pointer to a structure into a callback function. 

Example 3-7. Passing a pointer to a structure to a callback function 

typedef struct { 

String name; 

String street; 

String city; 
} app_stuff; 

/*ARGSUSEDV 

void PressMe (w, address, call_data) 

Widget w; 

app_stuff *address; 

caddr_t call_data; 

{ 

/* 

* Alternately, the second argument can remain declared as 

* client_data, and the following cast can be used: 

app_stuff *address = (app_stuff *) client_data; 
*/ 

fprintf (stderr, "%s\n%s\n%s\n", address->name, address->street, 
address->city) ; 

} 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget box, quit, pressme, topLevel; 

static app_stuff stuff = { 
"John Doe", 

"1776 Constitution Way", 
"Philadelphia, PA 01029" 



/* Xtlnitialize, create pressme widget */ 



78 X Toolkit Intrinsics Programming Manual 



Examples-?. Passing a pointer to a structure to a callback function (continued) 

XtAddCallback(pressme, XtNcallback, PressMe, &stuf f ) ; 



3.4.2 Callback Lists 

You may register any number of callback functions for a single widget callback resource. In 
other words, when a callback is triggered by a user event, all the functions in the current call 
back list for that callback for that widget instance will be called, one at a time, in the speci 
fied order. Multiple callback functions are not needed in many applications, but can be use 
ful if applied creatively. 

Remember that a widget may also have more than one callback list, each triggered by a dif 
ferent occurrence. For example, the Command widget has XtNcallback, which is trig 
gered by a pointer button click, and xtNdestroyCallback, which is triggered when the 
widget is destroyed. Each of these callback resources exists as a separate callback list for 
every instance of the widget. 

Xt supplies three standard callback functions that pop up a widget xtCallbackNone, 
XtCallbackExclusive, and XtCallbackNonexclusive.* 

Do not be confused by the names of the standard pop-up callback functions. Even though 
their names do not include the word Popup, their only use is to pop-up widgets. 

Each of these functions pops up the widget specified in the client_data argument. Xt 
CallbackExclusive and XtCallbackNonexclusive also grab certain events so 
that the user must provide the information requested before continuing. Exclusive is for 
use when you create a single pop up such as a menu or dialog box, and Nonexclusive is 
for when you pop up a menu that pops up submenus. Since these standard pop-up callback 
functions do not move the pop-up widget before popping it up, it is a good idea to add 
another callback function to the callback list before them, to place the widget. xboxS, which 
is not shown in this book but is included in the example source, creates a callback list com 
posed of PrepareDialog (which moves the pop up to the proper location) and Xt 
CallbackExclusive. 

Let s take another example of how a callback list might be used. Perhaps you have the func 
tions A, B, and C, and you need to be able to call them separately in response to events in 
three different Command widgets, or to call all of them in order in response to events in a 
fourth Command widget This fourth Command widget might have a callback list including 
the functions A, B, and C. While this can also be implemented by creating a function D that 
calls A, B, and C and then registering D as the callback of the fourth Command widget, you 
can t pass a different piece of data into each routine, and you can t change the order of the 
functions called by D. You can do both easily if A, B, and C are specified in a callback list. 



"These standard callback functions also set the calling widget (usually a Command widget) to insensitive mode. You 
must set the parent widget back to sensitive mode when you pop down the widget 



More Widget Programming Techniques 



The order in which the callback functions are called can be changed by removing them from 
the list (using XtRemoveCallback, XtRemoveCallbacks, or XtRemoveAll- 
Callbacks) and then adding them in a different order. You can also call the same function 
more than once in a callback list. 

One way to add more than one callback function is to call XtAddCallback more than 
once. Another way is to call XtAddCallbacks, which takes an XtCallbackRec array 
as an argument. This array is usually initialized at compile time, as shown in Example 3-8. 
The final NULL, NULL entry terminates the list. (This particular list registers the functions 
do_A and then_B, and passes them both as client_data.) 

Example 3-8. Initializing a callback list 

XtCallbackRec quit_callback_list [ ] = { 

{do_A, 0}, 

{then_B, 0}, 

{ (XtCallbackProc) NULL, (caddr_t) NULL} 
}; 

This form of XtCallbackRec list can also be used to replace a callback list with xt Set- 
Values (but not to get a callback list, because Xt compiles the list into an internal form). 
As demonstrated in Section 3.7.1, an XtCallbackRec list can also be used to register one 
or more callbacks when creating a widget. 



3.5 Application Resources 

You already know that widgets declare resources that can be configured through the resource 
mechanism. In addition, the application itself may have variables that it wants the user to be 
able to configure from the resource databases, even though these variables have nothing to do 
with widgets. These are called application resources. 

Application resources are just like widget resources except that they apply to application 
code, not to the widgets it creates. 

There are three steps for adding application resources. You must: 

1. Create an application data structure containing the variables to be set via the resource 
mechanism. 

2. Create a resource table defining the type and default value for each variable. 

3. Call xtGetApplicationResources with pointers to the application data structure 
and resource table as arguments. When this function returns, the application data struc 
ture will contain the current settings from the resource databases. 

To demonstrate how to get application resources, we will jump ahead and describe a portion 
of the code for the xbitmap4 bitmap editor example described in Chapter 4, An Example 
Application. Since this application draws into a widget using Xlib, it needs two colors to 
draw with. The bitmap editor also allows the user to specify the dimensions of the bitmap in 
cells, and the size of each cell in pixels. And, for general utility, it includes a debug flag that 
can be set in the application to invoke or ignore debugging code without recompiling. 



80 X Toolkit Intrinsics Programming Manual 



3.5.1 The Application Data Structure 

The structure type that contains all the application variables to be set through resources is 
commonly called AppData. Once this structure type is declared, memory can be allocated 
for a structure called app_data. Example 3-9 shows the code that defines the structure 
type and then allocates memory for the actual structure. 

Example 3-9. xbitmap: getting application resources 

typedef struct { 

Pixel copy_fg; 

Pixel copy_bg; 

int pixmap_width_in_cells; 

int pixmap_height_in_cells; 

int cell_size_in_pixels; 

Boolean debug; 
} AppData, *AppDataPtr; 

AppData app_data; 

Note that a pointer called AppDataPtr is defined for convenience in defining the resource 
list (as described in a moment). 

As usual in C, the members of the app_data structure will be referenced throughout the 
application code using the dot format. For example, the value of the debug field of 
app_data will be referenced with app_data . debug. 

3.5.2 The Resource List 

The resource list looks complicated, but it is easy to understand and even easier to write 
because it conforms to a consistent pattern. Each field in the application data structure has an 
entry in the resource list. Each resource user entry in turn has seven fields, which describe 
the name of the resource, its type and default value, and various other information. 

The resource list controls Xt s value conversion facilities. Since user resources are always 
strings, and application data structure fields can be any type, a conversion may have to take 
place. Xt has built-in converters to convert from string to most common types needed by 
applications. These types are called representation types by Xt, and they are indicated by 
constants starting with xtR. The representation type of a string is xtRString. You con 
trol the conversion simply by specifying a resource as a certain representation type in the 
resource list. 

Note that a representation type is different from a C-language type. For example, a color 
may be represented as an ASCII color name such as "blue," as a structure containing Red, 
Green, and Blue values, or as a pixel value (an index into a colormap.) It is also possible for 
two different representations of something to both use the same C-language type. For 
example, two hypothetical representation types might be xtRlnch and xtRMeter. Both 
represent distances and both would probably be floating point numbers, but each would have 
a different value for the same distance. 



More Widget Programming Techniques 81 



See Chapter 9, Resource Management and Type Conversion, for a description of the standard 
representation types, as well as information on how to write your own converter routine. 

Example 3-10 shows the resource list for xbitmap, followed by a description of each of the 
fields in each entry. 

Example 3- 1 0. The resource list for xbitmap 

/* 
* The following could be placed in a "xbitmap. h n file. 

*/ 

fdefine XtNdebug "debug" 
#define XtCDebug "Debug" 

#define XtNpixmapWidthlnCells "pixmapWidthlnCells" 
tdefine XtCPixmapWidthlnCells "PixmapWidthlnCells" 
tdefine XtNpixmapHeightlnCells "pixmapHeightlnCells" 
tdefine XtCPixmapHeightlnCells "PixmapHeightlnCells" 
tdefine XtNcellSizelnPixels "cellSizelnPixels" 
#define XtCCellSizelnPixels "CellSizelnPixels" 

static XtResource resources!] = { 
{ 

XtNforeground, 

XtCForeground, 

XtRPixel, 

sizeof (Pixel) , 

XtOf f set (AppDataPtr, copy_fg) , 

XtRString, 

XtDefaultForeground 
}, 
{ 

XtNbackground, 

XtCBackground, 

XtRPixel, 

sizeof (Pixel) , 

XtOf f set (AppDataPtr, copy_bg) , 

XtRString, 

XtDefaultBackground 
>, 
{ 

XtNpixmapWidthlnCells, 

XtCPixmapWidthlnCells, 

XtRInt, 

sizeof (int) , 

XtOf f set (AppDataPtr, pixmap_width_in_cells) , 

XtRImmediate, 
(caddr_t) 32, 
}, 
{ 

XtNpixmapHeightlnCells, 

XtCPixmapHeightlnCells, 

XtRInt, 

sizeof (int) , 

XtOf fset (AppDataPtr, pixmap_height_in_cells) , 

XtRImmediate, 
(caddr_t) 32, 



82 X Toolkit Intrinsics Programming Manual 



Example 3-10. The resource list for xbilmap (continued) 

XtNcellSizelnPixels, 

XtCCellSizelnPixels, 

XtRInt, 

sizeof (int) , 

XtOf f set (AppDataPtr, cell_size_in_pixels) , 

XtRImmediate, 

(caddr t) 30, 



XtNdebug, 
XtCDebug, 
XtRBoolean, 
sizeof (Boolean) , 
XtOf f set (AppDataPtr, debug) , 
XtRImmediate, 
(caddr_t) FALSE, 
>, 

}; 

A resource list entry has the following fields: 

The first two fields of each entry are the name and class of the resource, both strings. 
These are specified as symbolic constants to improve compile-time checking, and should 
be selected from <Xll/StringDefs.h> if any there have an appropriate name, or they can 
be defined in your application s own include file. For the debug resource entry, the 
resource name and class strings would be "debug" and "Debug," respectively defined in 
the application s include file as XtNdebug and XtCDebug. 

The third field is the representation type. A representation type is a symbolic constant, 
beginning with xtR, that defines the data type of a resource. Because user resource spec 
ifications are always in the form of strings, but the actual resources may be of any type, 
Xt uses resource converters to convert the string representation to the actual target type. 
If necessary, you can define your own representation type in your application include file, 
but you will also have to provide Xt with a way to convert from string to this type with a 
type converter function, as described in Chapter 9, Resource Management and Type Con 
version. Table 3-1 lists the correspondence between the representation types defined in 
<Xll/StringDefs.h> and actual C data types or X data types and structures. 

The fourth field, the size of the representation, is specified using the C macro sizeof 
with the actual C type as an argument For example, when the representation type is Xt 
RBoolean, the size field is sizeof (Boolean) . 

The fifth field identifies the place in your application s data structure where Xt is to place 
the converted value. In Example 3-11, the structure is called AppData, and the pointer 
to it is called AppDataPtr. This field for the debug resource entry is specified using 
the XtOffset macro as xtOff set (AppDataPtr, debug). Note that the field 
name in the application data structure is often the same as the resource name, except with 
all word-transitions marked with an underscore instead of a capital letter. 

The sixth field specifies the representation type of the default value (the seventh field). 
Xt has routines for converting data between types. They are used to translate strings from 
the resource databases into certain representation types. Therefore, you can specify the 



More Widget Programming Techniques 



default value as a string (among other things) and Xt will convert it to the representation 
type you specified in field three, if the default value is needed. If the representation type 
in field three is not standard in Xt, you will have to write the conversion routine that con 
verts from XtRSt ring to that representation, as described in Chapter 9, Resource Man 
agement and Type Conversion. In Release 3 and later, you can also use the special con 
stant xtRlmmediate here, which indicates that the value in field seven can be used 
without conversion. Using XtRlmmediate should lead to faster startup. 

The seventh field is the default value, using the representation type specified in field six. 
This default value will be set into the application data structure field if there is no setting 
for this resource in the resource database. 



Table 3-1. Resource type strings 



Resource Type 



Data Type 



XtRAcceleratorTable 

XtRBoolean 

XtRBool 

XtRCallback 

XtRColor 

XtRCursor 

XtRDimension 

XtRDisplay 

XtRFile 

XtRFloat 

XtRFont 

XtRFontStruct 

XtRFunction 

XtRInt 

XtRPixel 

XtRPixmap 

XtRPointer 

XtRPosition 

XtRShort 

XtRString 

XtRTranslationTable 

XtRUnsignedChar 

XtRWidget 

XtRWindow 



Xt Accelerators 

Boolean 

Bool 

XtCallbackList 

XColor 

Cursor 

Dimension 

Display* 

FILE* 

float 

Font 

XFontStruct * 

(*) () 

int 

Pixel 

Pixmap 

caddr_t 

Position 

short 

char* 

XtTranslations 

unsigned char 

Widget 

Window 



84 



X Toolkit Intrinsics Programming Manual 



3.5.3 Getting the Resources 

Once the application data structure and resource list are set up, you pass pointers to them to 
XtGetApplicationResources, just after calling Xtlnitialize. XtGet- 
ApplicationResources will search the databases for any matching resource settings 
and set the fields in the application data structure. 

The last requirement is that you check the values specified by the user to make sure they are 
acceptable. Example 3-11 shows these two steps from xbitmap4. 

Example 3-11. Calling XtGetApplicationResources and checking values 



AppData app_data; 



main(argc, argv) 
int argc; 
char *argv[ ] ; 

{ 

Widget toplevel, vpane, buttonbox, quit, output; 



/* call Xtlnitialize here */ 

XtGetApplicationResources (toplevel, 
&app_data, 
resources, 

XtNumber (resources) , 

NULL, /* argument list and length for making */ 
0) ; /* application resources non-user-configurable */ 

/* 

* We must check the application resource values here. 

* Otherwise, user could supply out of range values. 

* Conversion routines do this automatically, so 

* colors are already checked. 

*/ 

if ( (app_data.pixmap_width_in_cells > MAXBITMAPWIDTH) || 
(app_data.pixmap_width_in_cells < MINBITMAPWIDTH) I I 
(app_data.pixmap_height_in_cells > MAXBITMAPWIDTH) | | 
(app_data.pixmap_height_in_cells < MINBITMAPWIDTH)) { 
fprintf (stderr, "xbitmap: error in resource settings:", 

"bitmap dimension must be between %d and %d cells\n", 
MINBITMAPWIDTH, MAXBITMAPWIDTH) ; 
exit(l) ; 

} 

if ( (app_data.cell_size_in_pixels < MINCELLSIZE) I I 

(app_data.cell_size_in_pixels > MAXCELLSIZE) ) { 
fprintf (stderr, "xbitmap: error in resource settings:", 
"cell size must be between %d and %d pixels\n", 



More Widget Programming Techniques 



Example 3-11. Calling XtGetApplicationResources and checking values (continued) 

MINCELLSIZE, MAXCELLSIZE) ; 
exit (1) ; 



Note that only certain of the application resources need their values checked. Because Xt 
automatically converts the user s color specifications (such as "blue") into the form required 
by X, it takes care of warning the user when a color is specified improperly.* In this case, 
only the bitmap dimensions and cell size are checked, since they are critical to the applica 
tion s operation. 



3.6 Command-line Options 

You already know that Xt automatically customizes widgets according to the resource data 
base, but this is not the whole story. Users often expect command-line arguments for the 
most important aspects of an application. By default, Xt Initialize understands only a 
minimal set of command-line arguments; more need to be added so that application resources 
and certain widget resources can be set from the command line. 

There is no point, however, in trying to make every widget resource sellable from ihe com 
mand line, because that s the purpose of the resource database. You should concentrate on 
the resources that the user is most likely to want to have different between two simultaneous 
instances of the application (since it is difficult to arrange this with the resource database). 

Before describing how to define your own command-line arguments, we need to describe 
what command-line arguments Xt Initialize already handles. 

3.6.1 Standard Command-line Options 

First of all, Xt Initialize recognizes the -xrm option for setting any widget or applica 
tion resource. For example: 

spike% xhallo -xrm * background: blue 

This option is a little awkward. Not only is it long, but csh users must quote the string with 
right-handed single quotes so that the * is not interpreted by the shell. 



*That is, if the resource in a database file is specified properly, but the value is not, Xt will warn the user. However, if 
the resource is not specified properly, Xt has no way of knowing that the resource was intended to specify a color, 
and therefore, no message will be issued. For example, "* background: grein" will elicit a warning message because 
green is misspelled, but "*backgruond: green" will not, because the resource identifier is misspelled. 



86 X Toolkit Intrinsics Programming Manual 



Xt Initialize also understands some command-line options that were considered so 
basic that they should be the same for all applications. The above -xrm command line can be 
replaced by: 



spike% achallo -background blu 



or 



spike% xhallo -bg blua 

Xt Initialize also understands any unique abbreviation of an option name, such as: 

spike % xhallo -backg blue 

These resources will work with any application written using the X Toolkit with any widget 
set Try the command line above if you have a color screen. If not, try specifying a different 
font, using the -fn or -font option. 

Table 3-2 lists the complete set of standard options.* Options for which the resource name is 
shown starting with a dot rather than an asterisk set that resource only in the application s 
top-level Shell. 

Table 3-2. Standard command-line parameters 



Option 


Resource 


Value 


Sets 


-bg 


*background 


next argument 


background color 


-background 


*background 


next argument 


background color 


-bd 


*borderColor 


next argument 


border color 


-bw 


.borderWidth 


next argument 


width of border in pixels 


-borderwidth 


.borderWidth 


next argument 


width of border in pixels 


-bordercolor 


*border Color 


next argument 


color of border 


-display 


.display 


next argument 


server to use 


-fg 


* foreground 


next argument 


foreground color 


-fn 


*font 


next argument 


font name 


-font 


*font 


next argument 


font name 


-foreground 


*f oreground 


next argument 


foreground color 


-geometry 


.geometry 


next argument 


size and position 


-iconic 


. iconic 


"on" 


start as an icon 


-name 


.name 


next argument 


name of application 


-reverse 


*reverseVideo 


"on" 


reverse video 


-rv 


*reverseVideo 


"on" 


reverse video 


+rv 


*reverseVideo 


"off" 


No Reverse Video 


-selectionTimeout 


. selectionTimeout 


Null 


selection timeout 


-synchronous 


. synchronous 


"on" 


synchronous debug mode 



*There is no legitimate way for the application to access this parse table, which is necessary to show the user an error 
in a parameter. Furthermore, this table is in the source for Xt and therefore not available online to some Toolkit 
users. However, this parse table is not expected to change radically in new releases. Therefore it can probably be 
safely copied from this document into application code to provide a synopsis of valid options. Most current applica 
tions simply say "This application understands all standard X Toolkit command-line options." 



More Widget Programming Techniques 



87 



Table 3-2. Standard command-line parameters (continued) 



Option 


Resource 


Value 


Sets 


asynchronous 
-title 
-xrm 


. synchronous 
.title 
value of argument 


"off 
next argument 
next argument 


synchronous debug mode 
tide of application 
depends on argument 



Note that many of these command-line options set the resource of every widget in the appli 
cation to the same value. A few of them set the resources only of the application s top-level 
shell widget 



3.6.2 Defining Your Own Command-line Options 



Supplying your own command-line options allows you to simplify the customization of your 
application. It also allows the user to customize things that are difficult with the resource 
database (such as setting different values for the same resource in two instances of the appli 
cation). 



You make xt initialize understand additional command-line options by initializing a 
XrmOptionDescRec structure (called the options table) and passing it as an argument to 
xt Initialize. Example 3-12 shows the code that implements command-line options for 
the application resources added in Examples 3-9, 3-10, and 3-11. 



Example 3-1 2. xbitmap: specifying command-line options 

/* include files, etc. */ 



static XrmOptionDescRec options [] = { 

{"-pw", "*pixmapWidthInCells", 

{ "-pixmapwidth", "*pixmapWidthInCells", 



{"-ph", 

{ "-pixmapheighf 

{"-cellsize", 

{"-fg", 

{ "-foreground" , 

{"-debug", 



*pixmapHeight!nCells", 
*pixmapHeight!nCells", 

"*cellSize!nPixels", 

" * foreground" , 

" * foreground" , 

"*debug", 



XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 
XrmoptionNoArg, "True"}, 



static void Syntax (argc, argv) 
int argc; 
char * argv [ ] ; 

int i; 

static int errs = False; 

/* first argument is program name - skip that */ 
for (i = 1; i < argc; i++) { 
if (!errs++) /* do first time through */ 



88 



X Toolkit Intrinsics Programming Manual 



Example 3-1 2. xbitmap: specifying command-line options (continued) 



fprintf (stderr, "xbitmap4 : command line option unknown :\n") 
fprintf (stderr, "option: %s\n", argv[i]); 



Additional options are as follows:\nO) ; 



fprintf (stderr, "xbitmap understands all standard Xt \n 
command-line options . \nO) ; 

fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 
fprintf (stderr, 



"Option 

n -pw 

"-pixmapwidth 

-ph 

"-pixmapheight 

"-cellsize 

"-fg 

"-foreground 

"-debug 



Valid Range\n") ; 

2 to 1000\n") ; 

2 to 1000\n") ; 

2 to 1000\n") ; 

2 to 1000\n") ; 

4 to 100\n") ; 

color name\n") ; 

color name\n") ; 

no value necessary\nO) 



main(argc, argv) 
int argc; 
char *argv[] ; 
{ 

Widget toplevel, vpane, buttonbox, quit, output; 



toplevel = Xtlnitialize ( argv[0], 
"XBitmap4", 
options, 

XtNumber (options) , 
Sargc, 
argv) ; 

/* Xtlnitialize always leaves program name in args */ 
if (argc > 1) 
Syntax (argc, argv); 



Each options table entry consists of four fields: 

The option to be searched for on the command line. As with standard command-line 
options, Xt will automatically accept any unique abbreviation of the option specified 
here. For example, the option -pixmapWidthlnPixels will be recognized if typed on the 
command line as -pixmapW. However, if you wanted the option -pw to set the same 
resource, then you would need another entry, since pw is not the leading string of 
pixmapWidthlnPixels. 

The resource specification. This must identify a widget resource or an application 
resource, but not provide a value. Since it has the same form as allowed in the resource 
databases, it may apply to a single widget or to many widgets. If it applies to no widgets, 
no error message will be issued. 



More Widget Programming Techniques 



89 



The argument style. This field is one of seven constants describing how the option is to 
be interpreted. These constants are described below in Table 3-3. 

The value. This field is the value to be used for the resource if the argument style is 
XrmOptionNoArg. This field is not used otherwise. Note that this value must already 
be converted to the value expected for the resource (often not a string). You may be able 
to use Xt s type converter routines explicitly to convert this data to the right type (see 
Section 9.3.5). 

The enum constants that specify the various command-line argument styles are as shown in 
Table 3-3: 

Table 3-3. XrmOptbnKind: Command-line Option Style Constants 



Constant 



Meaning 



XrmoptionNoArg 



XrmoptionlsArg 



XrmoptionStickyArg 

XrmoptionSepArg 
XrmoptionResArg 



Xrmopt ionSkipAr g 
XrmoptionSkipLine 



Take the value in the value field of the options table. For 
example, this is used for Boolean fields, where the option 
might be -debug and the default value FALSE. 
The flag itself is the value without any additional information. 
For example, if the option were -on, the value would be "on." 
This constant is infrequently used, because the desired value 
such as "on" is usually not descriptive enough when used as 
an option (-on). 

The value is the characters immediately following the option 
with no white space intervening. This is the style of argu 
ments for some UNIX utilities such as uucico where -sventure 
means to call system venture. 

The next item after the white space after this flag is the value. 
For example, -fg blue would indicate that "blue" is the value 
for the resource specified by -fg. 

The resource name and its value are the next argument in 
argv after the white space after this flag. For example, the 
flag might be: 

-res basecalc*background: white; 

then the resource name/value pair would be used as is. This 

form is rarely used because it is equivalent to -xrm, and 

because the C shell requires that special characters such as * 

be quoted. 

Ignore this option and the next argument in argv. 

Ignore this option and the rest of argv. 



The options table is passed to xt Initialize as its third argument, and the number of 
options table entries as the fourth. The xt Number macro is a convenient way to count the 
number of entries (this is only one of many contexts in which you ll see this macro used). 



90 



X Toolkit Intrinsics Programming Manual 



Note that you cannot override the standard options by providing options with the same names 
in your own parsing table. If you try this, your options with the same names will simply not 
be set to the values specified on the command line. Instead, the standard options will be set 
to these values. This was a design decision in Xt, one of the few cases where a user-interface 
policy is enforced. Uniformity in this basic area was deemed more valuable than flexibility. 

It is important to check whether there is more than one argument left after xt initialize 
has returned. Xt Initialize conveniently removes from argc and argv the command- 
line arguments that it has already used to set resources. Command-line options that xt- 
Initialize doesn t recognize will be left in argv and argc. This is your chance to 
catch this error and tell the user.* The Syntax function shown in Example 3-12 demon 
strates code that informs the user of the proper syntax and the option that was not understood. 
(In response to incorrect command-line options, UNIX programs traditionally print only the 
correct calling sequence. However, you can be even nicer to the user by printing the option 
or options that were in error, by passing argv and argc into your Syntax function, as is 
done in Example 3-12. 

Experienced UNIX programmers will note that Xt applications can (but usually don t) use the 
single-letter command-line arguments mandated by POSIX and the System V Interface Defi 
nition. As mentioned earlier, Xt automatically matches any unique abbreviation for any com 
mand-line option. For example, by default the -display option can be specified as -d, but only 
if you haven t included any other option in the options table that also begins with d. You can 
define the meaning of single-letter options simply by including them verbatim in the options 
table. In other words, if you specify that -d turns on a debugging resource, Xt will no longer 
try to match any other, longer option that also begins with d. 

Note that the argc and argv arguments of Xtlnitialize are in the same order as in 
the call to main. This is the opposite order of arrays and array lengths throughout other Xt 
and Xlib routine calls. Also note that the address of argc, not argc itself, is passed to Xt 
lnitialize. This is so that Xtlnitialize can decrement the count to reflect recog 
nized options. Watch out for these snags. 



3.7 Preventing User Customization of Widget Resources 

Although user customization is good to a certain degree, some resources need to be hard- 
coded to make sure that an application will run properly regardless of user configuration. 
This is particularly true of widget geometry resources and constraints. For example, it is easy 
to make a mistake with Form widget constraints such that some important widget is hidden 
behind others. 

You prevent user customization of particular resources by creating an argument list and pass 
ing it as an argument to XtCreateWidget, or by calling xt Set Values once the widget 
already exists. The application can still modify these resources later using xtSetvalues. 
Therefore, this is hardcoding only from the user s perspective. 



*You can, of course, intentionally treat the arguments remaining after Xtlnitialize as filenames or other pieces 
of data. 



More Widget Programming Techniques 



The time to hardcode widget resources is when development of an application is almost fin 
ished, because until then the resource settings are still in flux and it is easier to edit the appli 
cation-defaults file than it is to recompile the application. 

Selecting which resources to hardcode is something we can t help you with, because there 
isn t enough experience to go on yet. Some application developers will hardcode almost 
everything, while others will hardcode nothing. Only time will tell where the proper balance 
lies. 



3.7.1 The Argument List 

Widget resources are hardcoded by creating an argument list containing the resources to be 
set and their values, and passing it to the call to create a widget 

An argument list is just an array of Arg structures, of the same type as you set up to call xt - 
Setvalues or xtGetValues. Once set, this array is used as an argument to xt- 
CreateManagedWidget. Each Arg structure contains a resource/value pair. Attributes 
specified here override the same ones specified from the command line or from resource data 
bases. 

Example 3-13 shows an argument list that hardcodes the sensitivity of a Command widget 
and its callback list. The sensitivity is a good thing to hardcode for Command widgets, 
because if set by the user it could disable an application.* The callback list cannot be speci 
fied by the user anyway; setting it here is just an alternative to calling xtAddCallback. 

The xtArgVal type used in the callback list aids in porting Toolkit programs to different 
architectures. It allows the system manufacturer to select the type in the typedef for Xt 
ArgVal, so that the application program need not worry about it. The value field of the 
Arg structure may be a number or a pointer. 

Example 3-1 3. An argument list 

Arg quit_args [ ] = { 

XtNsensitive, (XtArgVal) TRUE, 

XtNcallback, (XtArgVal) quit_callback_list, 

}; 

An argument list can be used as an argument in the call to create a widget, as shown in 
Example 3 -14. 

Example 3-14. Using an argument list in widget creation 

/* define quit_args */ 

main(argc, argv) 
int argc; 



^Sensitivity is a basic resource of all widgets. When set to TRUE, the default, a widget accepts input and operates 
normally. When FALSE, a widget displays itself in gray (or otherwise indicates insensitivity) and does not act on 
user input The purpose of sensitivity is to allow the application to disable certain commands when they are not val 
id. If sensitivity were left configurable, the user could turn it off on some widgets and effectively cripple an applica 
tion. It is hard to imagine the user doing this by accident, but it is not worth taking a gamble. 



92 X Toolkit Intrinsics Programming Manual 



Example 3-14. Using an argument list in widget creation (continued) 

char *argv [ ] ; 
{ 

Widget quit, box; 

/* create box */ 



quit = XtCreateManagedWidget ( 

"quit", /* widget name */ 

commandWidgetClass, /* widget class */ 
box, /* parent widget*/ 

quit_args, /* argument list*/ 

XtNumber (quit_args) /* arglist size */ 



Notice the use of the XtNumber macro to calculate how many arguments there are in the 
statically initialized argument list. This macro eliminates the need to keep track of the num 
ber of resources you have set 

Note that the value field in the argument list must be in the correct representation type for 
that resource, which is often not a string. You may need to call xt Con vert to arrive at the 
right representation of the data to be placed in the argument list. See Chapter 9, Resource 
Management and Type Conversion, for details on calling xtConvert. 

Unless you invoke a converter, no diagnostic is printed when you specify a resource value 
incorrectly in the argument list. Therefore, make sure you specify these correctly, and recog 
nize this as a possible place to begin looking for bugs. (This is another reason to hardcode 
resources only when the application is almost ready for release. If you do it all at once in a 
methodical fashion, you are less likely to make mistakes than if you are always adding, sub 
tracting, and changing values in the argument lists.) 

3.7.1 .1 Another Way to Set Arguments 

Instead of creating the argument list as a static array, you can allocate storage at run time and 
use the xtSetArg macro to set values into the storage. xtSetArg sets a single argument 
to a resource identifying a constant and a value. Example 3-15 shows the code that would 
create an argument list with the same contents as the one created in Example 3-13 above. 
Some people prefer this technique because it places the argument list setting closer to the 
xtCreateWidget call, making the code easier to read. 

Example 3-15. Setting the argument list with XtSetArg 

int i; 

Arg args [10] ; 

/* Xtlnitialize may be called before or after the XtSetArg calls */ 



i = 0; 



More Widget Programming Techniques 



93 



Example 3-1 5. Setting the argument list with XtSetArg (continued) 

XtSetArg(args[i] , XtNcallback, (XtArgVal) quit_callback_list) ; 
XtSetArg (args [i] , XtNsensitive, (XtArgVal) TRUE); i++; 

banner = XtCreateManagedWidget ( 

banner, /* widget name */ 

commandWidgetClass, /* widget class from Label. h */ 

toplevel, /* parent widget */ 

args, /* argument list */ 

i /* arg list size from XtSetArg counter */ 
); 

Notice that i is used as the number of arguments in the XtCreateManagedWidget call, 
not xt Number. xtNumber would in this case return the value 10, the total length of the 
Arg array. 

Remember that i must be incremented outside the macro, because XtSetArg references its 
first argument twice. The following code will not work because xtNresource2 will be set 
into widget_args [2 ] instead of widget_args [ 1] , as desired. Example 3-16 shows 
you how not to use XtSetArg: 

Example 3-16. Incorrectly setting the argument list with XtSetArg 

Arg arg [10] ; 
int num_args; 

/* This example will NOT work correctly! */ 
num_args =0; 

/* The next two lines are wrong! */ 

XtSetArg (args [num_args++] , XtNresourcel, (XtArgVal) 10); 

XtSetArg (args [num_args++] , XtNresource2, (XtArgVal) 40); 



The xt Set Args method has three advantages over static initialization: 

It moves the code that sets the argument list closer to where it is really used in the call 
to create a widget 

It allows run-time value modification using the same method. 
The same storage can be used for multiple argument lists. 

The disadvantages of the xt Set Args method are as follows: 

It performs all assignments at run time, which slows startup slightly. 

It is possible to try to set more arguments than space has been allocated for, leading to 
a core dump. 

It is possible to misplace the counter increment, leading to improper operation. 

An argument list and a counter variable must be kept until the call to create the widget 
instance; the static method requires keeping only the argument list. 



94 X Toolkit Intrinsics Programming Manual 



It may waste a small amount of storage since the argument list array is usually initial 
ized larger than the required size. 

Lots of xt Set Arg calls make for ugly code. 

As you can see, these differences are mostly subjective, and you may use whichever method 
you prefer, or some combination. 

3.7.1 .2 Merging Argument Lists 

xtMergeArgLists takes two argument lists and counts all arguments, allocates the stor 
age for a single argument list big enough to hold them, and stores all the entries from both in 
the returned argument list. It does not remove duplicate entries. The calling application can 
use xtNumber to determine the resulting argument count (or can add the original counts). 

3.7.2 The Varargs Interfaces 

A varargs interface allows a function to be called with a variable number of arguments. This 
style of interface is standard in other toolkits like XView, since it is much more convenient 
than the methods of setting arguments described above. It allows you to place the 
resource/value pairs to be set directly into the call to create a widget, instead of having to 
store them into an intermediate Arg array and then pass the array to xtCreateManaged- 
Widget. 

A varargs interface to Xt has been developed and adopted as a standard for R4. In addition, 
Dan Heller wrote a library called WidgetWrap that does essentially the same thing and is 
available under R3 (in the R3 distribution in the directory /contrib/widgets/widgetwrap). 

Example 3-17 and Example 3-18 demonstrate typical calls to create widgets using the two 
varargs interfaces to Xt. 

Example 3-17. The WidgetWrap interface to creating a widget 
#include "XI 1 /WidgetWrap. h" 



main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, layout, command; 



layout = WidgetCreate ("layout", formWidgetClass, topLevel, NULL) 

command = WidgetCreate ("command", commandWidgetClass, topLevel, 
XtNwidth, 200, 
XtNheight, 200, 
XtNjustify, XtJustifyCenter, 
XtNsensitivity, TRUE, 
XtNlabel, "Quit", 



More Widget Programming Techniques 



Example 3-17. The WidgetWrap interlace to creating a widget (continued) 

NULL) ; 



Example 3-18. The R4 varargs interface to creating a widget 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, layout, command; 



layout = XtVaCreateManagedWidget ("layout", formWidgetClass, 
topLevel, NULL); 

command = XtVaCreateManagedWidget ("command", commandWidgetClass, 
topLevel, 

XtNwidth, 200, 

XtNheight, 200, 

XtNjustify, XtJustifyCenter, 

XtNsensitivity, TRUE, 

XtNlabel, "Quit", 
NULL) ; 



As you can see, there are two varargs interfaces, and they are identical except for the func 
tion names and the fact that WidgetWrap requires the header file WidgetWrap.h. The 
WidgetWrap version also must be linked with the module WidgetWrap.o. The two interfaces 
do differ in some respects, but these cases do not appear often. Code using WidgetWrap can 
easily be converted to the standard library for Release 4. 

Note that the last argument in both interfaces is NULL, which terminates the variable-length 
argument list. 

The varargs interfaces also provide varargs versions of xtGetValues and xtSet- 
Values, so that argument lists won t be needed for these calls either. 

The varargs interfaces allow you to specify an argument list if you wish, so that if you have 
many widgets that will have the same hardcoded arguments, you can create one argument list 
and pass it to all the widget creation routines, instead of adding all the arguments to every 
widget creation routine. The R4 interface even allows nested argument lists. 

Depending on how you use them, there may be some extra overhead involved in using either 
varargs interface, because they massage the arguments into an argument list and call xt- 
CreateWidget, XtCreateManagedWidget, XtSetValues, or XtGetValues. 
However, the added convenience seems worth it 



96 X Toolkit Intrinsics Programming Manual 



3.8 Application Contexts 

An application context is a structure maintained by Xt that stores the functions registered by 
the application and other information about the application. Primarily, it allows Xt applica 
tions to run without modification on certain operating systems other than UNIX that do not 
have a separate address space for each process. These systems include the Xerox Cedar envi 
ronment, the Symbolics Genera environment, and the TI Explorer system. Although systems 
like this are not common, the goal of all X software in C is to be portable to any system that 
supports C.* 

It is possible to create more than one application context within a single program. This is 
rarely done and its implications are complex, so we will reserve discussion of it until Section 
13.6. 

So far we have shown you only routines that use the default application context invisibly. 
Xt initialize creates a default application context, and several other routines such as 
xtAddActions and XtMainLoop reference it internally. However, writing an applica 
tion this way does not provide the desired portability to the systems described above. There 
is a parallel set of routines to the ones you have used, that have an explicit application con 
text argument For reasons that have to do with the efficiency of the implementation of Xt, 
only the versions that have an explicit argument specifying the application context provide 
the desired portability. The parallel routines have the same names, but with App inserted 
after xt. 

The first argument of the xtApp* parallel routines is an application context ID of type xt- 
AppContext. After that they have the same calling sequence as their nonapp counterparts. 
The XtAppContext ID is returned by XtCreateApplicationContext, or in R4, 
by XtAppInitialize. 

It is fine to use the routines we have shown while developing your application. But when it is 
final, you should convert to the XtApp routines. Converting to the xtApp routines is a 
simple process in R4, but a bit more difficult in R3. R4 provides XtAppInitialize, a 
routine that is very similar to xt Initialize except that its first argument returns the xt- 
AppContext that will be used in subsequent calls to other functions. (XtAppInitialize also 
has several arguments that were not present in xt initialize.) In R3, to use explicit 
application contexts you normally have to call four separate functions. However, we have 
written a routine called RSlnitialize that does this for you. The R3lnitialize 
convenience function is shown later in this section. Its calling sequence is identical to xt- 
Initialize except that the first argument (which is unused in xtlnitialize) is 
replaced by an argument that returns the application context ID. (R3lnitialize works 



*It is almost a maxim that there is no such thing as portable software, only software that has been ported. The goal 
(and more or less the reality) of X is that the porting process should be much easier than it has traditionally been, and, 
most important, that only one version of a particular piece of software should need to be maintained. The various 
idiosyncrasies of particular compilers can be dealt with using conditional preprocessor directives (#ifdef). X features 
were designed specifically to provide ways to handle differences in screens and keyboards. The application context 
is an effort to provide a way to handle odd operating systems. 



More Widget Programming Techniques 97 



under R4, but should be replaced by xtAppinitialize to avoid waste.) Example 3-19 
shows the code necessary to modify a minimal application such as xbox to use explicit appli 
cation contexts. 

Example 3-19. Using R3 Initialize and explicit application contexts 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel; 

XtAppContext app_con; 

/* first argument of Xtlnitialize was unused, 
* replaced by app context return */ 

topLevel = RSInitialize ( 

&app_con, /* application context return */ 

"XBoxl", /* application class name */ 

NULL, /* application resources (not used) */ 

0, /* application resource count */ 

Sargc, /* command-line argument count */ 

argv) ; /* command-line string */ 



|| XtAppMainLoop (app_con) ; 

Of the routines you have seen so far in this book, only xtMainLoop and xtAddActions 
have versions that use explicit application contexts: XtAppMainLoop and xtAppAdd- 
Actions. The complete list of routines that have equivalents is presented in Section 13.6. 

Throughout this book we will continue to use the routines that use the default application 
context, because they are somewhat less cluttered, and because they work in both R3 and R4 
without having to use RSlnitialize. 

3.8.1 Xtlnitialize Equivalents 

RSlnitialize calls a combination of four routines instead of Xtlnitialize: xt- 
Toolkitlnitialize, XtCreateApplicationContext, XtOpenDisplay, 
and XtAppCreateShell. Example 3-20 shows the RSlnitialize routine. 

Example 3-20. RSlnitialize: a substitute for Xtlnitialize that returns an explicit application con 
text 

tinclude <Xll/Intrinsic.h> 
tinclude <Xll/StringDefs.h> 
tinclude <Xll/Shell .h> 

/* Function Name: R3Initialize 

* Description: A convience routine for initializing the toolkit, 

* for use in R3 to use explicit application contexts 

* Arguments: app_context_return - The application context of 

* the application 



98 X Toolkit Intrinsics Programming Manual 



Example 3-20. R3lnitialize: a substitute for Xtlnhialize that returns an explicit application con 
text (continued) 



application_class 

options 

num_options 

argc_in_out, 
argv_in_out 
Returns: The shell widget. 



- The class of the application. 

- The option list. 

- The number of options in the 
above list 

- number and list of command-line 
arguments . 



Widget 

RSlnitialize (app_context_return, application_class, options, 

num_options, argc_in_out, argv_in_out) 
XtAppContext * app_context_return; 
String application_class; 
XrmOptionDescRec *options; 
Cardinal num_options, *argc_in_out; 
String *argv_in_out; 

XtAppContext app_con; 
Display * dpy; 
Widget root; 

XtToolkitlnitialize () ; 

app_con = XtCreateApplicationContext () ; 

dpy = XtOpenDisplay (app_con, (String) NULL, NULL, 
application_class, options, num_options, 
argc_in_out, argv_in_out) ; 

if (dpy == NULL) 

XtErrorMsg ("invalidDisplay", "xtlnitialize", "XtToolkitError", 
"Can t Open display", (String *) NULL, (Cardinal *)NULL); 

root = XtAppCreateShell (NULL, application_class, 

applicationShellWidgetClass, dpy, NULL, 0); 

if (app_context_return != NULL) 

*app_context_return = app_con; 

return (root) ; 

In Release 4, XtApplnitialize provides the same functionality as RSlnitialize 
and more. It lets you pass an argument list for the shell widget which neither xt 
lnitialize nor RSlnitialize allow. 

Note that the XtOpenDisplay routine requires an XtAppContext argument This 
means that if your application opens a connection to more than one server, it must use expli 
cit application contexts. The topic of connecting to multiple displays is discussed more fully 
in Section 13.8. 



More Widget Programming Techniques 



99 



4 



An Example Application 



This chapter describes a complete application, in several iterations. First, it 
shows a simple version of the program, a bitmap editor, as it would be written 
assuming the existence of a BitmapEdit widget (which is actually developed in 
Chapter 5). Then, two refined versions are developed, each demonstrating 
additional Toolkit programming techniques. Finally, the same application is 
shown as it would be written if the bitmap editor were implemented in an appli 
cation window rather than with the BitmapEdit widget. 

In This Chapter: 

xbitmapl: Bitmap Editor Using a BitmapEdit Widget 104 

Widget Public Functions 106 

Application-defaults File 107 

xbitmap2: Adding Scrollbars to Handle Large Bitmaps 107 

Overriding Translations 112 

Action Arguments in the Translation Table 113 

The resize_thumbs Action 113 

Scrollbar Callbacks 114 

xbitmapS: Adding Graphics to Display the Bitmap 116 

Graphics from the Application 119 

Writing a Bitmap File 122 

xbitmap4: Bitmap Editor Without a BitmapEdit Widget 123 




Enough of these trivial programs! Now for an (almost) real application. This chapter 
describes the development of a bitmap editor. Although it is simple, it can be easily extended 
to be quite powerful without any new techniques. 

We will show several versions of xbitmap, beginning with a simple version that assumes the 
existence of a BitmapEdit widget (which will actually be developed in Chapters 5 and 6). 
Subsequent versions add scrollbars, then add two widgets that display the bitmap in small 
scale (one normal, one reverse video), and finally implement the same application without 
the use of the specialized BitmapEdit widget 

These examples will demonstrate the techniques described in Chapters 2 and 3 as they would 
appear in a real application, and will bring up a number of new topics: 

The initial version introduces the bitmap editor application, and demonstrates how the 
application can access the data within a widget using a public function defined by the 
widget class. 

The second version, which adds scrollbars, shows how scrollbars are linked to the win 
dow that they control. 

The third version demonstrates two ways of adding the small-scale bitmaps, one using a 
standard widget and one drawing into a Core widget from the application. 

The fourth version does not use the BitmapEdit widget, but instead implements its fea 
tures by drawing into a Core widget This demonstrates how to prototype features and 
prepare for writing your own widget It also allows us to describe the code necessary to 
implement the bitmap editor so that you will already understand this code when you see it 
in the internal framework of a widget described in Chapters 5 and 6. 

This chapter demonstrates that there are several ways to add any given feature, and describes 
the tradeoffs between the different options. Many features can be added from the application 
code by creating a Core widget to draw into, or by creating a custom widget By the end of 
Chapters 5 and 6, you will have seen how to implement this application entirely with existing 
widgets and application code, how to implement it using custom widgets, and how to imple 
ment a mixture of the two. 



An Example Application 1 3 



4.1 xbitmapl : Bitmap Editor Using a BitmapEdit Widget 

The screen appearance of xbitmapl is shown in Figure 4-1. As usual, it is a good idea to 
compile and run each example as it is discussed.* 




Figure 4-1. xbitmapl: how it looks on the screen 

The BitmapEdit widget lets you set bits in the visible bitmap by clicking the first pointer but 
ton or dragging the pointer with the first button held down, lets you erase bits using the sec 
ond button, or lets you toggle bits using the third button. The "Print Output" button simply 
prints on the standard output an array of 1 s and O s representing the set and unset bits in the 
bitmap. (Code to read and write standard XI 1 bitmap files is added in a later version.) 

xbitmapl consists of only five widgets other than the top-level Shell; one Form, one Box, one 
BitmapEdit, and two Command widgets. The Form widget is the child of the Shell widget. 
One child of the Form widget is a Box containing the two Command widgets, and the other is 
the BitmapEdit widget This arrangement of geometry-managing widgets keeps the appear 
ance of the application neat even when the application is resized. 

The code for xbitmapl is shown in Example 4-1. One new technique shown in this example 
is the use of the public function BitmapEditGetArrayString defined by the Bitmap- 
Edit widget This function allows an application callback function to access the BitmapEdit 
widget s private data. Even though the array of bits in the bitmap is a resource of the 
BitmapEdit widget that can be read with xtGetValues, this public function provides a 

*How to get and compile the example source code is described in the Preface and Section 2.3.2. 



104 



X Toolkit Intrinsics Programming Manual 



more convenient way for the application to get the contents of the bitmap so that it can print 
them out 

Example 4-1. xbitmapl: complete code 

/* 

* xbitmap.c an example application 
*/ 

tinclude <stdio.h> 
tinclude <Xll/Intrinsic.h> 
tinclude <Xll/StringDef s .h> 

tifdef X11R4 

tinclude <Xll/Xaw/Form.h> 

tinclude <Xll/Xaw/Box.h> 

tinclude <Xll/Xaw/Command.h> 

telse 

tinclude <Xll/Form.h> 

tinclude <Xll/Box.h> 

tinclude <X11 /Command. h> 

tendif /* X11R4 */ 

tinclude "BitmapEdit .h" 

Dimension pixmap_width_in_cells, pixmap_height_in_cells; 

/* 

* The printout routine prints an array of 1 s and O s representing 

* the contents of the bitmap. This data can be processed into any 

* desired form, including standard Xll bitmap file format. 
*/ 

/* ARGSUSED */ 

static void 

printout (widget, client_data, call_data) 

Widget widget; 

caddr_t client_data, call_data; /* unused */ 

{ 

int x, y; 

char *cell; 

cell = BitmapEditGetArrayString (widget) ; 

(void) putchar ( \n ); 

for (y = 0; y < pixmap_height_in cells; y++) { 
for (x = 0; x < pixmap_width_in_cells; x++) 

(void) putchar (cell [x + y * pixmap_width_in_cells] 

? 1 : ) ; 
(void) putchar ( \n ) ; 
} 

(void) putchar ( \n ); 
} 

main(argc, argv) 
int argc; 
char *argv[] ; 
{ 

Widget topLevel, form, buttonbox, quit, output, bigBitmap; 

int i; 

Arg arg[5]; 
extern exit () ; 



An Example Application 10S 



Example 4-1. xbitmapl: complete code (continued) 



static XrmOptionDescRec tablet] = { 

{"-pw", "*pixmapWidthInCells", 

{ "-pixmapwidth", ^pixmapWidthlnCells", 
{"-ph", "*pixmapHeightInCells 

{ "-pixmapheight", n *pixmapHeightInCells 
{"-cellsize", "*cellSizeInPixels", 



XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 

XrmoptionSepArg, NULL}, 



topLevel = Xtlnitialize (argv [0] , "XBitmapl 1 
XtNumber (table) , &argc, argv); 



table, 



} 



form = XtCreateManagedWidget ("form", formWidgetClass, 
topLevel, NULL, 0) ; 

buttonbox = XtCreateManagedWidget ("buttonbox", boxWidgetClass, 
form, NULL, 0) ; 

output = XtCreateManagedWidget ("output", commandWidgetClass, 
buttonbox, NULL, 0) ; 

XtAddCallback (output, XtNcallback, printout, NULL); 

quit = XtCreateManagedWidget ("quit", commandWidgetClass, 
buttonbox, NULL, 0); 

XtAddCallback (quit, XtNcallback, exit, NULL); 

bigBitmap = XtCreateManagedWidget ("bigBitmap", 
bitmapEditWidgetClass, form, NULL, 0); 

/* need the following values for the printout routine. */ 

i = 0; 

XtSetArg(arg[i] , XtNpixmapWidthlnCells, 

&pixmap_width_in_cells) ; i++; 
XtSetArg(arg[i] , XtNpixmapHeightlnCells, 

&pixmap_height_in_cells) ; 
XtGetValues (bigBitmap, arg, i) ; 

XtRealizeWidget (topLevel) ; 
XtMainLoopO ; 



You should recognize the options table as the one described in Section 3.6.2. Note that 
xbitmapl does not require application resources, because there is nothing for them to set 
The widgets themselves provide all needed resources. 



4.1.1 Widget Public Functions 

Public functions are supplied by a widget class when it wants certain data to be readable or 
writable by the application, but for some reason does not want the data both readable and 
writable as would be the case if it were a resource. Sometimes the application needs to be 
able to read data but not write it At other times, a widget class has features that it wants con 
trollable from the application but never user-customizable (because they are meaningless at 
startup, for example), and therefore it provides a function for setting them. 



106 



X Toolkit Intrinsics Programming Manual 



The BitmapEdit widget provides a public function because this version does not allow the 
application to set the bitmap, and because it is easier for the programmer to get the array with 
a specialized function than through xt Get Values. A more complete bitmap editor widget 
would need to make the array of bits a resource, so that the application could read bitmap 
files. 



4.1.2 Application-defaults File 

Example 4-2 shows the application-defaults file for xbitmapl . It sets the text in the Com 
mand widgets, the size in cells of the bitmap, the size in pixels of each cell in the bitmap, and 
the foreground color, and constrains the bigBitmap widget to appear below the button 
box. Without this constraint, the Form widget would place the button box overlapping big- 
Bitmap instead of above it 

Example 4-2. XBitmapl: application-defaults file 

*quit*label: Quit 
*output*label : Print Array 
*cellSizeInPixels: 30 
*pixmapWidthInCells: 20 
*pixmapHeightInCells: 20 
*foregroundPixel: blue 
*buttonbox. width: 200 
*bigBitmap*fromVert : buttonbox 



4.2 xbitmap2: Adding Scrollbars to Handle Large Bitmaps 

xbitmapl always displayed all the cells in the bitmap being edited. This can be inconvenient 
when the bitmap is large. For example, this makes it difficult to edit any bitmap larger than 
one-fifth of the screen (because each cell takes up a minimum of five pixels). The solution to 
this problem is to add scrollbars, and to display only part of the bitmap at a time. We ll add 
this feature to develop xbitmap2, shown in Figure 4-2. 

The easy way to add scrollbars is to use a widget provided just for this purpose, such as the 
Athena Viewport widget Simply by inserting a Viewport widget into the instance hierarchy 
between the Form widget and the BitmapEdit widget and providing the right resource set 
tings, scrollbars will appear around the BitmapEdit widget This example program is 
included with the source distribution as xbitmapS, but is not described here because it is a 
simple improvement from xbitmapl . 



An Example Application 



Print Array Quit 




Figure 4-2. xbitmap2: scrollbars added 

The Viewport widget, like the Dialog widget described in the last chapter, is really just a 
Form widget, two Scroll widgets, and the code to link them together. The window displayed 
is blank until you create a widget like BitmapEdit as a child of Viewport This child can be a 
composite widget with children of its own, if desired.* 

As an exercise, we ll pretend that we don t have the Viewport widget; we ll create scrollbars 
and link them with the BitmapEdit widget directly from the application. Scrollbars are inter 
esting because they need to be very tightly coupled with the window they are controlling. 
Whenever the user clicks or drags in the scrollbar, the controlled window must quickly 
redisplay the correct part of its contents. Each scrollbar widget provides at least two call 
backs: one for jump scrolling and one for smooth scrolling. Typically, the first and third but 
tons initiate jump scrolling by one screenful up and down, respectively, while the second but 
ton moves the thumb to the pointer position and smoothly scrolls the window up or down if 
the pointer is dragged while the button is held down. 



*Of course, it is also possible to create a widget similar to Viewport that combines BitmapEdit and scrollbars into a 
single unit This widget could be a subclass of a geometry managing widget such as Form, and would create a 
BitmapEdit widget and the scrollbar widgets as children. It would add the code necessary to create the child widgets 
and link the scrollbars with BitmapEdit. This widget is described in Chapter 1 1 , Geometry Management. 



108 



X Toolkit Intrinsics Programming Manual 



The application controls the position and length of the scrollbar thumb. The length of the 
thumb must reflect the percentage of the data that is currently in view, and the position must 
reflect the current position in the data. Only the application knows how much data there is: 
The application must set the thumb as the scrollbar widget is created, and reset the thumb in 
each of its callbacks. When the scrollbars are resized, this indicates that the accompanying 
window has also been resized, and therefore the portion of the data being shown has changed. 
Therefore, the thumb must also be reset in the procedure that handles resizes. 

We will use the Athena Scroll widget class in this example. Before proceeding further, it 
might be helpful to read the Scroll widget reference page in Volume Five, X Toolkit Intrinsics 
Reference Manual, to get an understanding of the basic operation of the widget. Other 
widget sets have scrollbar widgets that interact with the application in similar ways. 

Two Scroll widgets are created, one for horizontal and one for vertical scrolling. 

Another level of composite widget (a Form widget) is added to manage the BitmapEdit 
widget and Scroll widgets as a unit. The instance hierarchy ofxbitmap2 is shown in Fig 
ure 4-3. 

Two callback functions are added for each scrollbar, to perform the two kinds of scrolling 
(smooth and jump scrolling). 

An action is created to reset the scrollbar thumbs when the application is resized. This 
action is registered with Xt as usual, and added to the existing translation table of the 
Scroll widgets using XtOverrideTranslations. 



An Example Application 



TopLevelShell 

in 

form-- Form 

I T 



drawingForm 



Form 



buttonbox - Box 



















BitmapEdit; Scroll 


Scroll 



bigBitmap 



scrollVert 



T 

scrollHoriz 



Command Command 



Core 



Core 



quit 



output showNormalBitmap showReverseBitmap 






Figure 4-3. The instance hierarchy ofxbitmap2 

Example 4-3 shows the code needed to add scrollbars to xbitmopl . 

Example 4-3. xb rtmap2: adding scrollbars 

create_viewport (parent) 

Widget parent; 

{ 

Widget scrollHoriz, scrollVert, drawingForm; 

Arg args [6] ; 

int i; 

int cell_size; 

static XtActionsRec window_actions [ ] = { 
{ "resize_thumbs", resize_thumbs} 

}; 

XtAddActions (window_actions, 1); 

drawingForm = XtCreateManagedWidget ("drawingForm", 
formWidgetClass, parent, NULL, 0) ; 

bigBitmap = XtCreateManagedWidget ("bigBitmap", 

bitmapEditWidgetClass, drawingForm, NULL, 0); 

i = 0; 

XtSetArg(args[i] , XtNpixmapHeightlnCells, 
&pixmap_height_in_cells) ; 



110 



X Toolkit Intrinsics Programming Manual 



Example 4-3. xbitmap2: adding scrollbars (continued) 

XtSetArg(args[i] , XtNpixmapWidthlnCells, 

&pixmap_width_in_cells) ; i++; 

XtSetArg(args[i] f XtNcellSizelnPixels, &cell_size) ; 
XtGetValues(bigBitmap, args, i) ; 

pixmap_height_in_j>ixels = pixmap_height_in_cells * cell size; 
pixmap_width_in_pixels = pixmap_width_in_cells * cell_sTze; 

window_width = ( (pixmap_width_in_pixels > MAXSIZE) ? MAXSIZE 

: pixmap_width_in_pixels) ; 
window_height = ( (pixmap_height_injpixels > MAXSIZE) ? MAXSIZE 

: pixmap_height_injpixels) ; 

i = 0; 

XtSetArg(args[i] , XtNwidth, window_width) ; 
XtSetArg(args[i] , XtNheight, window_height) ; 
XtSetValues (bigBitmap, args, i) ; 

i = 0; 

XtSetArg(args[i] , XtNorientation, XtorientVertical) ; 
XtSetArg(args[i] , XtNheight, window_height) ; 
XtSetArg(args[i] , XtNwidth, 15); i++; 
XtSetArg(args[i] , XtNshown, 

window_height/pixmap_height_in_pixels) ; 



scrollVert = XtCreateManagedWidget ("scrollVert", 
scrollbarWidgetClass, drawingForm, args, i) ; 

XtAddCallback (scrollVert, XtNscrollProc, scroll_up_down, 

bigBitmap) ; 
XtAddCallback (scrollVert, XtNthumbProc, thumb_up_down, 

bigBitmap) ; 

XtOverrideTranslations (scrollVert, 

XtParseTranslationTable ("<Configure>: resize_thumbs (v) ") ) 

i = 0; 

XtSetArg(args[i] , XtNorientation, XtorientHorizontal) ; 
XtSetArg(args[i] , XtNwidth, window_width) ; 
XtSetArg(args[i], XtNheight, 15); i++; 
XtSetArg(args[i] , XtNshown, 

window_height/pixmap_height_in_pixels) ; 

scrollHoriz = XtCreateManagedWidget ("scrollHoriz", 
scrollbarWidgetClass, drawingForm, args, i) ; 

XtAddCallback (scrollHoriz, XtNscrollProc, scroll_left_right, 

bigBitmap) ; 
XtAddCallback (scrollHoriz, XtNthumbProc, thumb_left_right, 

bigBitmap) ; 
XtOverrideTranslations (scrollHoriz, 

XtParseTranslationTable ("<Conf igure>: resize_thumbs (h) ") ) ; 
} 

The create_viewport routine is called from main just before calling XtRealize- 
widget and XtMainLoop. Think of it as a substitute for the call that created the Bitmap- 
Edit widget alone. It is passed the parent widget, which, as in xbitmopl , is a Form widget 
whose other child is a Box containing Command widgets. create_viewport creates 
another Form widget to manage the Scroll widgets and the BitmapEdit widget. The routine 



An Example Application 111 




next gets the pixmap dimensions and cell size from the BitmapEdit widget; these will be 
needed in several places in the application, such as in the code that makes the scrollbars the 
same size as the BitmapEdit widget 

Next, create_viewport creates an argument list for each call to create a scrollbar. The 
arguments set the length and width of each scrollbar, its orientation, and the length of the 
thumb (the xtNshown resource). After creating each widget, the application s two callback 
functions are registered for that widget Notice that the ID of the BitmapEdit widget is 
passed to the callback functions. The callback functions will use this information to get 
resource values from the BitmapEdit widget 

The resize_thumbs action (shown in Section 4.2.3) simply resets the length of the 
thumb to represent the current amount of the data being shown, using a public function of the 
Scroll widget It is invoked whenever the scrollbars are resized, because when the scrollbars 
change size that means the viewing window also changed size and now displays a different 
portion of the bitmap. The event that indicates that a widget has been resized is the 
Conf igureNotif y event, indicated in the translation table as Configure. 

4.2.1 Overriding Translations 

Finally, create_viewport calls XtOverrideTranslations to make Xt call the 
application function resize_thumbs in response to resize and expose events. The 
res ize_t numbs routine sets the thumb to the proper length (and as a side effect, the 
Scroll widget redraws the thumb). This brings up a number of questions. Why call Xt 
OverrideTranslations instead of XtSetValues? Also, this translation table 
includes action functions with arguments. How do these work? 

Setting the xtNtranslations resource of a widget replaces the existing translations of 
that widget The problem in this case is that there is no reason to reset translations that we 
don t need to change but that the Scroll widgets need to function. Furthermore, we want the 
user to be able to configure certain translations, but not the ones that are essential if the appli 
cation is to function. That s why Xt provides two functions for adding translations to an 
existing table: XtOverrideTranslations and XtAugmentTranslations. 
Actions do not work like callback lists there can be only one action mapped to a particular 
event or event sequence. The difference between XtOverrideTranslations and Xt 
AugmentTranslations is in what happens when both the new and existing translation 
tables have an entry for the same event sequence, but a different action. XtAugment 
Translations uses the old translation, whereas XtOverrideTranslations uses 
the new translation. 

You should be careful when using XtOverrideTranslations not to override any 
translations that a widget depends on to function. In this case, the application overrides the 
translation that invokes the Scroll widget s expose and resize code, but this is acceptable 
because Scroll does not depend on this code. The Scroll widget automatically redraws its 
contents, the thumb, in response to the Scroll widget s public function XawScrollBar- 
SetThumb. As long as the application takes over the responsibility to call this at the right 
times, the Scroll widgets will be properly updated. 



/ 12 X Toolkit Intrinsics Programming Manual 



Action Arguments in the Translation Table 

Notice that the translation tables specified in the calls to xtOverrideTranslations in 
Example 4-4 supply either a v or an h argument to the action routine resize_thumbs. 
Xt passes this argument as the call_data argument to the action routine. This trick sim 
ply allows one action routine to serve both the horizontal and vertical scrollbars. This code 
could also have been written with two independent action routines. It is better to have inde 
pendent action routines when the applicable translations are user-configurable (which they 
are not, in this case). 

Remember that since the translation table is a string, the argument placed in the translation 
table is passed to the action routine as a string. This argument, therefore, is basically a con 
stant hardcoded into each translation table. It cannot be used in the same way that the 
client_data argument of callback functions can be used, to pass general data into an 
action routine. 

The action argument is not limited to a single string. You can place a series of words 
separated by spaces between the parentheses after an action in the translation table. These 
words will be passed into the action in the third argument, pa rams, which is an array of 
strings just like argv. The fourth argument is the number of parameters, num_j)arams, 
analogous to argc. This multiple-parameter feature is rarely used. 

Also remember that translation tables must be compiled with xtParseTranslation- 
Table before passing them to XtOverrideTranslations, xtAugment- 
Translations, or in an argument list passed to XtSetValues. 



4.2.3 The resize_thumbs Action 

Now, let s move on to the routine referenced in this translation table, resize_thumbs. 
Example 4-4 shows this code. It simply sets the thumb of either scrollbar based on the cur 
rent position of the data and the size of the BitmapEdit widget s window. 

Example 4-4. xbitmap2: resize_thumbs routine 

/* ARGSUSED */ 

static void 

resize_thumbs (w, event, orientation) 

Widget w; 

XEvent *event; 

char *orientation[] ; /* String *params; */ 

/* Cardinal num_params; (not needed) */ 

{ 

Dimension width, height; 
int cur_x, cur_y; 
Arg args [5] ; 
int i; 

i = 0; 

XtSetArg(args[i] , XtNheight, Sheight) ; 

XtSetArg(args[i], XtNwidth, Swidth) 

XtSetArg(args[i], XtNcurX, &cur_x) ; 



An Example Application 



Example 4-4. xbitmap2: resizejthumbs routine (continued) 

XtSetArg(args[i] , XtNcurY, &cur_y) ; i++; 
XtGetValues (bigBitmap, args, i) ; 

if (*orientation[0] == h ) 
fifdef X11R4 

XawScrollBar Set Thumb (w, 
#else 

XtScrollBarSetThumb (w, 
#endif /* X11R4 */ 

(float)cur_x/pixmap_width_in_pixels, 

(float) width/pixmap_width_in_pixels) ; 
else 
tifdef X11R4 

XawScrollBarSetThumb (w, 
felse 

XtScrollBarSetThumb (w, 
#endif /* X11R4 */ 

(float)cur_y/pixmap_height_in_pixels, 

(float) height/pixmap_height_in_pixels) ; 
} 

The XawScrollBarSetThumb routine is defined by the Scroll widget class.* It provides 
an easy method for applications to set the position and length of the thumb. The Scroll 
widget also has resources that set these same parameters. 

Note that re size_t bombs is called in response to Expose events as well as during 
resizing. This is because the application never knows exactly how much screen space it will 
be allocated by the window manager. Its size when it appears on the screen may not be the 
size specified in the code or in the resource databases since the user may intervene to resize 
the application between two existing windows. Therefore, it is futile to set the thumb when 
the Scroll widgets are created, because the size of the thumbs has to be recalculated based on 
the current size of the window. 



4.2.4 Scrollbar Callbacks 

The callback functions for each scrollbar are very similar to resize_thumbs. They also 
reset the thumb, but add code that moves the thumb in proportion to the pointer position. 
Example 4-5 shows the callback functions for the vertical scrollbar. The horizontal scrollbar 
has two analogous callback functions. 

Example 4-5. xbitmap2: scrolling callback functions 

/* ARGSUSED */ 

static void 

scroll_up_down (w, unused, pixels) 



*In Release 3 and earlier, all public functions declared by widgets in the Athena widget set had the Xt prefix. This 
was incorrect Only routines defined by the Xt library should have the Xt prefix, because it is important to distinguish 
the fact that Xt routines are an X Consortium standard, while the Athena widgets are not Public functions defined by 
other widget sets will have their own distinctive prefix. As of Release 4, all Athena widget public functions have the 
prefix Xaw. 



114 X Toolkit Intrinsics Programming Manual 



Example 4-5. xbitmap2: scrolling callback functions (continued) 

Widget w; 
caddr_t unused; 
int pixels; 
{ 

Dimension height; 

int cur_y; 

Arg args [5] ; 

int i; 

i = 0; 

XtSetArg(args[i] , XtNheight, sheight) ; 
XtSetArg(args[i] , XtNcurY, &cur_y) ; 
XtGetValues(bigBitmap, args, i); 

/* When pixels is negative, right button pressed, move 

* data down, thumb moves up. Otherwise, left button 

* pressed, pixels positive, move data up, thumb down. 
*/ 

cur_y += pixels; 

/* limit panning to size of bitmap */ 
if (cur_y < 0) 

cur_y = 0; 
else if (cur_y > pixmap_height_in_pixels - height ) 

cur_y = pixmap_height_in_pixels - height; 

i = 0; 

XtSetArg(args[i] , XtNcurY, cur_y) ; i++; 

XtSetValues (bigBitmap, args, i) ; 

#ifdef X11R4 

XawScrollBarSetThumb (w, 
telse 

XtScrollBarSetThumb (w, 
#endif /* X11R4 */ 

(float) cur_y/pixmap_height_in_pixels, 
(float ) height/pixmap_height_in_pixels) ; 
} 

/* ARGSUSED */ 

static void 

thumb_up_down (w, unused, percent) 

Widget w; 

caddr_t unused; 

float percent; 

{ 

Dimension height; 

int cur_y; 

Arg args [5] ; 

int i; 

i = 0; 

XtSetArg(args[i] , XtNheight, &height) ; i-H-; 
XtSetArg(args[i] , XtNcurY, &cur_y) ; i++; 
XtGetValues (bigBitmap, args, i) ; 

if ( (cur_y = (int) (pixmap_height_in_pixels * percent) ) >= 

pixmap_height_in_pixels - height) 
cur_y = pixmap_height_in_pixels - height; 



An Example Application 1 15 



Example 4-5. xbitmap2: scrolling callback functions (continued) 

i = 0; 

XtSetArg(args[i] , XtNcurY, cur_y) ; i++; 

XtSetValues (bigBitmap, args, i) ; 

tifdef X11R4 

XawScrollBarSetThumb (w, 
telse 

XtScrollBarSetThumb (w, 
#endif /* X11R4 */ 

(f loat)cur_y/pixmap_height_in_pixels, 
(f loat)height/pixmap_height_in_pixels) ; 
} 

Note that the scroll_up_down callback is called with the pixels argument, which 
describes the vertical position of the button press from the top of the widget. If the left but 
ton was pressed, this number is positive, and for the right button it is negative. This routine 
moves the thumb by this amount, unless the data being shown is already at one of the 
extremes. In effect, the thumb and data are moved an amount proportional to the vertical dis 
tance between the top of the scrollbar and the point where the button press occurred. 

The thumb_up_down callback moves the top of the thumb to the position where the but 
ton press occurred. Since this callback is called repeatedly if the pointer is dragged while the 
button is pressed, it lets the user scan up and down through the data. 

Notice that both callback functions set the cur_x and cur_y resources of BitmapEdit. 
This is how the application tells BitmapEdit which part of the bitmap to display. You ll see 
how this works in Section 4.4, where the code to implement the bitmap editor from the appli 
cation is described. 



4.3 xbitmapS: Adding Graphics to Display the Bitmap 

In addition to displaying the bitmap in editable form, with one cell for each pixel in the 
actual bitmap, a bitmap editor should also display an image in true scale that shows what the 
bitmap really looks like when displayed on the screen. It is customary to present this bitmap 
in both normal and reverse video, and update it every time the user toggles a cell in the 
enlarged bitmap. Figure 4-4 shows the appearance of the application with this feature added. 
There are two ways to implement this behavior. One is to use the Label widget, which can 
display a pixmap instead of a string. The other is to draw into a Core widget. From the point 
of view of the user, both would look exactly the same. 

Implementing this feature with Label widgets is straightforward; the application creates two 
pixmaps of the proper size, and sets the xtNpixmap resources of two Label widgets to dis 
play them. The problem comes when trying to update this display each time a cell is toggled. 
We can easily draw the changed pixel into the small pixmaps, but without a push the Label 
widget won t redisplay the pixmap. Because the XtNpixmap resource is not chang 
ing the same pixmap ID is used for the life of the application the Label widget is not 
notified by Xt that the pixmap has been drawn into. There are two ways to make the existing 
Label widget redraw the pixmap; one is to clear its window using an Xlib routine that 



1 16 X Toolkit Intrinsics Programming Manual 




Figure 4-4. xbitmapS: true-scale normal and reverse bitmaps added 

generates an Expose event, which will then cause Label to redraw the widget But this 
causes the pixmap to flash annoyingly every time a pixel is changed, since the server clears 
each window to its background color before the pixmap is redrawn. If you would like to see 
this problem, or the code to implement this approach, compile and run xbitmopd. The second 
method, which avoids the flashing problem, is to synthesize an Expose event (create an 
XExposeEvent structure and fill it with values) and send it to the Label widget using 
XSendEvent. This is a bit of a kludge but it works. 

The source of this (surmountable) problem is that the Label widget is designed for static pix- 
maps. If it provided a public function called XawLabelRedrawPixmap, we could more 
cleanly correct the flashing bug. Although adding this function to the widget code would be 
easy, we could no longer call the remaining widget class Label. We would be creating a new 
widget class. (Some widget sets do in fact define two separate widget classes, one for dis 
playing static pixmaps, the other for dynamic, editable pixmaps.) 

An alternate approach is to create Core widgets for each small pixmap and draw into them 
from the application, as illustrated in Figure 4-5. This way we can redraw each pixmap with 
out clearing the window in between each update, eliminating the flash. We can consider this 
approach because these small pixmap widgets have no input semantics and simple output 
semantics and should be easy to implement 



An Example Application 



117 



Application 
draws to 
pixmap 
only... 




...then 
copies 
pixmap 
to widget 
window 




Figure 4-5. Application draws into Pixmap and copies it to widget window 

Three new routines are needed: redraw_small_picture, set_up_things, and 
cell_toggled. These three routines are primarily composed of Xlib calls that set up for 
and perform graphics. The redraw_small_picture routine copies a pixmap into a 
widget, set_up_things creates the pixmaps and the GCs needed to draw into these pix- 
maps, and cell_toggled is a callback function registered with the BitmapEdit widget 
that updates the pixmaps whenever a cell is toggled. Code is also added to main to create 
the two Core widgets and give them translations so that they are redrawn on Expose events. 
We ll show these routines one at a time. Example 4-6 shows the improvements to the main 
routine. 

Example 4-6. xbitmapS: implementing small pixmaps by drawing into Core widgets 

main(argc, argv) 
int argc; 
char *argv[] ; 
{ 

Widget toplevel, form, buttonbox, quit, output; 

static XtActionsRec window_actions [ ] = { 
{ n redraw_small_picture", redraw_small_picture} 

}; 

String trans = "<Expose>: redraw_small_picture () "; 

bigBitmap = XtCreateManagedWidget ("bigBitmap", 
bitmapEditWidgetClass, form, NULL, 0) ; 

XtAddCallback (bigBitmap, XtNcallback, cell_toggled, NULL); 
XtAddActions (window actions, XtNumber (window actions)); 



i = 0; 



118 



X Toolkit Intrinsics Programming Manual 



Example 4-6. xbitmapS: implementing small pixmaps by drawing into Core widgets (con 
tinued) 



XtSetArg(args[i] , XtNwidth, pixmap_width_in_cells) ; 
XtSetArg(args[i] , XtNheight, pixmap_height_in_cells) ; 
XtSetArg(args[i] , XtNtranslations, 

XtParseTranslationTable (trans) ) ; i++; 
showNormalBitmap = XtCreateManagedWidget ("showNormalBitmap", 

widgetClass, buttonbox, args, i) ; 

showReverseBitmap = XtCreateManagedWidget ("showReverseBitmap", 
widgetClass, buttonbox, args, i) ; 

XtRealizeWidget (toplevel) ; 
XtMainLoop { ) ; 

II } 

Core widgets are created using the class pointer widgetClass, rather than core- 
widget Class as you might have expected.* The include files for Core (and Composite 
and Constraint) are included by <XlllIntrinsics.h> and therefore don t need to appear in the 
application. 

Note that the size of the Core widget must be set before the Core widgets are realized (either 
in the application or in the application-defaults file), since the Core widget has a default size 
of zero and Xt does not allow widgets with a size of zero. Here we use xt Set Arg to set the 
size in the argument list used to create the widgets. The same argument list is used to create 
both widgets. 

The main routine arranges for the redraw_small_picture routine to be called when 
ever an Expose event arrives for either Core widget, and registers the cell_toggled 
callback with the BitmapEdit widget These routines depend on the setup performed in 
set_up_things. 

4.3.1 Graphics from the Application 

Drawing in the X Window System is done by creating a graphics context (GC) that specifies 
such things as colors and line widths, and then calling a drawing routine that specifies what 
shape is to be drawn. These two steps are basic to X and required in programs written in any 
language with or without a toolkit. For example, the call to draw a line specifies only the 
start and endpoints of the line. The GC specifies everything else about how the server will 
actually draw this line. 

A GC is a server-side object that must be created by the application. The purpose of the GC 
is to cache on the server side information about how graphics are to be executed by the 
server, so that this information doesn t have to be sent over the network with every graphics 
call. If X did not have GCs, every graphics call would have many arguments and this would 
waste network time (and be annoying to program). Instead, you create a small number of 
GCs before drawing (in the startup phase of the application), each representing a particular 
color or line style you will need to draw in at some point, and then specify one of these GCs 



*As of Release 4, coreWidgetClass will also woik. 



An Example Application 



in each call to draw. For example, to draw text and be able to highlight it at will, it is cus 
tomary to create two GCs, one for drawing in white on black, and one for drawing in black 
on white (where colors can be substituted for black and white on color screens). 

Once created, a GC is referred to by its ID, of type GC. This ID is specified in calls to draw 
using that GC. 

From the application, the Xlib routine XGreateGC is usually used to create GCs. Xt also 
provides the xtGetGC routine for creating GCs, but it is typically used only inside widget 
code when there could be many of the same GCs created. XtGetGC is very similar to 
XGreateGC, except that it arranges for GCs to be shared among widgets (within one appli 
cation). XtGetGC will be described in Section 6.1. 

Xt does not provide drawing calls of its own. You must call Xlib directly to draw. An Xlib 
drawing routine is known as a primitive. Under X, text is drawn by a graphics primitive, just 
as lines, arcs, and other graphics are drawn. 

Colors are normally specified by the user as strings such as "blue," but the X server under 
stands colors only when specified as numbers called pixel values. A pixel value is used as an 
index to a lookup table called a colormap, which contains values for the RGB (red-green- 
blue) primaries used to generate colors on the screen. However, a particular pixel value does 
not necessarily always map to the same color, even when run twice on the same system, 
because the contents of the colormap are configurable on most color systems. The wide vari 
ation of graphics hardware that X supports has required that the design of color handling in X 
be very flexible and very complex. 

Fortunately, as long as your widget or application requires only a small number of colors, and 
you do not particularly care whether the colors you get are exactly the colors you requested, 
Xt provides a simplified interface. It hides the actual Xlib calls involved in the Resource 
Manager s converter routines. As described in Chapter 3, if you specify application 
resources for colors in a resource list, Xt will automatically convert color names specified as 
resource settings into pixel values. If you need to do more advanced color handling, then you 
will need to make Xlib calls yourself. For a description of Xlib s color handling, see Chapter 
7, Color in Volume One, Xlib Programming Manual. 

All the versions of xbitmap so far in this chapter work either in color or monochrome, since 
the widgets they create can have their color set by resources. (They default to black and 
white, even on a color screen.) However, to support color in the small pixmaps we are creat 
ing takes more work. We would need to add application resources to get the pixel values that 
will be set into the GCs used in drawing, as described in Section 3.5. 

In xbitmapS, the set_up_things routine is responsible for creating two pixmaps that act 
as drawing surfaces, and two GCs that will be used to draw and undraw pixels in the pix 
maps. Whenever the Core widgets need updating, the pixmaps are copied into the widgets. 
This is only one possible approach to adding this feature. Another is to draw the required 
points directly into the Core widgets each time they need updating, keeping a record of the 
drawn points so that the entire widget can be redrawn in case of exposure. 
set_up_things is shown in conjunction with the next version of xbitmap, xbimap4, at 
the end of this chapter. 



120 X Toolkit Intrinsics Programming Manual 



Example 4-7 shows the cell_toggled routine. As you may recall, this routine is a call 
back function registered with the BitmapEdit widget, to be called whenever a cell is toggled. 

Example 4-7. xbhmap3: the cell_toggled routine 

/* ARGSUSED */ 

static void 

cell_toggled(w, unused, info) 

Widget w; 

caddr_t unused; /* client_data */ 

caddr_t info; /* call_data */ 

{ 

BitmapEditPointlnfo *cur_info = (BitmapEditPointlnfo *) info; 

/* 

* Note, BitmapEditPointlnfo is defined in BitmapEdit. h 
*/ 

XDrawPoint (XtDisplay (w) , normal_bitmap, ( (cur_info->mode 

== UNDRAWN) ? draw_gc : undraw_gc) , cur_info->newx, 

cur_inf o->newy) ; 
XDrawPoint (XtDisplay (w) , reverse_bitmap, ( (cur_info->mode 

== UNDRAWN) ? undraw_gc : draw_gc) , cur_inf o->newx, 

cur_info->newy) ; 

redraw_small_picture (showNormalBitmap) ; 
redraw_small_picture (showReverseBitmap) ; 
} 

Note that BitmapEdit passes a structure called BitmapEditPointlnfo into the callback 
function as an argument. This structure is defined in the public include file, BitmapEdit. h, 
and it provides the information necessary to keep the small bitmaps displaying the same pat 
tern as BitmapEdit. The fields of BitmapEditPointlnfo are the mode (whether drawn 
or undrawn) and the coordinates of the point toggled. The cell_toggled routine draws 
points into the pixmaps according to the information passed in, and then calls 
redraw_small_picture to copy the pixmaps into each Core widget 

The first line of cell_toggled casts the generic pointer info into the structure type 
defined by BitmapEdit, BitmapEditPointlnfo. This can also be done (perhaps more 
clearly) by declaring the info argument as type BitmapEditPointlnfo in the first 
place. However, some programmers have a preference for using a cast. 

The redraw_small_j>icture routine is shown in Example 4-8. 

Example 4-8. xbitmapS: the redraw_small_picture routine 

static void 

redraw_small_picture (w) 
Widget w; 
{ 

Pixmap pixmap; 

if (w == showNormalBitmap) 

pixmap = normal_bitmap; 
else 

pixmap = reverse_bitmap; 

/* 

* Note that DefaultGCOfScreen is one plane on monochrome 



An Example Application 12 1 



Example 4-8. xbitmapS: the redraw_small_picture routine (continued) 

* screens, but multiple planes on color screens. The GCs 

* created in set_up_things are always single plane. 
*/ 

if (Def aultDepthOf Screen (XtScreen (w) ) == 1) 

XCopyArea(XtDisplay (w) , pixmap, XtWindow(w), 
Def aultGCOf Screen (XtScreen (w) ), 0, 0, 

pixmap_width_in_cells, pixmap_height_in_cells, 0, 0) ; 
else 

XCopyPlane (XtDisplay (w) , pixmap, XtWindow(w), 
DefaultGCOf Screen (XtScreen (w) ), 0, 0, 

pixmap_width_in_cells, pixmap_height_in_cells, 0, 0, 1) 
} 

This routine is called from cell_toggled and by Xt in response to Expose events 
because we registered it as an action and specified it in the translation table resource of each 
of the Core widgets. The use of one of two Xlib routines, depending on the depth of the 
screen, is an optimization. XCopyArea is faster, but can be used for this job only on mono 
chrome displays, because the pixmaps are one plane deep on all displays and must be 
translated into multiple planes with XCopyPlane on color displays. 

See Volume One, Xlib Programming Manual, for details. 

4.3.2 Writing a Bitmap File 

Once we have pixmaps in our application that contain the current bitmap, it is a trivial matter 
to change the printout callback function to write a bitmap file instead of just printing an 
array of 1 s and O s to the standard output This is easy because there is an Xlib function, 
XWriteBitmapFile, that writes the contents of a single-plane pixmap into a file. 
Example 4-9 shows the code that gets a filename from the command line and then writes the 
bitmap file. 

Example 4-9. xbitmap3: writing a bitmap file 

String filename; /* filename to read and write */ 

/* ARGSUSED */ 

static void 

printout (widget, client_data, call_data) 

Widget widget; 

caddr_t client_data, call_data; /* unused */ 

{ 

XWriteBitmapFile (XtDisplay (widget) , filename, normal_bitmap, 

pixmap_width_in_cells, pixmap_height_in_cells, 0, 0); 
} 

main (argc, argv) 
int argc; 
char *argv [ ] ; 



/* Xtlnitialize */ 



122 X Toolkit Intrinsics Programming Manual 



Example 4-9. xbitmapS: writing a bitmap file (continued) 



if (argv[l] != NULL) 

filename = argv[l]; 
else { 

fprintf (stderr, "xbitmap: must specify filename \ 
on command line.\n"); 

exit (1) ; 



Contrast this version of printout to the one shown in Example 4-1. 

Note that reading a bitmap file is not difficult either, but we will not take the space to 
describe it If you are curious, the complete code for xbitmapS, which both reads and writes 
bitmap files, is shown in Appendix F, The xbitmap Application. 



4.4 xbitmap4: Bitmap Editor Without a BitmapEdit Widget 

Many applications have at least one window that has certain characteristics not available in 
any existing widget class in any widget set. The small bitmaps added in the last section pro 
vided a simple example of making a custom window by creating a Core widget and drawing 
into it from the application. 

Until you have experience working with widget code, it may be easier to prototype the "cus 
tom window" for your application by adding to a Core widget using just the techniques 
described so far in this book. Once this code is working, and you have read Chapters 5 and 6, 
you can easily move the code into a widget when you want to package it or take advantage of 
any of the features of Xt that are inaccessible from the application. 

The code for the BitmapEdit widget was originally written in an application, and later moved 
into a widget. In this section we describe this original application, a version of xbitmap that 
works just like xbitmapl but without using the BitmapEdit widget This example is a culmi 
nation of many of the techniques described so far in this book. In addition, you will be see 
ing this same code inside the BitmapEdit widget in Chapters 5 and 6, and it should be easier 
to understand the additional widget code when you have already seen the functional code 
described in a familiar setting. 

This example takes advantage of application resources to set the configurable parameters of 
the bitmap code. The code that sets up the application resources was described in Section 
3.5. When moving the code into a widget framework, the same resource list will be used ver 
batim. The example also provides command-line options to set the important parameters of 
the bitmap code. The code for processing these options was described in Section 3.6. The 
code is the same whether it is used for setting application resources or widget resources, 



An Example Application 123 



except that no call equivalent to XtGetApplicationResources is necessary in a 
widget 

The exposure strategy used for the bitmap editor is the same as for the small bitmaps in the 
previous section. The application creates a large pixmap of depth one that stores the current 
image of the bitmap being edited. Whenever the screen needs updating, the applicable part 
of the pixmap is copied to the Core widget in the redraw_jpicture routine. Since this 
pixmap is much bigger than the ones in the last section, it is an important optimization that 
only the required parts of the pixmap are copied. (This is not the only possible exposure 
strategy. This particular strategy has very low network load, but uses a relatively large 
amount of server memory. For this reason it is not ideal for PC servers.) 

The set_up_things routine creates the pixmap, draws a grid into it that will persist for 
the life of the application, and creates three GCs. One GC is for copying from the pixmap to 
the window, and two are for drawing and undrawing cells in the pixmap. The btn_event 
routine draws and undraws cells in the pixmap according to pointer clicks and drags, and 
calls redraw_j>icture to update the Core widget display. 

redraw_picture is called both from the application and from Xt. This is a common 
trick used to reduce the duplication of drawing code. Since redraw_picture is an 
action, it has an event argument that is used by Xt to pass in the Expose event describing 
the area exposed. This application also uses this argument by constructing a fake event to 
pass in information about which part of the widget to draw. 

The application adds actions and sets the xtNtranslations resource of the Core widget 
so that Xt calls the application routine redraw_jpicture whenever Expose events 
arrive, and calls btn_event when ButtonPress orMotionNotify events arrive. 

Example 4-10 shows the complete code for xbitmap4 . You have seen all the techniques here 
in various examples before. You should work through the code and make sure you under 
stand the purpose of each section. However, don t worry about the details of the Xlib calls, 
since they are specific to this application. 

Example 4-10. xbitmap4: implementing the bitmap editor from the application 

/* 

* xbitmap4.c 
*/ 

tinclude <Xll/Intrinsic.h> 
tinclude <Xll/StringDef s .h> 

tifdef X11R3 

tinclude <Xll/VPaned.h> 

tinclude <Xll/Box.h> 

tinclude <X11 /Command. h> 

telse /* R4 or later */ 

tinclude <Xll/Xaw/Paned.h> 

tinclude <Xll/Xaw/Box.h> 

tinclude <Xll/Xaw/Command.h> 

tendif /* X11R3 */ 

tinclude <stdio.h> 

/ * 

* The following could be placed in an "xbitmap.h" file. 



124 X Toolkit Intrinsics Programming Manual 



Example 4-10. xbitmap4: implementing the bitmap editor from the application (continued) 

*/ 

#define XtNdebug "debug" 
tdefine XtCDebug "Debug" 

tdefine XtNpixmapWidthlnCells "pixmapWidthlnCells" 
#define XtCPixmapWidthlnCells "PixmapWidthlnCells" 
tdefine XtNpixmapHeightlnCells "pixmapHeightlnCells" 
tdefine XtCPixmapHeightlnCells "PixmapHeightlnCells" 
tdefine XtNcellSizelnPixels "cellSizelnPixels" 
tdefine XtCCellSizelnPixels "CellSizelnPixels" 

tdefine DRAWN 1 
tdefine UNDRAWN 

tdefine DRAW 1 
tdefine UNDRAW 

tdefine MAXLINES 1000 

tdefine MINBITMAPWIDTH 1 
tdefine MAXBITMAPWIDTH 1000 
tdefine MINCELLSIZE 4 
tdefine MAXCELLSIZE 100 

tdefine DEFAULTWIDTH 300 
tdefine DEFAULTHEIGHT 300 

tdefine SCROLLBARWIDTH 15 

Pixmap big_j3icture; 

GC draw_gc, undraw_gc;/* drawing into the big_picture, 1-bit deep */ 

GC copy_gc; /* copying from pixmap into window, screen depth */ 

Widget bitmap; /* this is the drawing surface */ 

char *cell; /* this is the array for printing output and */ 

int cur_x, cur_y; /* keeping track of cells drawn */ 

int pixmap_width_in_pixels, pixmap_height_in_pixels; 

/* data structure for application resources */ 
typedef struct { 

Pixel copy_fg; 

Pixel copy_bg; 

int pixmap_width_in_cells; 

int pixmap_height__in_cells; 

int cell_size_in_pixels; 

Boolean debug; 
} AppData, *AppDataPtr; 

AppData app_data; 

/* resource list */ 

static XtResource resources [] = { 

( 

XtNforeground, 

XtCForeground, 

XtRPixel, 

sizeof (Pixel) , 

XtOf f set (AppDataPtr, copy_fg) , 

XtRString, 

XtDefaultForeground 



An Example Application 



Example 4-10. xbitmap4: implementing the bitmap editor from the application (continued) 

XtNbackground, 

XtCBackground, 

XtRPixel, 

sizeof (Pixel) , 

XtOf fset (AppDataPtr, copy_bg) , 

XtRString, 

Xt Default Background 



XtNpixmapWidthlnCells, 

XtCPixmapWidthlnCells, 

XtRInt, 

sizeof (int) , 

XtOf f set {AppDataPtr, pixmap_width_in_cells) , 

XtR Immediate, 

(caddr_t) 32, 



XtNpixmapHeightlnCells, 
XtCPixmapHeightlnCells, 
XtRInt, 
sizeof (int) , 

XtOf fset (AppDataPtr, pixmap_height_in_cells) , 
XtR Immediate, 
(caddr_t) 32, 



XtNcellSizelnPixels, 

XtCCellSizelnPixels, 

XtRInt, 

sizeof (int) , 

XtOf fset (AppDataPtr, cell_size_in_pixels) , 

XtRImmediate, 

(caddr_t) 30, 



XtNdebug, 

XtCDebug, 

XtRBoolean, 

sizeof (Boolean) , 

XtOf fset (AppDataPtr, debug) , 

XtRImmediate, 

(caddr_t) FALSE, 



/* Command-line options table */ 

static XrmOptionDescRec options [] = { 

{"-pw", "*pixmapWidthInCells", XrmoptionSepArg, NULL}, 

{"-pixmapwidth", "*pixmapWidthInCells", XrmoptionSepArg, NULL}, 

{" ph", "*pixmapHeightInCells", XrmoptionSepArg, NULL}, 

{ "-pixmapheight", "*pixmapHeightInCells", XrmoptionSepArg, NULL}, 

{ "-cellsize", "*cellSizeInPixels", XrmoptionSepArg, NULL}, 

{"-fg", "*foreground", XrmoptionSepArg, NULL}, 

{"-foreground", "*foreground", XrmoptionSepArg, NULL}, 

{"-debug", "*debug", XrmoptionNoArg, "True"} 



126 X Toolkit Intrinsics Programming Manual 



Example 4-10. xbitmap4: implementing the bitmap editor from the application (continued) 

>; 

/* callback function to print cell array to stdout */ 
/* ARGSUSED */ 
static void 
printout () 



int x, y; 

putchar ( \n ) ; 
for (y = 0; y 



app_data.pixmap_height_in_cells; 



for (x = 0; x < app_data .pixmap_width_in_cells; x++) 

putchar (cell [x + y * app_data.pixmap_width_in_cells] 

? 1 : ) ; 
putchar ( \n ) ; 

putchar ( \n ) ; 



static void RedrawPicture () , DrawCellO, UndrawCell () , 
ToggleCell () , DrawPixmaps () ; 

static void Syntax (argc, argv) 
int argc; 
char * argv [ ] ; 
{ 

int i; 

static int errs = False; 

/* first argument is program name - skip that */ 
for (1=1; i < argc; i++) { 
if (!errs++) /* do first time through */ 

fprintf (stderr, "xbitmap4 : command line optionX 

not understood: \n") ; 
fprintf (stderr, "option: %s\n", argv[i]); 



fprintf (stderr, "xbitmap understands all standard Xt\ 

command line options . \n") ; 



fprintf (stderr, "Additional options 

fprintf (stderr, "Option 

fprintf (stderr, "-pw 

fprintf (stderr, "-pixmapwidth 

fprintf (stderr, "-ph 

fprintf (stderr, "-pixmapheight 

fprintf (stderr, "-cellsize 

fprintf (stderr, "-fg 

fprintf (stderr, "-foreground 

fprintf (stderr, "-debug 



are as follows : \n") ; 

Valid RangeXn") ; 

2 to lOOOXn") 

2 to 1000\n") 

2 to lOOOXn") 

2 to lOOOXn") 

4 to lOOXn") ; 

color nameXn"); 

color nameXn") ; 

no value necessaryXn") 



main (argc, argv) 
int argc; 
char *argv [ ] ; 
{ 

int i; 

Arg args [5] ; 

Widget topLevel, vpane, buttonbox, guit, output 



An Example Application 



127 



Example 4-10. xb rtmap4: implementing the bitmap editor from the application (continued) 

/* translation table for bitmap core widget */ 

String trans = 

"<Expose>: RedrawPicture () \n\ 

<BtnlDown>: DrawCellO \n\ 

<Btn2Down>: UndrawCellO \n\ 

<Btn3Down>: ToggleCell ( ) \n\ 

<BtnlMotion>: DrawCellO \n\ 

<Btn2Motion>: UndrawCellO \n\ 

<Btn3Motion>: ToggleCell ()"; 

static XtActionsRec window_actions [ ] = { 

{ "RedrawPicture", RedrawPicture } , 

{"DrawCell", DrawCell}, 

{"UndrawCell", UndrawCell}, 

{"ToggleCell 11 , ToggleCell}, 
}; 

topLevel = Xtlnitialize { argv[0], 
"XB it map 4 ", 
options, 

XtNumber (options) , 
&argc, 
argv) ; 

/* Xtlnitialize leaves program name in args */ 
if (argc > 1) 

Syntax (argc, argv); 

XtGetApplicationRe sources (topLevel, 
&app_data, 
resources, 

XtNumber (resources) , 
NULL, 
0); 

/* 

* We must check the application resource values here. 

* Otherwise, user could supply out of range values 

* and crash program. Conversion routines do this 

* automatically, so colors are already checked. 
*/ 

if ( (app_data.pixmap_width_in_cells > MAXBITMAPWIDTH) || 

(app_data.pixmap_width_in_cells < MINBITMAPWIDTH) | | 
(app_data.pixmap_height_in_cells > MAXBITMAPWIDTH) | | 
(app_data.pixmap_height_in_cells < MINBITMAPWIDTH)) { 
fprintf (stderr, "xbitmap: error in resource settings:", 
"dimension must be between %d and %d cells\n", 
MINBITMAPWIDTH, MAXBITMAPWIDTH) ; 
exit (1) ; 
} 
if ( (app_data.cell_size_in_pixels < MINCELLSIZE) I I 

(app_data.cell_size_in_pixels > MAXCELLSIZE) ) { 
fprintf (stderr, "xbitmap: error in resource settings:", 
"cell size must be between %d and %d pixels\n", 
MINCELLSIZE, MAXCELLSIZE); 
exit (1) ; 



128 X Toolkit Intrinsics Programming Manual 



Example 4-1 0. xbitmap4: implementing the bitmap editor from the application (continued) 
/* begin application code */ 
set_up_things (topLevel) ; 

cell = XtCalloc (app_data.pixmap_width_in_cells * 

app_data.pixmap_height_in_cells, sizeof (char) ) ; 

if (app_data .debug) 

fprintf (stderr, "xbitmap: pixmap\ 
dimensions are %d by %d\n", 
app_data .pixmap_width_in_cells, 
app_data.pixmap_height_in_cells) ; 

i = 0; 

XtSetArg(args [i] , XtNwidth, (pixmap_width_in_pixels > 300) 

? (300 + SCROLLBARWIDTH + 15) : (pixmap_width_in_pixels 

+ SCROLLBARWIDTH + 15)); i++; 

/* following line is a kludge */ 
XtSetArg(args[i] , XtNheight, 15); i + + ; 

tifdef X11R3 

vpane = XtCreateManagedWidget ("vpane", vPanedWidgetClass, 

topLevel, args, i) ; 
#else /* R4 or later */ 

vpane = XtCreateManagedWidget ("vpane", panedWidgetClass, 

topLevel, args, i) ; 
tendif /* X11R3 */ 

buttonbox = XtCreateManagedWidget ("buttonbox", boxWidgetClass, 
vpane, NULL, 0) ; 

output = XtCreateManagedWidget ("output", commandWidgetClass, 
buttonbox, NULL, 0) ; 

XtAddCallback (output, XtNcallback, printout, NULL); 

quit = XtCreateManagedWidget ("quit", commandWidgetClass, 
buttonbox, NULL, 0); 

XtAddCallback (quit, XtNcallback, exit, NULL) ; 

1 = 0; 

XtSetArg (args [i] , XtNtranslations, 

XtParseTranslationTable (trans) ) ; i++; 
XtSetArg (args [ i] , XtNwidth, 

(pixmap_width_in_pixels > 300) ? 300 : 

pixmap_width_in_pixels) ; i++; 
XtSetArg (args [i] , XtNheight, 

(pixmap_height_in_pixels > 300) ? 300 : 

pixmap_height_in_pixels) ; i++; 
bitmap = XtCreateManagedWidget ("bitmap", widgetClass, 

vpane, args, i) ; 

XtAddActions (wi-ndow_actions, XtNumber (window_actions) ) ; 
XtRealizeWidget (topLevel) ; 

XtMainLoop () ; 
} 

set_up_things (w) 



An Example Application 



Example 4-10. xbitmap4: implementing the bitmap editor from the application (continued) 

Widget w; 
{ 

XGCValues values; 

int x, y; 

XSegment segment [MAXLINES] ; 

int n_horiz_segments, n_vert_segments; 

pixmap_width_in_pixels = app_data.pixmap_width_in_cells * 

app_data .cell_size_in_pixels; 
pixmap_height_in_pixels = app_data.pixmap_height_in_cells * 

app_data . cell_size_in_pixels; 

big_picture = XCreatePixmap (XtDisplay (w) , 
RootWindowOf Screen (XtScreen (w) ) , 
pixmap_width_in_pixels, pixmap_height_in_pixels, 1); 

values . foreground = 1; 

values .background = 0; 

values. dashes =1; 

values .dash_off set = 0; 

values . line_style = LineOnOf fDash; 

draw_gc = XCreateGC (XtDisplay (w) , big_picture, 

GCForeground | GCBackground | GCDashOffset | 
GCDashList | GCLineStyle, Svalues) ; 

values. foreground = 0; 
values. background = 1; 
undraw_gc = XCreateGC (XtDisplay (w) , big_picture, 

GCForeground I GCBackground I GCDashOffset | 

GCDashList | GCLineStyle, Svalues) ; 

values. foreground = app_data.copy_fg; 

values. background = app_data.copy_bg; 

copy_gc = XCreateGC (XtDisplay (w) , 

RootWindowOf Screen (XtScreen (w) ) , 
GCForeground | GCBackground, & values) ; 

/* draw permanent grid into pixmap */ 

n_horiz_segments = app_data .pixmap_height_in_cells + 1; 

n_vert_segments = app_data .pixmap_width_in_cells + 1; 

for (x = 0; x < n_horiz_segments; x += 1) { 

segment [x] ,xl = 0; 

segment [x] .x2 = pixmap_width_in_pixels; 

segment [x] .yl = app_data .cell_size_in_pixels * x; 

segment [x] .y2 = app_data .cell_size_in_pixels * x; 
} 

/* drawn only once into pixmap */ 

XDrawSegments (XtDisplay (w) , big^picture, draw_gc, segment, 
n_horiz_segments) ; 

for (y = 0; y < n_vert_segments; y += 1) { 

segment [y] .xl = y * app_data.cell_size_in_pixels; 
segment [y] .x2 = y * app_data.cell_size_in_ j pixels; 
segment [y] .yl = 0; 
segment [y] .y2 = pixmap_height_in_pixels; 



130 X Toolkit Intrinsics Programming Manual 



Example 4-10. xbitmap4: implementing the bitmap editor from the application (continued) 

/* drawn only once into pixmap */ 

XDrawSegments (XtDisplay (w) , big_picture, draw_gc, segment, 
n_vert_segments) ; 

} 

/* Action */ 
static void 

RedrawPicture (w, event) 
Widget w; 

XExposeEvent *event; 
{ 

register int x, y; 

unsigned int width, height; 

if (event) { /* drawing because of expose or button press */ 

x = event->x; 

y = event->y; 

width = event->width; 

height = event->height; 
} 
else { /* drawing because of scrolling */ 

x = 0; 

y - 0; 

width = 10000; /* always the whole window! */ 

height = 10000; 
} 

if (Def aultDepthOf Screen (XtScreen (w) ) = = 1) 

XCopyArea (XtDisplay (w) , big_picture, . XtWindow (w) , 
copy_gc, x + cur_x, 
y + cur_y, width, height, x, y) ; 
else 

XCopyPlane (XtDisplay (w) , big_picture, XtWindow (w), 
copy_gc, x + cur_x, 

y + cur_y, width, height, x, y, 1); 
} 

/* Action */ 
static void 
DrawCell (w, event) 
Widget w; 

XButtonEvent *event; 
{ 

DrawPixmaps (draw_gc, DRAW, w, event); 
} 

/* Action */ 
static void 
UndrawCell (w, event) 
Widget w; 

XButtonEvent *event; 
{ 

DrawPixmaps (undraw_gc, UNDRAW, w, event); 
} 

/* Action */ 
static void 
ToggleCell (w, event) 



An Example Application 



Example 4-1 0. xbitmap4: implementing the bitmap editor from the application (continued) 

Widget w; 

XButtonEvent *event; 
{ 

static int oldx = -1, oldy = -1; 

GC gc; 

int mode; 

int newx = (cur_x 4- event->x) / app_data .cell_size_in_pixels; 

int newy = (cur_y + event->y) / app_data .cell_size_in_pixels; 

if ((mode = cell [newx + newy * app_data .pixmap_width_in_cells] ) 
== DRAWN) { 

gc = undraw_gc; 

mode - UNDRAW; 
} 
else { 

gc = draw_gc; 

mode = DRAW; 



if (oldx != newx I I oldy 1= newy) { 
oldx = newx; 
oldy = newy; 
DrawPixmaps (gc, mode, w, event); 



/* Private Function */ 

static void 

DrawPixmaps (gc, mode, w, event) 

GC gc; 

int mode; 

Widget w; 

XButtonEvent *event; 

int newx = (cur_x + event->x) / app_data .cell_size_in_pixels; 
int newy = (cur_y + event->y) / app_data .cell_size_in_pixels; 
XExposeEvent fake_event; 

/* if already done, return */ 

if (cell [newx + newy * app_data .pixmap_width_in_cells] == mode) 
return; 

XFillRectangle (XtDisplay (w) , big_picture, gc, 
app_data . cell_size_in_pixels*newx + 2, 
app_data .cell_size_in_pixels*newy +2, 
(unsigned int) app_data .cell_size_in_pixels - 3, 
(unsigned int ) app_data .cell_size_in_pixels -3); 

cell [newx + newy * app_data .pixmap_width_in_cells] = mode; 

fake_event.x = app_data . cell_size_in_pixels * newx - cur_x; 
fake_event.y = app_data . cell_size_in_pixels * newy - cur_y; 
fake_event .width = app_data . cell_size_in_pixels; 
fake_event .height = app_data .cell_size_in_pixels; 

RedrawPicture (bitmap, Sfake event); 



732 



X Toolkit Intrinsics Programming Manual 



5 



Inside a Widget 



This chapter describes the code inside a basic widget. Much of this code is 
common to all widgets. You can think of it as a framework that Xt uses to 
implement a widget s features. After reading this chapter, you should under 
stand the procedure for creating your own widget around this framework. 

In This Chapter: 

Widget Source File Organization 135 

The Private Header File B it map Ed it P. h 136 

Parts and Records 137 

Class Part and Class Record 138 

Instance Part and Instance Record 139 

The Widget Source File BitmapEdit.c 141 

Obligatory Include Files 141 

Defining the Resource List 143 

The Translation Table and Actions Table 145 

Declaring Methods 147 

Initializing the Class Record 148 

The Core Class Part 148 

Initializing the Core Methods 151 

Description of Core Methods 153 

Packaging the Class Record for Application Use 155 

A Sample Method 155 

The Public Header File BitmapEdit.h 158 

The Process of Widget Writing 160 

Summary of Conventions 162 



5 
Inside a Widget 



This chapter reveals the framework of code common to all widgets. As an example, it 
describes the code for the BitmapEdit widget that was used in versions of the xbitmap appli 
cations early in Chapter 4, An Example Application. Later examples in that chapter described 
how to implement the bitmap editor without a BitmapEdit widget. Therefore, you have 
already seen the code that is specific to this widget, and can concentrate on the framework 
and how to place widget-specific code within this framework. 

Placing specialized user-interface code into a widget has several advantages. For one, the 
widget becomes a self-contained module that can be modified and documented separately 
and used in other programs. Second, the code will take advantage of Xt s automatic dis 
patching of events to widgets, and several other features that you can t use from the applica 
tion. Finally, it is a general premise of Xt that application code should be separated as much 
as possible from user-interface code. 

It is important to remember that widget classes are never written from scratch. People 
always start from template files that contain the framework for a widget without the specific 
code, or even better, when possible, from an existing widget that has some similar character 
istics. 



5.1 Widget Source File Organization 

A widget is implemented in two include files and an executable code file. Each of these files 
contains specific elements. The names of these files are derived from the name of the widget 
class, which in this case is BitmapEdit: 

The private header file, BitmapEditP.h, defines the widget s class and instance structures, 
including pointers to the widget s methods. 

The implementation file, BitmapEdit.c, contains the actual executable code for the 
widget, including the widget s methods and actions. 

The public header file, BitmapEdit.h, contains declarations needed by the application to 
use the widget 



Inside a Widget 135 



The final P in the include file name stands for Private. Only BitmapEdit.c and any modules 
that implement subclasses of BitmapEdit should include BitmapEditP .h. If an application 
includes this file and references any of its contents, it is breaking the rules of encapsulation, 
and changes to this widget might affect the application. 

An application program that uses a widget includes only BitmapEdit.h. 

The implementation filenames (and all the filenames used by your application, for that mat 
ter) should have 12 or fewer characters or less so that the code can be copied easily to some 
System V systems.* 

The next three major sections describe the contents of the three files that make up a widget. 
These files are treated in the order shown in the above list because they are generally devel 
oped in this order. 



5.2 The Private Header File BitmapEditP.h 

Xt implements classes and instances with two structures, the class structure and the instance 
structure. By definition of C structures, the fields in both structures are fixed at compile time. 
Both of these structures are defined in the private include file for the class, in this case 
BitmapEditP.h. 

There is only one copy of the class structure in the running application, which all instances 
share. But each instance has its own copy of the instance structure, whose fields are set by 
the resource database as the instance is created. Fields in the instance structure can also be 
set by Xt SetValues or read by XtGetValues. 

The class structure s fields contain pointers to methods and pieces of data that control how Xt 
handles instances of this class. 

The instance structure carries a complete widget state, including everything that can be dif 
ferent between one instance and the next. For example, the instance structure of the Core 
class, which every widget inherits, has fields for x, y, width, and height values, which 
correspond to the size of the widget and its location relative to the top-left corner of its par 
ent. These particular fields are public; they can be set from the resource database or with 
xtSetValues, and their values can be read with XtGetValues. Other instance struc 
ture fields are private, and are used only for convenience to make data globally available 
within the widget 

Actually, the instance structure is not global in the normal C sense. When Xt invokes a 
method, it passes the method a pointer to the widget instance structure. Methods do their 
work by using the public fields and changing the private fields in this instance structure. For 
example, a method that draws in the window can get the window s dimensions directly from 



* These systems have a 14-character filename limit; the 12-character limit allows files to be placed under source con 
trol or compressed. The X Consortium keeps all filenames to a maximum of 12 characters. That limits the actual 
class name to 9 characters, to leave room for the P.h suffix. If the widget class name is longer than 9 characters, it is 
truncated in the filename. For example, the private include file for the Constraint class is Constrain? h (without the 
final t); BitmapEditP .h is BitmapEdiP .h in our example code. 



136 X Toolkit Intrinsics Programming Manual 



the widget instance structure. When action functions are called, they also are passed a 
pointer to the instance structure. Therefore, the fields inside the instance structure are avail 
able just about everywhere in the widget code. 



5.2.1 Parts and Records 

The organization of both class and instance structures is determined by the hierarchy of 
widget classes from which the current widget class is derived. For example, in the code for 
the BitmapEdit widget whose class hierarchy is shown in Figure 5-1, the class structure 
begins with the class fields defined by the Core class, followed by the class fields defined by 
BitmapEdit. 



Class hierarchy 



Core 



BitmapEdit 



i Composite 

I 

Constraint 



Figure 5-1. The class hierarchy of the BitmapEdit widget (with other classes shown dotted) 



Xt supplies three basic classes that are used as the basis for custom widgets, Core, Compos 
ite, and Constraint.* Figure 5-1 also shows the relationship of these classes to each other. 
Core is the class upon which all widgets are based. It defines common characteristics of all 
widgets, such as their methods, and basic resources such as height and width. Even if your 
widget is unlike any existing widget, it will still inherit features from the Core widget. The 
class and instance structures of a subclass of Composite such as Box begin with the fields 
from Core, continue with fields from Composite, and end with the fields defined by Box. 
Composite and Constraint are subclasses of Core that have additional methods that allow 
them to manage children; they are described in Chapter 11, Geometry Management. This 
chapter concentrates on the features of the Core widget 

Xt requires that you implement each class s new fields as a separate structure called a Part, 
and then combine this Part structure with each superclass s Part structure in the complete 
structure called a Rec, or record. In real code, these structures are called 
widgetnameClassPart and widgetnameClassRec for the class structure, and simply 
widgetnamePazt and widgetnameRec for the instance structure. 



*Shell, the fourth Litrinsics-supplied widget class, is not usually subclassed by application or widget programmers. 



Inside a Widget 



137 



The reason for this "structure within a structure" design is primarily to reduce the changes in 
the code of subclasses that would be required if changes were made to the superclass s struc 
tures. As we will see later, only the portion of the .c file that initializes the class structure 
will need changing if a superclass class structure is changed. A second benefit of this design 
is that it reduces the amount of typing required to implement a new class. 



5.2.2 Class Part and Class Record 

Let s make these ideas concrete by showing the class structure for BitmapEdit. The complete 
class structure is called BitmapEdit ClassRec, and the partial structure is called 
BitmapEditClassPart. Their definitions from BitmapEditP .h are shown in Example 
5-1. 

Example 5-1. BitmapEditP. h: the class part and class record 

/* 

* BitmapEditP. h - Private definitions for BitmapEdit widget 
*/ 

/* protect against multiple including of this file */ 
#ifndef _ORABitmapEditP_h 
fdefine _ORABitmapEditP_h 

ill /* 

* This include not needed unless the .c file includes 

* IntrinsicP.h after this file. Anyway, it doesn t hurt. 
*/ 

tinclude <Xll/CoreP .h> 

/* 

* This one is always needed! 

II */ 

#include "BitmapEdit .h" 

/* New fields for the BitmapEdit widget class record */ 

typedef struct { 

int make_compiler_happy; /* need dummy field */ 
} BitmapEditClassPart; 

/* Full class record declaration */ 
typedef struct _BitmapEditClassRec { 

CoreClassPart core_class; 

BitmapEditClassPart bitmapEdit_class; 
} BitmapEditClassRec; 

Like most widget classes, BitmapEdit provides no new fields in the class part, but it needs 
one dummy member to make the C compiler happy. Few classes define new class part fields 
because the Core class already provides all the class fields that Xt knows what to do with.* 



*Nevertheless, adding new fields does have its uses. If you place a new method field here, subclasses can choose to 
inherit the function or to replace it However, the widget code will have to call the method itself because Xt doesn t 
know when to. This fine point is described in Section 1 1 .4.5. 



138 X Toolkit Intrinsics Programming Manual 



The CorePart and CoreClassPart structures are defined in Core s private header file 
<XlllCoreP.h>. In general, you need to include the private header file of the superclass at 
the top of your private header file. It turns out that if the header files at the top of the .c file 
are in the right order, and the superclass of your class is Core, Composite, or Constraint (a 
class defined by Xt), then this header file doesn t need to be included. But it doesn t hurt to 
do so, because the header files begin with an if ndef statement that allows the preprocessor 
to make sure that no header file is included twice. 



5.2.3 Instance Part and Instance Record 

The instance record is built exactly like the class structure, by defining new fields in a part 
structure, and then combining the instance parts of all superclasses in the instance record. 
BitmapEditPart defines BitmapEdit s new widget instance fields, and the entire widget 
instance record is BitmapEditRec. These structures are defined in BitmapEditP .h (along 
with the class structures just shown) and are shown in Example 5-2. We ve included several 
likely instance variables, but none of those shown is an essential part of the widget structure. 

Example 5-2. BitmapEditP.h: the instance part and instance record 

/* New fields for the BitmapEdit widget record */ 
typedef struct { 

/* resources */ 

Pixel foreground; 

XtCallbackList callback;/* application installed callback fns */ 

Dimension pixmap_width_in_cells; 

Dimension pixmap_height_in_cells; 

int cell_size; 

int cur x, cur_y; /* pstn of visible corner in big pixmap */ 

char *ce~ll; /* for keeping track of array of bits */ 

/* private state */ 
Dimension pixmap_width_in_pixels; 
Dimension pixmap_height_in_pixels; 
Pixmap big_picture; 

GC draw gc; /* for drawing into pixmap */ 
GC undraw_gc; /* for undrawing into pixmap */ 
GC copy_gc:; /* for copying pixmap into window */ 
} BitmapEditPart; 

/* 
* Full instance record declaration 

*/ 

typedef struct _BitmapEditRec { 

CorePart core; 

BitmapEditPart bitmapEdit ; 
} BitmapEditRec; 

tendif /* _ORABitmapEditP_h */ 

Unlike the class part, which generally defines no new fields, the instance part of most widgets 
does define new instance variables. These variables control all the configurable elements of 
the widget, and they hold the widget s state. 



Inside a Widget 



Some of these instance variables are resources because they are listed in the resource list in 
the BitmapEdit.c file. (This resource list has exactly the same format as the resource list you 
saw in the application code in Section 3.5.2). These variables are known as public instance 
variables (because they are readable and writable from the application). By convention, the 
public instance variables are placed first in the instance part structure, and comments indicate 
which fields are public. When the application instantiates the widget, Xt sets the public fields 
based on the resource databases, the command line (the -xrm form), and the argument list 
passed to xtCreateWidget. Later on, the application may change these fields using xt- 
SetValues. 

The private instance structure fields (not listed in the widget s resource list) are either 
derived from resource values or they hold some aspect of the widget s state (such as whether 
it is highlighted). As in Example 5-2, graphics contexts (GCs) are always fojund here as pri 
vate fields if the widget draws any graphics. Graphics contexts are needed for doing draw 
ing, and are derived from public instance structure fields such as colors and fonts, because it 
is the GC that actually carries color and font information to the X server. GCs were intro 
duced in Section 4.3.1. 

You may notice that the Part structures of the superclasses are referenced in the Bitmap- 
EditRec structure. As mentioned earlier, you get these by including the private include file 
of the immediate superclass, which in turn includes the private include file of its own super 
class, and so on. 

Note that both the class and instance structures defined in BitmapEditP .h are typedef tem 
plates; they do not allocate storage. Xt allocates storage for the instance record when the 
application calls XtCreateWidget or XtCreateManagedWidget to create the 
widget The class record, on the other hand, is initialized statically (at compile time) in the .c 
file. To make sure that the definition of the class record (in BitmapEditP .K) and the initializa 
tion of the class record (in BitmapEdit.c) use identical structures, BitmapEditP .h contains an 
extern reference to the class structure initialized in BitmapEdit.c. This reference is shown 
in Example 5-3. If a field is accidentally left out of the class structure in either file, the com 
piler will catch the problem (but if the same member is left out of both files, the problem 
won t be caught and Xt will likely dump core). 

Example 5-3. BitmapEditP.h: declaring the external class record 
extern BitmapEditClassRec bitmapEditClassRec; 

The naming conventions for the various structure declarations in the private header file are 
important, and can be confusing. A table summarizing the conventions for types and vari 
ables in the widget implementation files is shown in Section 5.6 (after the contents of the .c 
and .h files are shown). 

That s all there is in the private header file! If you should need to refer back to the private 
header file for BitmapEdit, it is listed with the rest of the source for the widget in Appendix 
B, The xbitmap Application. 



140 X Toolkit Intrinsics Programming Manual 



5.3 The Widget Source File BitmapEdit.c 



The central element of the .c file is the initialization of the class record. Remember that the 
typedef of the class record was declared in BitmapEditP .h, but the record is allocated and 
the actual values in each field are set in BitmapEdit.c. When Xt takes over control of the 
widgets after the application calls xtMainLoop, it is the values in this class record that 
supply Xt with all the information it uses to manage widget instances. 

The organization of the .c file is quite simple. First, it defines everything that will be placed 
into the class record, and then initializes the class record, setting fields using these defini 
tions. The major things that need defining are the functions that implement each method, the 
resource list, the translation table, and the actions table. It would be logical to define these 
four things at the beginning of the source file, and then put the class record last. This is 
almost the case, except that by convention the methods and actions are declared at the top of 
the source file and then defined at the end after the class record initialization. This actually 
makes the widget code clearer because the method declarations provide a complete list of the 
methods that will be defined later in the file, and the class record remains near the top of the 
file where it s easier to find. (Not all the methods have to be defined by a class, because some 
methods can be inherited or not used, as we will discuss in Section 5.3.6.) Figure 5-2 sum 
marizes the conventional order of code in the .c file.* 



5.3.1 Obligatory Include Files 

The .c file begins with the standard includes: 

<stdio.h>, since print f always comes in handy for debugging purposes. 

<X1 II Intrinsic?. h> (which includes <XlllIntrinsic.h>) for the Xt supplied widget 
classes Core, Composite, and Constraint, declarations of Intrinsics functions, and several 
useful macros. 

<XlllStringDefs.h> for the standard resource names used in defining the resource list. 

Example 5-4. BitmapEdit.c: include files 
tinclude <stdio.h> 

tinclude <Xll/StringDef s .h> 
tinclude <Xll/IntrinsicP .h> 

#include "BitmapEditP .h" 

Remember that BitmapEditP. h includes the private header file of the immediate superclass 
(which includes the private header file of its own superclass, and so on), and each private 



"Here we use the terminology defined in Kemighan and Ritchie s The C Programming Language (Prentice-Hall 
1978). A declaration announces the properties of a variable (its type, size, etc.), while a definition causes storage to 
be allocated. This distinction is important in the Toolkit because many things are declared and defined in separate 
steps. 



Inside a Widget 



header file includes the public header file for its class, so that all the information in all the 
public and private header files for all superclasses is available to this .c file as a result of this 
one include statement. 



Structure of widget .c File 



Header Files 



Resource List 



Action Function Declarations 



Actions Table 



Default Translation Table 



Method Function Declarations 



Class Record Initialization 



Method Function Definitions 



Action Function Definitions 



#include 



~~L static XtResource resources = { }; 
p static void Action (); 



static XtActionsRec actions []={}; 
static char def aultTranslations []=""; 
static void Initialize (), Redisplay (); 

NewWidgetClassRec newWidgetClassRec={ } 
{ 

/*CoreClassPart,etc. */ 
} 

static void Initialize () 



static void Action () 



Figure 5-2. Order of code in widget .c file 

We ll look at BitmapEdit.c in seven parts, in an order corresponding to Figure 5-2. 



142 



X Toolkit Intrinsics Programming Manual 



5.3.2 Defining the Resource List 

A widget inherits the resources defined by its superclasses, and it can also add its own 
resources by defining a resource list and setting it into the class structure. This section 
reviews the basic techniques for creating a resource list, since this technique was shown in 
Chapter 4 when we added application resources to xbitmap. 

In creating an application resource list, we created a structure called app_data whose 
fields were to be set through resources. In widget code, the instance part structure is used just 
like app_data, except that the private instance structure fields will not appear in the 
resource list. Each member of the instance structure that is to be a resource must have an 
entry in the resource list. 

Example 5-5 shows a resource list for the public instance variables defined in Example 5-2 
above. 

Example 5-5. BitmapEdit s resource list 

static XtResource resources!] = { 

{ 

XtNforeground, 
XtCForeground, 
XtRPixel, 
sizeof (Pixel) , 

offset (bitmapEdit . foreground) , 
XtRString, 
XtDefaultForeground 

}, 

{ 

XtNcallback, 
XtCCallback, 
XtRCallback, 
sizeof (caddr_t) , 
offset (bitmapEdit . callback) , 
XtRCallback, 
NULL 

}, 

{ 

XtNcellSizelnPixels, 
XtCCellSizelnPixels, 
XtRInt, sizeof (int), 

offset (bitmapEdit .cell_size_in_pixels) , 
XtRImmediate, 
(caddr_t) DEFAULT_CELL_SIZE 

}, 

{ 

XtNpixmapWidthlnCells, 
XtCPixmapWidthlnCells, 
XtRDimension, 
sizeof (Dimension) , 

offset (bitmapEdit .pixmap_width_in_cells) , 
XtRImmediate, 
(caddr_t) DEFAULT_PIXMAP_WIDTH 



Inside a Widget 



143 



Example 5-5. BitmapEdit s resource list (continued) 

XtNpixmapHeightlnCells, 

XtCPixmapHeightlnCells, 

XtRDimension, 

sizeof (Dimension) , 

offset (bitmapEdit .pixmap_height_in_cells) , 

XtRImmediate, 

(caddrt) DEFAULT_PIXMAP_HEIGHT 



XtNcurX, 
XtCCurX, 
XtRInt, 
sizeof (int ) , 

offset (bitmapEdit . cur_x) 
XtRImmediate, 
(caddr_t) 



XtNcurY, 
XtCCurY, 
XtRInt, 
sizeof (int) , 

offset (bitmapEdit . cur_y ) , 
XtRString, 
(caddr_t) NULL 



XtNcellArray, 

XtCCellArray, 

XtRString, 

sizeof (String) , 

offset (bitmapEdit .cell) , 

XtRImmediate, 

(caddr_t) 



As mentioned earlier, a widget class inherits all the resources defined in the resource lists of 
its superclasses. If a resource is given the same name as a superclass resource, it overrides 
the superclass resource. The only reason to create a new resource with the same name as a 
superclass resource is to give it a new, subclass-specific default value. The type and offset 
should remain the same. 

When defining a resource list, use as many as possible of the constants defined in 
<XlllStringDefs.h>. However, any constant unique to this widget class can be defined in the 
public include file, as will be described in the next section. 

Table 5-1 summarizes the conventions for the constants used in the resource list. 



144 X Toolkit Intrinsics Programming Manual 



Table 5- 1. Resource list constant conventions 



Prefix 


First word capitalization 


Description 


XtN 

xtc 

XtR 


Lower 
Upper 
Upper 


Resource name 
Resource class 
Representation type 



Xt constants and functions of all types use upper case letters whenever a word break might 
otherwise be called for. Two examples of resource names following this convention are xt- 
NborderColor and XtNmappedWhenManaged. 

Example 5-6 shows how the resource list is entered into the class structure. You ll see this 
again in Section 5.3.5 where we show the entire class record and describe how to initialize it. 
The names of the fields in the class structure are shown in the comments at right. 

Example 5-6. Setting the resource list into the class structure 

BitmapEditClassRec bitmapEditClassRec = { 
{ /* Core class part */ 



resources, 

XtNumber (resources) , 



/* resources */ 

/* resource count */ 



/* BitmapEdit class part */ 



0, 



/* dummy field */ 



Note that a widget or an application can get the resource list for a class using xtGet- 
ResourceList, which returns a pointer to a resource list of the same form as shown 
above. This function isn t needed in most applications or widgets. 



>.3.3 The Translation Table and Actions Table 

You may recall that the translation table maps event sequences into string action names, and 
the action table then maps string action names into actual action functions. This is done in 
two steps so that the translation table is a single string that can be specified in the resource 
databases (since resource databases are always composed entirely of strings). The action 
table is not configurable through the resource database, but it can be modified from the appli 
cation or from the widget code with xtAddAction (s) , xtRemoveAction (s) , or 
XtRemoveAllActions. 

Like the resource list, the default translation table and the actions table have to be defined 
before the class record can be initialized. They determine which events this widget will 
respond to, and which functions defined in this source file will be triggered by those events. 



Inside a Widget 



145 



The translation table is a resource defined by the Core class. It is a strange resource in sev 
eral ways. It has no default value in the resource list. Instead, the default translation table is 
initialized into the class structure. Translations are not inherited like other resources you 
do not get the sum of all the translation tables registered by the superclasses. Rather, the 
translation table you specify in the class structure is the only one (in the code) that matters. 
However, you can choose to use the immediate superclass s translation table, in which case 
you initialize the translation table field in the class structure to be xt inherit - 
Translations. 

Each widget has its own action list, and if the application registers an action list, it is kept as 
a separate list. When an event combination occurs in a widget, Xt translates the event combi 
nation into an action string and searches that widget s action list. If the action string is found 
in the widget s action list, the search stops and that action function is called. If the action 
string is not found in the widget s action list, then the application s action list is searched. If 
neither list contains the appropriate action string, Xt prints a diagnostic warning. If the appli 
cation and the widget both define the same action string in the actions table, the application s 
function mapped to that string will never be called. Two widget classes, however, may have 
the same action function name, and they will not conflict. 

Example 5-7 shows a default translation table and an action table. Note that, like methods, 
the action functions are declared before being used in the actions table, but they will actually 
be defined later in the source file. 

Example 5-7. The default translation table and the actions table 
static void DrawCellO, UndrawCell ( ) , ToggleCell O; 

static char defaultTranslations [] = 

"<BtnlDown>: DrawCellO \n\ 

<Btn2Down>: UndrawCell () \n\ 

<Btn3Down>: ToggleCell {) \n\ 

<BtnlMotion>: DrawCellO \n\ 

<Btn2Motion>: UndrawCell () \n\ 

<Btn3Motion>: ToggleCell O "; 
static XtActionsRec actions!] = { 
{"DrawCell", DrawCell}, 
{"UndrawCell", UndrawCell}, 
{"ToggleCell", ToggleCell}, 
}; 

The pointers to the actions table and translation table are placed into the class structure just 
like the resource list (but of course into different fields), as shown in Example 5-8. The 
names of the fields in the class structure are shown in the comments at right. (You ll see this 
again shortly in the section on class structure initialization.) 

Example 5-8. Translations in the Core Class Record 

BitmapEditClassRec bitmapEditClassRec = { 
{ /* core class part */ 

actions, /* actions */ 

XtNumber (actions) , /* num actions */ 



146 X Toolkit Intrinsics Programming Manual 



Example 5-8. Translations in the Core Class Record (continued) 



default Translations, 



0, 



/* tm table 



*/ 



/* BitmapEdit class part */ 
/* dummy field */ 



Note that the default translation table cannot be compiled with xtParseTranslation- 
Table before being placed in the class structure, since the class structure initialization 
occurs at compile time. Xt compiles the default translations when the class is initialized. 

The translation table and actions table are discussed more fully in Chapter 7, Events, Transla 
tions, and Accelerators. 



5.3.4 Declaring Methods 

The widget s methods should be declared near the top of the .c file. This is so that the class 
structure initialization can appear before the method definitions. IntrinsicP.h declares 
typedefs for each type of function that will be a widget method. For example, the 
expose method (to be described later in this chapter) is a function of type XtExpose 
Proc. XtExposeProc is actually defined to be void. 

However, these typedefs do not seem to work on all compilers. The Athena widgets don t 
use them to declare their methods. Instead, they use the actual type returned, such as void 
or Bool. You should probably do this too. Example 5-9 shows the method declarations 
from BitmapEdit done both ways, with the typedef approach commented out 

Example 5-9. BitmapEdit.c: function type declarations 

/* Declaration of methods */ 

These function prototype declarations don t work under 
SunOs 4.0.1 and perhaps others so we ll instead declare 
the actual return type 

static XtlnitProc Initialize O ; 
static XtExposeProc Redisplay O; 

* static XtWidgetProc Destroy O ; 

* static XtWidgetProc Resize O ; 

* static XtSetValuesFunc SetValuesO; 
*/ 

static void Initialize O; 

static void Redisplay O; 

static void Destroy O; 

static void Resize O ; 

static Boolean SetValuesO; 

static XtGeometryResult QueryGeometry () ; 

/* these Core methods not needed by BitmapEdit: 

* 



Inside a Widget 



147 



Example 5-9. BitmapEdit.c: function type declarations (continued) 

static XtProc Classlnitialize (); 
static XtRealizeProc Realize (); 
static void Classlnitialize (); 
static void Realize (); 

/* the following are functions private to BitmapEdit */ 
static void DrawPixmaps { ) , DoCelK), ChangeCellSize ( ) ; 

/* the following are actions of BitmapEdit */ 
static void DrawCellO, UndrawCell ( ) , ToggleCell ( ) ; 

By convention, the names of function typedefs in Xt end in Proc or Func. Also by conven 
tion, function typedefs ending in Func return a meaningful value, while those ending in 
Proc return void. A basic description of all the methods is given in Section 5.3.6. 

Notice that several methods use the same typedefs. For example, xtwidgetProc is the 
type of several methods (destroy, resize, and others). Volume Five, X Toolkit Intrin- 
sics Reference Manual, summarizes the calling sequence for each typedef, and its multiple 
uses when appropriate. 

The methods are declared static to prevent access to the functions from outside this 
source file, and to prevent collisions with other functions of the same name in other source 
files. 



5.3.5 Initializing the Class Record 

We ve already shown you how to create the resource list, the translation table, and the 
actions table, and set into the class structure. A major part of the work is done. Now we just 
need to insert the method function names we declared earlier into the class record, and set a 
few of the miscellaneous data fields. 

As we saw in the discussion of the private header file, the BitmapEdit class record includes 
class parts for BitmapEdit itself and for each superclass of BitmapEdit, in this case only 
Core. To initialize the class record, each class part has to be initialized field by field. But for 
simple (noncomposite) widgets this job comes down to initializing the Core class part, 
because few classes actually define new class part fields. 

5.3.5.1 The Core Class Part 

Since all widget classes are subclasses of Core, all need to initialize the Core class part. 
Example 5-10 shows the core part initialized as needed by the BitmapEdit widget. The 
actual name of each field is shown in the comment at left. Each field will be discussed after 
the example. 

Example 5-10. BitmapEdit.c: initialization of Core class record 

BitmapEditClassRec bitmapEditClassRec = { 
{ 
/* core class fields */ 



148 X Toolkit Intrinsics Programming Manual 



Example 5-10. BitmapEdit.c: initialization ol Core class record (continued) 



/* superclass 

/* class_name 

/* widget_size 

/* class_initialize 

/* class_part_initialize 

/* class_inited 

/* initialize 

/* initialize_hook 

/* realize 

/* actions 

/* num_actions 

/* resources 

/* num_resources 

/* xrm_class 

/* compress_motion 

/* compress_exposure 

/* compress_enterleave 

/* visible_interest 

/* destroy 

/* resize 

/* expose 

/* set_values 

/* set_values_hook 

/* set_values_almost 

/* get_values_hook 

/* accept_focus 

/* version 

/* callback_private 

/* tm_table 

/* query_geometry 

/* display_accelerator 

/* extension 



*/ (WidgetClass) SwidgetClassRec, 

*/ "BitmapEdit", 

*/ sizeof (BitmapEditRec) , 

*/ NULL, 

*/ NULL, 

*/ FALSE, 

*/ Initialize, 

*/ NULL, 

*/ XtlnheritRealize, 

*/ actions, 

*/ XtNumber (actions) , 

*/ resources, 

*/ XtNumber (resources) , 

*/ NULLQUARK, 

*/ TRUE, 

*/ TRUE, 

*/. TRUE, 

*/ FALSE, 

*/ Destroy, 

*/ Resize, 

*/ Redisplay, 

*/ SetValues, 

*/ NULL, 

*/ XtlnheritSetValuesAlmost, 

*/ NULL, 

*/ NULL, 

*/ XtVersion, 

*/ NULL, 

*/ defaultTranslations, 

*/ QueryGeometry, 

*/ XtlnheritDisplayAccelerator, 

*/ NULL 



{ /* BitmapEdit class part*/ 
/* dummy_field */ 



If you are like most programmers, the core class structure is the biggest structure you have 
ever seen! Don t worry, because many of the fields you will never have to worry about, and 
the rest you will gradually come to know as you need them. We will introduce all the fields 
here, but you are not expected to absorb all the details in a single sitting. Treat this section 
both as an introduction and as a summary to which you can turn back when you encounter a 
field you don t understand. Also, all of the methods and some of the data fields will be 
described in more detail later in the book. These field descriptions reference the section in 
this book where you will find additional information about the field. 

The superclass defines a pointer to the superclass s class structure. This defines 
which widgets this class can inherit from. For a subclass of Core this would be 
SwidgetClassRec; for a subclass of Composite, ScompositeClassRec; for a 
subclass of Constraint, &constraintClassRec,andsoon. 



Inside a Widget 



149 



The next field, class_name, contains the name that will be used to set resources by 
class. In other words, this is the string that you want to appear in the resource database 
when setting resources for all instances of this class. 

The widget_size field is the size of the instance record. This should always be speci 
fied using sizeof with the complete instance record declaration for this class, defined 
in BitmapEditP.h, as an argument In this case the field is initialized to 
sizeof (BitmapEditRec) . Xt uses this field to allocate memory for instance 
records at run-time. 

The next field, class_initialize, is the first of many pointers to widget methods. 
There are several issues regarding methods that require separate treatment, so we ll 
describe these in the next section. The complete list of methods in the Core part structure 
is as follows: class_initialize, class_part_init, initialize, real 
ize, destroy, resize, expose, set_values, set_values_almost, 
query_geometry, and accept_f ocus. 

The display_accelerator field is used in conjunction with accelerators, which 
are a way of redirecting events to actions in different widgets, and will be discussed in 
more detail in Chapter 9, Resource Management and Type Conversion. 

The class_inited field is used internally by Xt to indicate whether this class has 
been initialized before. Always initialize it to FALSE. 

The initialize_hook, set_values_hook, and get_values_hook fields 
are for use in widgets that have subparts that are not widgets. Subparts can have their 
own resources, and can load them from the resource databases like a widget can. These 
methods are called immediately after the method of the same name without _hook, and 
are for performing the same operations except on subparts. (The Text widget is the only 
Athena widget that has subparts.) These fields are described in Chapter 9, Resource Man 
agement and Type Conversion. 

The fields relating to resources, the default translation table, and the actions table have 
already been described. The only one of these fields without an obvious name is the 
tm_table field, in which you place the default translation table. 

The xrm_class field is used internally by Xt, and must always be initialized to 
NULLQUARK. This is a fixed initialization value. 

The compress_motion, compress_exposure, and compress_enterleave 
fields control the Toolkit s event filters. Basically, these filters remove events that some 
widgets can do without, thus improving performance. Unless a widget performs compli 
cated drawing or tracks the pointer, these fields should usually be TRUE. These filters are 
described in Chapter 8, Other Input Sources. 

The visible_interest field can be set to TRUE if your widget wishes to get 
visibilityNotif y events, which signal changes in the visibility of your widget 
Normally this is set to FALSE, because Expose events cause the widget to be redrawn at 
the proper times. For some widgets, however, Expose events are not enough. If your 
widget draws continuously, as in a game, it can stop computing output for areas that are 
no longer visible. There are other cases where VisibilityNotif y events are useful. 



150 X Toolkit Intrinsics Programming Manual 



Xt uses the version field to check the compiled widget code against the library the 
widget is linked against. If you specify the constant Xt Version and it is different from 
the version used by the libraries, then Xt displays a run-time warning message. However, 
if you have intentionally designed a widget to run under more than one version of Xt, you 
can specify the constant XtVersionDontCheck. 

The callback_private field is, as it says, private to Xt, and you always initialize it 
tO NULL. 

The extension field is unused in Release 3. It is for extending the Core widget in 
later releases while maintaining binary compatibility with the current release. 



5.3.5.2 Initializing the Core Methods 

As you ve just seen, there are several places for pointers to methods stored in the Core class 
structure. We will be describing the purpose of each of these methods in the next section. 
But first, a word about how to set the method fields. 

Fortunately, the Core class already defines some of the methods, and you can choose to 
inherit them instead of writing your own. In general, when you set out to write a widget, you 
will pick as your superclass the widget that has the most methods that you can inherit instead 
of write from scratch. 

Broadly speaking, there are two types of methods, self-contained methods and chained meth 
ods. 

A self-contained method is one that is called alone the methods of the same name in the 
widget s superclasses are not called. For example, expose is self-contained. When you 
write the expose method, you are writing all the drawing code for the widget. The 
expose method of the superclass will not be called even if it was designed to do drawing. 
Therefore, by writing an expose method you replace the expose method of the super 
class. 

A chained method is one that is not called alone it is called either before or after all the 
methods of the same name in its superclasses and subclasses. Therefore, you can t replace 
any of the code in this method in the subclasses or superclasses, you can only add to it by 
writing your own. 

Inheritance works differently for each type of method. For self-contained methods, such as 
realize and expose, inheritance works almost as it does for default translations. When 
initializing a field in the class record that represents a self-contained method, you have three 
choices: 

You can define these methods in your widget code by placing the name of the function in 
the class record and defining that function somewhere in the source file. 

You can inherit that method from the immediate superclass by placing a special symbol 
beginning with Xt Inherit in that field in the class record. 



Inside a Widget 1S1 



You can use the first technique, but reference the superclass s method in your method. 
This allows you to add features to the superclass s method without having to completely 
copy it and modify it 

Several other methods such as initialize use the other flavor of inheritance called 
chaining. These methods do not supercede the methods of their superclasses. Instead, the 
methods in each superclass are called in order. Some methods are downward chained, which 
means that the Core method is called first, followed by the same method in each subclass. 
Other methods are upward chained, which means that the Core class method is called last. 
For both upward and downward chained methods, your choice is whether to specify addi 
tional code by defining your own method, or to go with what the other classes have already 
defined. You cannot prevent the code from the other classes from being executed. 

Here is how chaining works for the initialize method in BitmapEdit. Remember that 
BitmapEdit is a subclass of Core. The Core widget s class record contains only the Core part 
structure. The BitmapEdit widget s class record contains the Core and BitmapEdit part struc 
tures. The initialize method is present in the Core part structure of both classes. When 
an application creates an instance of the BitmapEdit widget, Xt calls the function specified in 
the initialize field in the Core class record first, followed by the one in the BitmapEdit 
class record. This is an example of downward chaining. 

The destroy method, on the other hand, is upward chained. That is, the destroy method 
in BitmapEdit would be called first, followed by the destroy method for Core. 

If you specify NULL in your class structure for a method that chains upward or downward, it 
is equivalent to specifying a function that does nothing. The function for that method of the 
superclasses and subclasses will still be called normally. 

Table 5-2 lists which methods fall into each type of inheritance. It also shows how transla 
tions, actions, and resources are chained. 

Table 5-2. Inheritance style of various methods 



Self-contained 


Upward chained 


Downward chained 


class initialize 
realize 


destroy 


class part init 
initialize 


resize 




set values 


expose 
accept focus 
set values almost 




get values hook 
set values hook 
initialize hook 


query geometry 
translations 


actions 


resources 



152 



X Toolkit Intrinsics Programming Manual 



5.3.6 Description of Core Methods 

Here is a brief description of the purpose of each Core method, and where in this book the 
method will be described in detail. All these methods, except realize, can be set to NULL 
in the class record and the widget will still function. However, all widgets that draw into 
their window will also require the expose method, the initialize method, and usually 
the resize method. And to be good children, widgets should define a query_geome- 
try method. The realize method is shown in Section 5.3.8, and the rest of the com 
monly-used methods immediately after that in Chapter 6, Basic Widget Methods. 

This list describes all the methods, even those that are rarely used. There is a lot of detail 
here that you should not expect to absorb in a first reading. Like the list of Core class struc 
ture fields, treat this as an introduction and come back to it later for reference when you come 
across a method you don t know how to use, or if you have something you want to do and 
you don t remember in which method to do it 

initialize sets initial values for all the fields in the instance part structure. This 
method is responsible for checking that all public fields have been set to reasonable val 
ues. This method is downward chained, so each class s initialize method sets the 
initial values for its own instance part structure. This method is described in Chapter 6, 
Basic Widget Methods. 

initialize_hook is called immediately after the initialize method of the same class. 
It allows the widget to initialize subparts, and is used only in widgets that have subparts, 
like the Athena Text widget Subparts have their own resources and are described in Sec 
tion 9.4. The initialize_hook method is also described there, initial- 
ize_hook is downward chained. 

class_initialize is called once, the first time an instance of a class is created by 
the application. The widget registers type converters here, if it has defined any nonstan- 
dard ones. class_initialize is self-sufficient, and is described in Chapter 9, 
Resource Management and Type Conversion. 

class_part_init is called once the first time an instance of a class is created by the 
application. It is different from class_initialize only in that it is downward 
chained. This method resolves inheritance of self-sufficient methods from the immediate 
superclass. It is needed only in classes that define their own methods in their class part 
(but is not present in Core, Composite, or Constraint, because Xt handles inheritance in 
these). This method is described in Chapter 13, Miscellaneous Toolkit Programming 
Techniques. 

realize is called when the application calls XtRealizeWidget. This method is 
responsible for setting window attributes and for creating the window for the widget. It is 
self-sufficient, and is described in Section 5.3.8. 

expose redraws a widget whenever an Expose event arrives from the server (but note 
that Xt can coalesce consecutive Expose events to minimize the number of times it is 
called). This method is responsible for making Xlib calls to draw in the widget s win 
dow. The widget s instance variables are often used in the expose method to guide the 
drawing. This method is self-sufficient This method is described in Chapter 6, Basic 
Widget Methods. 



Inside a Widget 



153 



resize is called when the parent widget resizes the widget It recalculates the instance 
variables based on the new position and size of its window, which are passed into the 
method. This method is self-sufficient and is described in Chapter 6, Basic Widget Meth 
ods, and in Chapter 11, Geometry Management. 

set_values is called whenever the application calls xtSetValues to set the 
resources of the widget This method recalculates private instance variables based on the 
new public instance variable values. It contains similar code to the initialize 
method, but is called at different, and perhaps multiple, times. The set_values 
method is downward chained. This method is described in Chapter 6, Basic Widget 
Methods. 

set_values_almost is used to process application requests to change this widget s 
size. This field should never be NULL. Unless you ve written your own set_val- 
ues_almost method, this field should be set to Xt Inherit SetValuesAlmost. 
Most classes inherit this procedure from their superclass. This method is self-contained 
and is described in Chapter 11, Geometry Management. 

set_values_hook sets resource values in subparts. This method is used only in 
widgets that have subparts, as described in Section 9.4. It is downward chained and is 
described in Chapter 9, Re source Management and Type Conversion. 

accept_f ocus is NULL for most widgets (or, at least, for all the Athena widgets). 
When it is present, this method should set the keyboard focus to a subwidget of this 
widget. This would be used, for example, to allow the application to set the input focus 
to the Text widget within a Dialog widget. This method is invoked when the application 
calls xtCallAcceptFocus. This method is self-contained and is described in Chap 
ter 13 , Miscellaneous Toolkit Programming Techniques. 

get_values_hook is called just after get_values and is used to return the 
resources of subparts. This method is downward chained and is described in Chapter 9, 
Resource Management and Type Conversion. 

destroy deallocates local and server memory allocated by this widget. This is called 
when an application destroys a widget but remains running. This method is described in 
Chapter 6, Basic Widget Methods. 

query_geometry may be called when the parent widget is about to resize the widget. 
The method is passed the proposed new size, and is allowed to suggest a compromise 
size, or to agree to the change as specified. This method it self-contained. It is described 
in Chapter 6, Basic Widget Methods. 

Initialization of the Composite and Constraint class parts, including the methods in those 
structures, is described in Chapter 11, Geometry Management, since this is necessary only in 
widgets that manage children. 



754 X Toolkit Intrinsics Programming Manual 



5.3.7 Packaging the Class Record for Application Use 

The final requirement of the .c file is a pointer to the class record, called bitmapEdit- 
WidgetClass, that applications use as an argument to xtCreateManagedWidget to 
create instances of this widget class. This is shown in Example 5-11. 

Example 5-11. BitmapEdit.c: declaring the class record pointer 

WidgetClass bitmapEditWidgetClass = (WidgetClass) sbitmapEditClassRec; 

bitmapEditWidgetClass is set to be a pointer to the bitmapEditClassRec, the 
complete class record. Remember that since the actual declaration of the class structure is in 
the private include file, the application cannot access class structure fields, and therefore this 
pointer is opaque to the application. 

5.3.8 A Sample Method 

Each method has a particular job to do, and will be described in the chapter that discusses 
that job. However, we ll describe the realize method now, because it is simple and dem 
onstrates the two techniques of inheriting for self-contained fields that were described in Sec 
tion 5.3.5.2. The realize method is responsible for creating the widget s window, and vir 
tually all widgets have a window.* The first technique is to inherit wholesale the method 
defined by the immediate superclass. The superclass may have its own realize method, or 
it may also inherit the method from its superclass, and so on. The Core widget s realize 
method creates a basic window.f In your subclasses of any of these widgets, you can inherit 
the Core realize method without modification by initializing the realize member of 
the Core class record to the symbolic constant xtinheritRealize, as shown in 
Example 5-12. 

BS 

Example 5-12. BitmapEdit.c: inheriting a self-contained method 

BitmapEditClassRec bitmapEditClassRec = { 

{ /* Core class part */ 



XtinheritRealize, /* realize */ 



* A windowless widget is called a gadget. Some versions of Xt support gadgets, but their use has not been standard 
ized. Furthermore, they were created to reduce the overhead of widgets by removing the window maintained on the 
server side and replacing it with client-side code. But at the same time, the X Consortium has reduced the overhead 
of windows to the point where it is questionable whether gadgets are worthwhile. Gadgets are described in Chapter 
12, Menus, Gadgets and Cascading Pop Ups. 

flf you have the source code for Xt, you may discover that the Core widget is actually an amalgamation of several 
other superclasses called WindowObj, RectObj, and so on. (You might also notice the include files for these classes 
in lusrlincludelXll.) The Core widget actually inherits the realize procedure from WindowObj. These classes 
are an implementation detail that will affect you only if you want to look in some of these superclasses to find the 
code that implements features normally attributed to Core. From application code or widget code, it is always safe to 
assume that Core is the top of the class tree. For gadgets (discussed in Chapter 12), you need to know more about 
these "hidden" classes, so we ll discuss them there. 



Inside a Widget 



Example 5-1 2. BitmapEdit.c: inheriting a self-contained method (continued) 



}, 

{ 
o, 

} 



/* BitmapEdit class part */ 

/* dummy field 



Xt also defines symbolic constants for inheriting for every other self-contained method. 
They all begin with Xt Inherit, and in general continue with the capitalized name of the 
method field. 

An important part of the process of creating an X window is the setting of window attributes. 
Therefore, a brief aside on window attributes is necessary. (You can skim the next page if 
you are already familiar with them.) 

Window attributes are basic features of the way the server makes windows look and act. 
Window attributes can also be changed later if necessary, but the realize method is the 
place to set them initially. The Core class realize method sets some basic window attri 
butes such as the window background and border colors or patterns, and it gets these values 
from Core resources. Here is a list of the window attributes that you may wish to set: 

Background can be a solid color, pattern, or transparent. 
Border can be a solid color or pattern. 

Bit Gravity determines how partial window contents are preserved when a window is 

resized. This is an optimization that can save redrawing. 

Backing Store provides hints about when a window s contents should be preserved by the 
server even when the window is obscured or unmapped. This is useful for 
widgets that are very time-consuming to redraw. Not all servers are cap 
able of maintaining a backing store. Check the value returned from the 
Xlib DoesBackingStore macro to determine whether this feature is 
supported on a particular screen on your server. 

Saving Under provides hints about whether or not the screen area beneath a window 
should be saved while a window such as a pop-up menu is in place, to save 
obscured windows from having to redraw themselves when the pop up is 
removed. Not all servers can save under windows. You can find out 
whether this feature is supported on a particular screen with the Xlib 
DoesSaveUnders macro. 

Colormap determines which virtual colormap should be used for this window. If 

your widget requires a lot of specific colors, for example to draw a shaded 
image, it may need to create its own virtual colormap. In that case, it 
would set this attribute to the ID of the created colormap. For more infor 
mation on this, see Chapter 7, Color, in Volume One, Xlib Programming 
Manual. 



156 



X Toolkit Intrinsics Programming Manual 



Cursor determines which cursor should be displayed when the pointer is in this 

window. You must create this cursor before setting this attribute. This can 
be done with a standard type converter, as described in Chapter 13, Mis 
cellaneous Toolkit Programming Techniques. 

It may clarify the picture to describe the features that window attributes do not affect. Set 
ting the window attributes does not determine a window s parent, depth, or visual. These are 
all set when a window is created, and are permanent. The window attributes are also not 
used for setting the size, position, or border width of a widget These are set using xtSet- 
Values. Window attributes do not determine how graphics requests are interpreted; this is 
the job of the graphics context (GC). 

Note that some of the window attributes are not listed here because they should not be set 
directly by widgets, in the realize method or anywhere else. These include the 
event_mask, which controls which events are sent to this widget Xt itself sets this win 
dow attribute based on the translation table. Another is override_redirect, which is 
handled by the Shell widget 

If you want to set additional window attributes for your widget you will use the second 
inheritance scheme used for self-contained fields. You define your own realize method 
just as if you were going to write it from scratch, but then you call the superclass s real 
ize method directly, as shown in Example 5-13. 

Example 5-13. Inheriting by invoking the superclass method from a widget method 
tdefine superclass (SwidgetClassRec) 

static void Realize (w, valueMask, attributes) 

Widget w; 

XtValueMask *valueMask; 

XSetWindowAttributes *attributes; 

{ 

/* this is already set, but just for example */ 

*valueMask |= CWBitGravity; 

attributes->bit_gravity = NorthWestGravity; 

/* use realize method from superclass */ 
(*superclass->core_class. realize) {w, valueMask, attributes); 

} 

Xt passes to the realize method a set of window attributes based on Core instance struc 
ture values. You update these values as necessary, and then call the superclass s realize 
method, as shown. 

See the Xt Realize? roc reference page in Volume Five, X Toolkit Intrinsics Reference 
Manual to find out the default settings of the window attributes as passed into the realize 
method. 

You may wonder what happens if the superclass also inherited its realize method does 
the code in Example 5-13 crash by assuming the superclass field contains a function pointer 
when it actually contains the constant xtlnheritRealize? No. When the class is ini 
tialized, Xt reconciles all the inherited methods and resets the class record fields to be point 
ers to the right methods. 



Inside a Widget 



What is happening behind the scenes when you inherit the realize method is that the Core 
realize method calls the Toolkit function Xt Great eWindow, which in turn calls the 
Xlib function XCreateWindow. You may need to call the Xlib routine yourself in the 
realize method if you want to use a visual other than the default. See the reference page 
for XCreateWindow in Volume Two, Xlib Reference Manual, and Chapter 7, Color, in 
Volume One, Xlib Programming Manual, for details on depth, visual, and the issue of color 
in general. 



5.4 The Public Header File BitmapEdit.h 

The public header file defines the aspects of the widget that can be accessed from the applica 
tion. Public include files tend to be short The two obligatory features of the BitmapEdit.h 
file are: 

An external declaration of bitmapEditwidgetClass, the class record pointer used 
by applications in calls to xtCreateWidget to create an instance of this widget class. 

A pointer to the widget instance record, in this case BitmapEditwidget. Xt calls all 
methods and actions with an argument of type widget. To access any of the fields in 
the instance structure, this pointer must be cast to type BitmapEditwidget. The eas 
iest way to do this is to declare the argument of the method as type BitmapEdit 
widget (the other way is to cast in an assignment). 

If your resource list uses xtN, xtC, or xtR constants not defined in <XlllStringDefs.h>, 
you must define them in the public include file. 

If a widget offers any public functions, they would be declared extern here (and actually 
defined in the .c file). Public functions allow the application to read or change certain private 
data in certain more restricted but more convenient ways than is possible with resources. For 
example, the BitmapEdit widget provides the public function BitmapEditGetArray- 
String that applications can call to get the array of bits currently stored as private data in 
the widget (This array is not an attribute readable with XtGetValues because the current 
implementation does not allow the application to set this array. A future iteration could add 
this feature, and then the public function would cease to be necessary, though it might be 
kept anyway for conveniece and backward compatibility.) 

Example 5-14 shows BitmapEdit s public header file. 
Example 5-1 4. BitmapEdit.h: incidental declarations 

lifndef _ORABitmapEdit_h 
#define _ORABitmapEdit_h 

/* 

* BitmapEdit Widget public include file 
*/ 

/* 

* This include not needed unless the application includes 

* Intrinsic. h after this file. Anyway, it doesn t hurt. 
*/ 



158 X Toolkit Intrinsics Programming Manual 



Example 5-1 4. BitmapEdh.h: incidental declarations (continued) 
tinclude <Xll/Core.h> 



/* Resources: 

* Name 

* 

* (from RectObj) 

* ancestorSensitive 



y 

width 
height 
borderWidth 
sensitive 

(from Core) 

* screen 

* depth 

* colormap 

* background 

* background? ixmap 

* borderColor 

* borderPixmap 



* mappedWhenManaged 

* translations 

* accelerators 

* 

* (from BitmapEdit) 

* foregroundPixel 

* backgroundPixel 

* callback 

* cellSize 

* pixmapWidth 

* pixmapHeight 



Class 



RepType 



Screen 

Depth 

Colormap 

Backgroun 

Pixmap 

BorderColor 
BorderPixmap 

MappedWhen 
Managed 



Pointer 

Int 

Pointer 

pixel 

Pixmap 

pixel 
Pixmap 

Boolean 



Foreground pixel 

Background pixel 

Callback Callback 

CellSize int 

PixmapWidth int 

PixmapHeight int 



Default Value 



Ancestor- 






Sensitive 






Position 


int 





Position 


int 





Dimension 
Dimension 
BorderWidth 


unsigned int 
unsigned int 






Sensitive 







XtCopyScreen 
XtCopyFromParent 
XtCopyFromParent 
White 
XtUnspecif ied- 

Pixmap 
Black 
XtUnspecif ied- 

Pixmap 
True 



Black 

White 

NULL 

30 

32 

32 



* This public structure is used as call_data to the callback. 

* It passes the x, y position of the cell toggled (in units of 

* cells, not pixels) and a mode flag that indicates whether the 

* cell was turned on (1) or off (0) . 
*/ 

typedef struct { 

int mode; 

int newx; 

int newy; 
} BitmapEditPointlnfo; 



#define XtNcellSizelnPixels 
tdefine XtNpixmapWidthlnCells 
fdefine XtNpixmapHeightlnCells 
tdefine XtNcurX 
tdefine XtNcurY 
tdefine XtNcellArray 



"cellSize InPixels" 

"pixmapWidthlnCells" 

"pixmapHeight InCel Is 1 

"curX" 

"curY" 

"cellArray" 



Inside a Widget 



Example 5-1 4. BitmapEdit.h: incidental declarations (continued) 

#define XtCCellSizelnPixels "CellSizelnPixels" 

tdefine XtCPixmapWidthlnCells "PixmapWidthlnCells" 

tdefine XtCPixmapHeightlnCells "PixmapHeightlnCells" 

tdefine XtCCurX "CurX" 

#define XtCCurY "CurY" 

fdefine XtCCellArray "CellArray" 

extern char *BitmapEditGetArrayString ( ) ; /* w */ 
/* Widget w; */ 

/* Class record constants */ 

extern WidgetClass bitmapEditWidgetClass; 

typedef struct _BitmapEditClassRec *BitmapEditWidgetClass; 
typedef struct _BitmapEditRec *BitmapEditWidget ; 

fendif /* _ORABitmapEdit_h */ 

/* DON T ADD STUFF AFTER THIS #endif */ 

It is a good idea to comment the types of the resources for all superclasses as shown in 
Example 5-14. Not only is this a good summary for you of all the resources of your widget, 
but it allows the application programmer to use this file for documentation when creating 
argument lists. 



5.5 The Process of Widget Writing 

The process of writing a widget always begins with the same steps. They are: 

Copy all three files of the widget most similar to the one you intend to write; pick one 
that has many methods defined so that you don t need to type them in. (It s easier to 
delete than to retype.) 

Globally change the widget class name in the files. The fastest way to do this under UNIX 
is with sed, using a script similar to the following: 

s/BitmapEdit/AfewMime/g 
s/bi-tmapEdit/newName/q 

Place this script in the file sedscr, and run the command: 

spike% sed -f sedscr file > new file 
on each file. (Or write a simple for loop to run it on multiple files.) 

Start from the top of the .c file, and begin by writing the resource list. While writing the 
resource list, you may need to edit the public header file to define new resource names 
and classes (xtN and xtc symbols). While writing the resource list (and during the 
entire widget- writing process), you will also need to edit the private header file in order 
to add and remove instance part structure fields, as you determine a need for them while 
writing methods and actions. Later you will probably discover additional parameters that 
you want to define as resources. 



160 X Toolkit Intrinsics Programming Manual 



Design the output you expect your widget to draw. Your instance part structure fields 
must hold all the information necessary to redraw everything when the window is expo 
sed add the necessary fields. 

Design the user input you expect your widget to accept Start with as many separate 
actions as you can one for each distinguishable user input idiom. For example, 
BitmapEdit has three actions for changing one bitmap cell: DrawCell, UndrawCell, 
and ToggleCell. Even though these invoke almost identical underlying code, it is 
best to keep them as separate actions. 

Design a default translation table to have these actions called in response to the appropri 
ate events. Help in this area is available in Section 7.1.2. 

Write the expose method and actions. Just how to do this is described in the next chap 
ter. But in summary, both the expose method and actions often draw into the widget. 
The expose method must always be able to redraw what the actions drew. Therefore, it 
usually pays to have common elements of code called by both an action and the expose 
method. Neither the action nor the expose method pass arguments to this common 
code. Instead, the actions set instance variables that are read in the expose method or 
common code. The instance variables act as global variables because they are available 
almost everywhere in the widget code. 

Add parameters that allow your drawing code to work smoothly in any size window, and 
add a resize method that sets these parameters. 

Add the initialize method to check resource values that might have been user sup 
plied and to initialize private instance variables. 

Add the set_values method to check application-supplied resource values and reset 
private instance variables based on the new resource values. 

Declare the methods and actions you have defined, near the top of the .c file. 

Enter all these functions and tables you have defined into the class structure initialization. 

It is useful to have a simple application available for testing your widget as you develop it. 
One that simply creates the widget under construction and provides a Quit button is quite 
adequate. Then you can add code to the widget incrementally, assuring at each step that the 
program compiles, links, and runs without error. 

As this list implies, it is a good idea to start simply and complete all the above steps for a 
small subset of the features you eventually want. Once you have a working widget that you 
can test, you can add features one at a time by going through the list again. If instead you 
attempt to write an ambitious widget in one pass, you will spend much longer debugging it. 

Once you have learned how to write methods and actions in the next chapter, Basic Widget 
Methods, you should be ready to write a simple widget 



Inside a Widget 



5.6 Summary of Conventions 



The naming conventions for the various structure declarations in the widget source files can 
be confusing. Table 5-3 summarizes these conventions, using the BitmapEdit widget as an 
example, and describes where each type is used. This table is just to help you read the code. 
If you create a new class starting from an existing class, and globally change the names as 
described above, all of the definitions and references listed here will already be done for you. 

Table 5-3. Summary ofXt Structure Name Conventions 



Structure Name 



Description 



BitmapEditClassPart 

BitmapEditClassRec 

bitmapEditClassRec 

BitmapEditPart 

BitmapEditRec 

_BitmapEditRec 

_BitmapEditClassRec 

BitmapEditWidget 

BitmapEditWidgetClass 
bitmapEditWidgetClass 



Partial class structure typedef (usually dummy field only) used 
for defining BitmapEditClassRec in P.h file. 
Complete class structure typedef, declared extern in P.h file, 
used for initializing class structure in .c file. 
Name of complete class structure allocated in .c file, declared 
extern in P.h file, allocated in .c file, used as superclass in 
class record initialization of subclasses of this widget (.c file). 
Partial instance structure typedef, used for defining Bitmap 
EditRec in P.h file. 

Complete instance structure typedef, also used to initialize 
widget_size field of class record in .c file. 
Type of BitmapEditRec, used for defining BitmapEdit 
Widget pointer in .h file. 

Type of BitmapEditClassRec, used for defining 
BitmapEditWidgetClass pointer in .h file. 
Pointer to BitmapEditRec (complete instance structure), 
used to reference instance structure fields in .c file (passed as 
argument to methods). 

Pointer to _BitmapEditClassRec, used to cast bitmap 
EditClassRec for superclass in class record initialization of 
subclasses of this widget (.c file). 

Of type WidgetClass, address of bitmapEditClass 
Rec, used in XCreateWidget calls to identify class to be 
created. 



162 



X Toolkit Intrinsics Programming Manual 



6 



Basic Widget Methods 



This chapter describes the initialize, expose, set_values, resize, query geom 
etry, and destroy methods. It explains when Xt calls each method, and 
describes in detail what should be in each of these methods. Among other 
things, these methods prepare for and do the drawing of graphics that appear 
in a widget. This chapter describes what the Toolkit adds to the graphics 
model provided by Xlib, but does not describe in detail how to draw using Xlib; 
this topic is described in Chapters 5, 6 and 7 of Volume One, Xlib Program 
ming Manual. This chapter also describes how to write action routines that 
work in the widget framework. 

In This Chapter: 

The X Graphics Model Inside Widgets 166 

The initialize Method 166 

Creating GCs 168 

The expose Method 170 

The set_yalues Method 174 

The resize Method 177 

The query_geometry Method 180 

The destroy Method 183 

Actions in the Widget Framework 184 



6 
Basic Widget Methods 



This chapter describes the initialize, expose, set_values, resize, 
query_geometry, and destroy methods. These are the methods you need to write to 
make a functioning widget (although destroy is optional). The thread that ties most of 
these methods together is that they have a role in drawing graphics, although all but the 
expose method are also responsible for other things. We will describe all the responsibili 
ties of these methods, but focus on the issues involving graphics because they are so impor 
tant. 

Three of these methods are called by Xt in response to application function calls: 

The initialize method is called when the application calls xtCreateWidget. 

The set_values method is called when the application calls xtSetValues. 

The destroy method is called when the application calls xtDestroyWidget. 

A fourth method, expose, is called in response to Expose events, which occur whenever 
part or all of a widget s window becomes newly visible on the screen.* 

When the parent widget, which is usually a geometry-managing Composite or Constraint 
widget, needs to resize one of its children, it may call the child s query_geometry 
method to find the child s opinion of the proposed change. Once the parent has actually 
resized the child, Xt calls the child s resize method, which is responsible for calculating 
private instance variables, so that the child is prepared to redraw itself in its new window 
size. 

Applications that use the Toolkit should do all their drawing in widgets. Although it is pos 
sible to create normal X windows and draw into them from the application code, you lose the 
advantage of Xt s event dispatching, event filtering, and other features. It s just as easy to 
draw in a widget, and it s easier to add processing of user input as described in Chapter 7, 
Events, Translations, and Accelerators. 



*Note that Expose events are also handled through the translation mechanism like any other event. When they are 
present in the translation table, the action registered for Expose events will be called in addition to the expose 
method. Widgets do not normally include the Expose event in their translation table, because they already have the 
expose method. Applications might, conceivably, have Expose in their translation table to add drawing capabil 
ity to a widget, although it is difficult to calculate where to do this drawing from the application since the widget s 
size may change. 



Basic Widget Methods 165 



6.1 The X Graphics Model Inside Widgets 

Section 4.3.1 described the X graphics model and how drawing from the application is 
accomplished. In summary, the process consisted of creating GCs and then drawing from a 
function that Xt calls on receipt of Expose events. Drawing from inside a widget follows 
the same general procedure, but the code is organized differently. 

Inside a widget, you normally create GCs with the Xt routine xtGetGC instead of the Xlib 
routine XCreateGC. XtGetGC is similar to the Xlib routine except that it arranges for the 
sharing of GCs among widgets within an application. This is important because each GC has 
some overhead and servers can achieve better performance when handling fewer GCs. 
Because Xt applications often have many instances of the same widget class, each needing 
the same GC characteristics (unless the user specifies a different color for each one), Xt 
arranges for them to share GCs when possible. 

Xt organizes GC creation and drawing into separate methods. Setting initial values for the 
GC and creating the GC is done in the initialize method, and actual drawing is done in 
the expose method. This makes it very easy to find this code in existing widgets and 
straightforward to write this code for new widgets. 

Since Xt allows resources to be changed during program execution by calling xtSet- 
Values, the widget code must be prepared to change the GC at any time if the GC compo 
nents depend on resource values. The set_values method calculates the new values 
based on resource changes and updates the appropriate GCs. 

The next six major sections discuss the code needed to implement the initialize, 
expose, set_values, resize, query_geometry, and destroy methods. 



6.2 The initialize Method 



As described in Section 5.3.5.2, the initialize method has basically one function: it 
sets instance structure members (also called instance variables).* This job has two parts: 
setting the initial values of private instance variables, and checking to make sure that the val 
ues of the public instance variables are valid (since they are user configurable). Since the 
initialize method is upward chained (defined in Section 5.3.5.2), the method for this 
class needs to initialize only the fields present in the instance part structure for this class. 
The exceptions are width and height. Even though they are instance variables of Core, 
they need to be checked by the subclass, because only this class knows its desired initial size. 

Example 6-1 shows the initialize method from BitmapEdit 



* As described in Chapter 1 1 , Geometry Management, the initialize method can also be used for creating child 
widgets of any widget This is a way of getting around Xt s geometry management scheme, and is not frequently 
done. 



166 X Toolkit Intrinsics Programming Manual 



Example 6-1. The initialize method 

/* ARGSUSED */ 

static void 

Initialize (request, new) 

BitmapEditWidget request, new; 

{ 

/* 

Alternate method of casting: 

BitmapEditWidget cw = (BitmapEditWidget) new; 



Set widget to initially display starting at top-left 

corner of bitmap 
*/ 

new->bitmapEdit .cur_x = 0; 
new->bitmapEdit .cur_y = 0; 

/* 

* Check instance values set by resources that may be invalid. 
*/ 

if ( (new->bitmapEdit .pixmap_width_in_cells < 1) || 

(new->bitmapEdit .pixmap_height_in_cells < 1)) { 
XtWarningC BitmapEdit : pixmapWidth and/or pixmapHeight is too \ 

small (using 10 x 10)."); 

new->bitmapEdit .pixmap_width_in_cells = 10; 
new->bitmapEdit .pixmap_height_in_cells = 10; 
} 

if (new->bitmapEdit .cell_size < 5) { 

XtWarningC BitmapEdit: cellSize is too small (using 5)."); 

new->bitmapEdit .cell_size = 5; 
} 

if ( (new->bitmapEdit .cur_x < 0) || (new->bitmapEdit . cur_y < 0) ) { 
XtWarningC BitmapEdit: cur_x and cur_y must be non-negative \ 

(using 0, 0) . ") ; 
new->bitmapEdit . cur_x = 0; 
new->bitmapEdit .cur_y = 0; 

} 

/* 

* allocate memory to store array of cells 
*/ 

if (new->bitmapEdit .cell == NULL)/*unless NULL, application allocated*/ 
new->bitmapEdit .cell = 

XtCalloc (new->bitmapEdit .pixmap_width_in_cells 
* new->bitmapEdit .pixmap_height_in_cells, 
sizeof (char) ) ; 

new->bitmapEdit .pixmap_width_in_pixels = 

new->bitmapEdit .pixmap_width_in_cells 

* new->bitmapEdit . cell_size; 

new->bitmapEdit .pixmap_height_in_pixels = 

new->bitmapEdit .pixmap_height_in_cells 

* new->bitmapEdit .cell_size; 
if (new->core .width == 0) 

new->core. width = (new->bitmapEdit .pixmap_width_in_pixels 



Basic Widget Methods 167 



Example 6-1. The initialize method (continued) 

> 300) ? 

300 : (new->bitmapEdit .pixmap_width_in_pixels) ; 
if (riew->core . height == 0) 

new->core. height = (new->bitmapEdit .pixmap_height_in_pixels 

> 300) ? 

300 : (new->bitmapEdit .pixmap_height_in_pixels) ; 

CreateBigPixmap (new) ; 

GetDrawGC (new) ; 
GetUndrawGC (new) ; 
GetCopyGC (new) ; 

DrawIntoBigPixmap (new) ; 
} 

Even though the specific instance variables initialized here are particular to BitmapEdit, the 
techniques are common to all initialize methods. Some private instance variables, 
such as cur_x and cur_y, do not depend on resource settings and are simply initialized to 
a fixed value. Public instance variables are checked; if their values are out of range, xt- 
Warning is called to print a message on the standard output and they are instead initialized 
to a fixed value. Some private instance variables are set based on public instance variables. 
GCs are the most common example. 

6.2.1 Creating GCs 

In any widget that does drawing, some of the private instance variables will hold the IDs of 
GCs created in the initialize method. These variables will be read when the GCs are 
needed in the expose method, and will be reset if necessary in the set_values method. 
Example 6-1 called separate routines, GetDrawGC, GetUndrawGC, and GetCopyGC to 
create the GCs. Example 6-2 shows these routines. 

A program prepares for creating a GC by setting the desired characteristics of the GC into 
members of a large structure called XGCValues (defined by Xlib), and specifying which 
members of XGCValues it has provided by setting a bitmask. This bitmask is made by 
ORing the GC mask symbols defined in <Xll/X.h>. Each bitmask symbol represents a mem 
ber of the XGCValues structure. Every GC field has a default value, so only those values 
that differ from the default need to be set. The default GC values are discussed in Volume 
One, Xlib Programming Manual. 

Widget code normally creates a GC with the xtGetGC call, not the Xlib analogue 
XCreateGC. XtGetGC keeps track of requests to get GCs by all the widgets in an appli 
cation, and creates new server GCs only when a widget requests a GC with different values. 
In other words, after the first widget creates a GC with XtGetGC, any subsequent widget 
that calls XtGetGC to create a GC with the same values will get the same GC, not a new 
one. Using this client-side caching also reduces the number of requests to the server. 

Xlib provides XChangeGC to change the values in an existing GC. Xt provides no analo 
gue. Because of the sharing of GCs allocated with XtGetGC, you must treat them as read 
only. If you don t, you may confuse or break other widgets. In cases where your widget 



168 X Toolkit Intrinsics Programming Manual 



creates a GC that needs changing in such a way that it is impractical to create a new GC each 
time, it may be appropriate to use the Xlib call XCreateGC instead of the Xt call XtGet 
GC. 

BitmapEdit must use XCreateGC for two of its three GCs because these GCs are for draw 
ing into pixmaps of depth 1, while XtGetGC always creates GCs for drawing into windows 
or pixmaps of the default depth of the screen. In other words, XtGetGC would work on a 
monochrome screen, but not on color. However, this is an unusual situation. Most widgets 
can use XtGetGC exclusively. 

Example 6-2. Creating GCs from the initialize method 

static void 
GetDrawGC (cw) 
BitmapEditWidget cw; 

XGCValues values; 

XtGCMask mask = GCForeground | GCBackground | GCDashOffset | 
GCDashList I GCLineStyle; 

/* 

* Setting foreground and background to 1 and looks like a 

* kludge but isn t. This GC is used for drawing 

* into a pixmap of depth one. Real colors are applied with a 

* separate GC when the pixmap is copied into the window. 
*/ 

values . foreground = 1; 

values .background = 0; 

values. dashes = 1; 

values .dash_off set = 0; 

values. line_style = LineOnOf fDash; 

cw->bitmapEdit .draw_gc = XCreateGC (XtDisplay (cw) , 
cw->bitmapEdit ,big_picture, mask, Svalues) ; 

static void 
GetUndrawGC (cw) 
BitmapEditWidget cw; 

XGCValues values; 

XtGCMask mask = GCForeground I GCBackground; 

/* Looks like a kludge but isn t see comment in GetDrawGC */ 
values . foreground = 0; 
values .background = 1; 

cw->bitmapEdit.undraw_gc = XCreateGC (XtDisplay (cw) , 
cw->bitmapEdit ,big_picture, mask, svalues) ; 

static void 
GetCopyGC (cw) 



BitmapEditWidget cw; 

XGCValues values 
XtGCMask mask = 

values. foreground = cw->bitmapEdit . foreground 



XGCValues values; 

XtGCMask mask = GCForeground | GCBackground; 



Basic Widget Methods 169 



Example 6-2. Creating GCs from the initialize method (continued) 

values .background = cw->core . background j>ixel; 

/* This GC is the same depth as screen */ 
cw->bitmapEdit .copy_gc = XtGetGC(cw, mask, Svalues) ; 
} 

As shown in Example 6-2, some GC components are set based on other instance variables, 
and some are just hardcoded. In this example, the foreground pixel value (color) in the GC is 
set to be the value of the foreground instance variable, which is derived from a resource 
of BitmapEdiL The background pixel value is derived from a resource of the Core widget. 
(Core defines a background resource but no foreground.) On the other hand, the 
line_style member of XGCValues is set to LineOnOf f Dash regardless of resource 
settings. In general, you hardcode the GC components that you don t want to be user cus 
tomizable. (All these instance variables are defined in the yourwidgetPart structure 
defined in yourwidgetP.h.) 

Certain GC parameters are traditionally handled as resources rather than being hardcoded. 
Colors and fonts are the most basic examples. In the X Window System you can t use a color 
until you allocate a pixel value for it, and you can t use a font until you load it. The code that 
processes resources called by xt Initialize automatically allocates and loads the colors 
and fonts specified as resources, and sets the instance variables to the right representation 
type as specified in the resource table. Therefore, it is actually easier to provide user custom 
izability than to convert values to the representation types required to hardcode them. 

How the resource conversion process works will be described in more detail in Chapter 9, 
Resource Management and Type Conversion. To decide which GC settings you need for your 
application, see Chapter 5, The Graphics Context, in Volume One, Xlib Programming Man 
ual. 



6.3 The expose Method 

The expose method is responsible for initially drawing into a widget s window and for 
redrawing the window every time a part of the window becomes exposed. This redrawing is 
necessary because the X server does not maintain the contents of windows when they are 
obscured. When a window becomes visible again, it must be redrawn. 

The expose method usually needs to modify its drawing based on the geometry of the win 
dow and other instance variables set in other methods. For example, the Label widget will 
left-justify, center, or right-justify its text according to the XtN justify resource, and the 
actual position to draw the text depends on the widget s current size. 

Another factor to consider when writing the expose method is that many widgets also draw 
from action routines, in response to user events. For example, BitmapEdit toggles bitmap 
cells in action routines. The expose method must be capable of redrawing the current state 



1 70 X Toolkit Intrinsics Programming Manual 



of the widget at any time. This means that action routines usually set instance variables 
when they draw so that the expose method can read these instance variables and draw the 
right thing. 

BitmapEdit uses a slightly unusual exposure handling strategy. Most widgets keep track of 
what they draw in some form of arrays or display lists. When they need to redraw, they sim 
ply replay the saved drawing commands in the original order to redraw the window. For 
example, BitmapEdit keeps track of the state of each bitmap cell in a character array. It 
could easily traverse this array and redraw each cell that is set in the array. 

However, BitmapEdit does not use this strategy. In order to improve its scrolling perfor 
mance, the expose method copies an off-screen pixmap into the window whenever 
redisplay is required. The actions draw into this off-screen pixmap, and then call the 
expose method directly to have the pixmap copied to the window. 

The expose method is passed an event that contains the bounding box of the area exposed. 
To achieve maximum performance it copies only this area from the pixmap to the window. 
The BitmapEdit actions take advantage of this, too. They manufacture an artificial event 
containing the bounding box of the cell to be toggled, and pass it when they call expose. 
This causes the expose method to copy that one cell that was just updated to the window. 

Example 6-3 shows the expose method from the BitmapEdit widget. 
Example 6-3. The expose method 

/* ARGSUSED */ 

static void 
Redisplay (cw, event) 
BitmapEditWidget cw; 
XExposeEvent *event; 
{ 

register int x, y; 
unsigned int width, height; 
if (IXtlsRealized(cw) ) 
return; 

if (event) { /* called from btn-event */ 

x = event->x; 

y = event->y; 

width = event->width; 

height = event->height; 
} 

else { /* called because of expose */ 
x = 0; 
y = 0; 

width = cw->bitmapEdit .pixmap_width_in_pixels; 
height = cw-->bitmapEdit .pixmap_height_in_pixels; 
} 

if (Def aultDepthOf Screen (XtScreen (cw) ) == 1) 

XCopyArea (XtDisplay (cw) , cw->bitmapEdit .big_picture, 
XtWindow(cw) , 

cw->bitmapEdit .copy_gc, x + cw->bitmapEdit .cur_x, y + 
cw->bitmapEdit .cur_y, width, height, x, y) ; 



Basic Widget Methods 171 



Example 6-3. The expose method (continued) 

else 

XCopyPlane (XtDisplay (cw) , cw->bitmapEdit .big_picture, 
XtWindow(cw) , 

cw->bitmapEdit .copy_gc, x + cw->bitmapEdit .cur_x, y + 
cw->bitmapEdit .cur_y, width, height, x, y, 1); 

Note that the expose method first checks to see that the widget is realized using xt- 
is Realized. This is a precaution against the unlikely event that an instance of this 
widget is suddenly destroyed or unrealized by an application while Expose events are still 
pending. If this did happen, drawing on the nonexistent window would cause an X protocol 
error. 

Next, BitmapEdit s expose method sets the rectangle it will redraw based on the event 
passed in by Xt. We also call this method directly from the action that processes button 
presses. That action routine creates a pseudo-event to pass to expose to describe the area 
to be drawn. 

If the compress_exposures field of the class structure is initialized to TRUE, as it is in 
BitmapEdit, Xt automatically merges the multiple Expose events that may occur because of 
a single user action into one Expose event. In this case, the Expose event contains the 
bounding box of the areas exposed. BitmapEdit redraws everything in this bounding box. 
For widgets that are very time-consuming to redraw, you might want to use the third argu 
ment of the expose method, which is a region. The Region type is opaquely defined by 
Xlib (internally a linked list of rectangles). The Region passed into expose describes the 
union of all the areas exposed by a user action. You can use this region to clip output to the 
exposed region, and possibly calculate which drawing primitives affect this area. Xlib pro 
vides region mathematics routines (such as XRectinRegion) to compare the regions in 
which your widget needs to draw with the region needing redrawing. If certain areas do not 
require redrawing, you can skip the code that redraws them, thereby saving valuable time. 
However, if this calculation is complicated, its cost/benefit ratio should be examined. 

Consider the arrangement of windows shown in Figure 6-1. Window 1 and Window 3 are 
other applications, and Widget 2 is an application consisting solely of our widget 

Initially, Window 3 is on top, Window 1 is behind it, and Widget 2 is hidden completely 
behind Window 1. When Window 1 is lowered, Widget 2 becomes visible, except where it is 
still overlapped by Window 3. The newly-exposed area can be described by two rectangles; 
A and B. If compress_exposure is FALSE, Widget 2 s expose method will be called 
twice, and passed an Expose event first describing Rectangle A, then Rectangle B. But if 
compress_exposure is TRUE, Widget 2 s expose method will be called just once, 
passed an Expose event describing the bounding box of all the original Expose events 
(which would be the entire widget in this case), and passed a Region which is the union of 
the rectangles described by all of the Expose events. The region argument of the 
expose method is unused unless compress_exposures is TRUE. 

Each of these exposure handling techniques may be the best for certain widgets. For a 
widget like BitmapEdit, any of the three methods will work, but the bounding box method is 
the most efficient and convenient. For a complete description of Expose event handling 
strategies, see Chapter 8, Events, in Volume One, Xlib Programming Manual. 



172 X Toolkit Intrinsics Programming Manual 



window 1 



widget 2 
expose A - 



B 



expose B 



window 3 - 
(overlapping window) 



bounding 
rectangle in 
merged 
expose event 



region 




Figure 6-1. compress_exposures: 2 rectangles if FALSE; the bounding box and a region if 
TRUE 

The remainder of BitmapEdit s expose method shown in Example 6-3 consists of a single 
Xlib call to copy from a pixmap into the widget s window. As described in Chapter 4, An 
Example Application, BitmapEdit makes a large pixmap that is one plane deep and draws the 
current bitmap into it. When needed in the expose method, this pixmap just has to be 
copied into the window. This approach was chosen for its simplicity. When scrollbars are 
added, the widget is able to pan around in the large bitmap quickly and efficiently. Note that 
one of two Xlib routines is called based on the depth of the screen. This is because XCopy- 
Area is slightly more efficient than XCopyPlane and should be used when running on a 
monochrome screen. 



Basic Widget Methods 



173 



Note that instance variables are used for the arguments of the Xlib routines in Example 6-3. 
Don t worry about exactly what each Xlib routine does or the meaning of each argument. 
See the reference page for each routine in Volume Two, Xlib Reference Manual, when you 
need to call them in your code. 

See Chapters 5, 6, and 7 in Volume One, Xlib Programming Manual, for more information on 
the GC, drawing graphics, and color, respectively. 



6.4 The set_vaiues Method 

When the application calls xt Set Values to change widget resources during run time, Xt 
calls the set_values method. The set_values method is where a widget responds to 
changes in its public instance variables. It should validate the values of the public variables, 
and recalculate any private variables that depend on public variables that have changed. 

Example 6-4 shows the set_values method for BitmapEdit. 
Example 6-4. The set_values method 

/* ARGSUSED */ 

static Boolean 

SetValues (current , request, new) 

Widget current, request, new; 

{ 

BitmapEditWidget curcw = (BitmapEditWidget ) current; 

BitmapEditWidget newcw = (BitmapEditWidget) new; 

Boolean do_redisplay = False; 

if (curcw->bitmapEdit . foreground_pixel != 

newcw->bitmapEdit . f oreground_pixel ) { 

XtReleaseGC (curcw, curcw->bitmapEdit . copy_gc) ; 

GetCopyGC (newcw) ; 

do_redisplay = True; 
} 

if ( (curcw->bitmapEdit .cur_x != newcw->bitmapEdit .cur_x) I I 

(curcw->bitmapEdit .cur_y != newcw->bitmapEdit . cur_y) ) { 
do_redisplay = True; 
} 

if (curcw->bitmapEdit .pixmap_width_in_cells != 

newcw->bitmapEdit .pixmap_width_in_cells) { 
newcw->bitmapEdit .pixmap_width_in_cells = 

curcw->bitmapEdit . pixmap_width_in_cells; 
XtWarning ("BitmapEdit: pixmap_width_in_cells cannot be set by\ 

XtSetValues.\n") ; 
} 

if (curcw->bitmapEdit .pixmap_height_in_cells != 

newcw->bitmapEdit .pixmap_height_in_cells) { 
newcw->bitmapEdit .pixmap_height_in_cells = 

curcw->bitmapEdit . pixmap_height_in_cells; 

XtWarning ("BitmapEdit : pixmap_height_in_cells cannot be set by\ 
XtSetValues.Xn") ; 



174 X Toolkit Intrinsics Programming Manual 



Example 6-4. The set_values method (continued) 

/* the following limitation is removed later on: */ 
if (curcw->bitmapEdit .cell_size_in_pixels != 

newcw->bitmapEdit .cell_size_in__pixels) { 
newcw->bitmapEdit .cell_size_in_pixels = 

curcw->bitmapEdit . cell_size_in_pixels; 

XtWarningC BitmapEdit : cell_size_in_pixels cannot be set by\ 
XtSetValuesAn") ; 



return do_redisplay; 

The set_values method is called with three copies of the widget s instance structure as 
arguments: current, request, and new. The current copy includes the current set 
tings of the instance variables, and request includes the settings made through xtSet- 
Values but not yet changed by the superclasses set_values methods. The new copy 
is the same as request except that it has already been processed by the set_yalues 
methods of all superclasses. 

For each public variable, set_values compares the current value and the new value, and 
if they are different, validates the new value or changes any private values that depend on it. 
The new copy is the only one that the method changes; request and current are only 
for reference. As in the initialize method, you have to deal only with the instance vari 
ables for your subclass, and perhaps with width and height, because the set_values 
method is downward chained. Superclass set_values methods take care of setting all the 
superclass instance fields. However, if desired, you can change superclass fields in your 
method since it is called last. For example, this might be useful if your class has different cri 
teria for determining valid values or dependencies. 

The request copy of the instance variables is used only if your class needs to decide 
between a superclass setting and your widget s setting; disagreements about this usually 
occur over the size of the widget For more information on when to use request, see the 
reference page for xtSetValuesFunc in Volume Five, X Toolkit Intrinsics Reference 
Manual. 

It is also important to notice that the set_values method, if it exists at all (that is, ifj.it is 
not specified as NULL in the class structure), must return TRUE or FALSE to indicate whether 
the changes made to the state variables require the widget to be redrawn. If it is TRUE for this 
class or any superclass, Xt calls the Xlib routine XClearArea with the exposures argu 
ment set to TRUE (to force the background of the widget to be redrawn, which normally 
occurs only after Expose events), and then Xt calls the expose method. In other words, 
you should make set_values return TRUE whenever the changes to the instance variables 
will change what is drawn in the widget. 

Note, however, that set_values should not return TRUE if width and height change, 
because the X server automatically generates Expose events for a window when it is 
resized. If you do return TRUE in this case, your expose method will be called twice. 



Basic Widget Methods 175 



Since the application may call XtSetValues before the widget is realized, it is important 
not to assume in the set_values method that the widget has a window. In other words, 
the code must use xt isRealized to check whether the widget is realized before using the 
xt window macro, such as in a call to set window attributes. 

As mentioned earlier, some of the private variables are usually GCs. Whenever the public 
variable for a color or font is changed through XtSetValues, a GC also has to be 
changed. This is an example of a private variable depending on a public one. GCs allocated 
with xtGetGC should not be changed since they may be shared by other widgets. There 
fore, the normal response to a change in one of the resources on which a GC depends is to 
release the GC with XtReleaseGC and request a new one with XtGetGC.* 

If some of your widget s GCs are unlikely to be shared by other widget instances in an appli 
cation (either because each instance will use different values for the GC components or there 
will be only one instance), and the widget needs to be able to make changes to them, and the 
changes are not predictable enough or few enough to reasonably create a GC for each varia 
tion, then the xtGetGC/xtReleaseGC approach is not ideal. What happens in this situa 
tion is that XtGetGC creates a new GC and XtReleaseGC frees the old GC every time a 
change is made, even if the changes are small. It is more efficient in this situation to change 
the affected values in the existing GC. But this can be done only with an Xlib routine there 
is no Toolkit routine for changing a GC. To implement this approach, you create, modify, 
and free the unusual GC using Xlib routines only. You call XCreateGC in the initial 
ize method to create the GC, XChangeGC in the set_yalues method to change the 
GC, and XFreeGC in the destroy method to free the GC. All of these Xlib routines are 
described in Chapter 5, The Graphics Context, in Volume One, Xlib Programming Manual. 

XtGetGC always creates a GC that can only be used on drawables (windows and pixmaps) 
of the default depth of the screen. Drawing into a pixmap of depth one using a GC created 
with XtGetGC works on a monochrome display, but usually does not work on a color dis 
play. (The depth is the number of bits per pixel used to represent colors on the screen.) This 
is another situation in which you will need to call XCreateGC instead of XtGetGC. 

Note also that BitmapEdit does not allow three of its resources to be changed by XtSet 
Values; they can be set only until the widget is created. To disallow changes to a resource, 
the set_values method must actively set the value in the new widget (newcw) to the 
value in the current widget (curcw), wiping out the setting made through XtSetValues. 
It is also advisable that the widget print a message describing that the resource cannot be set 
through XtSetValues. 

The xtwarning call used in the example is simply an alternative to calling fprintf . It 
helps to make all error messages uniform, and is described in Chapter 13, Miscellaneous 
Toolkit Programming Techniques. 



*In Release 2, the function to release a GC was called XtDestroyGC. 



1 76 X Toolkit Intrinsics Programming Manual 



6.5 The resize Method 



When a widget is used in an application, it is created with a parent that will manage its geom 
etry. Depending on the layout policy of this parent widget in the application, the widget s 
window may change size when the application is resized.* Most widgets need to recalculate 
the position and size of their graphics when their window changes size. This is the job of the 
resize method. 

The resize method is passed only one argument, the widget instance structure pointer 
(widget ID). This structure contains the new position, size, and border width of the widget s 
window. The method changes any instance part fields that depend on the size or position of 
the widget When the resize method returns, Xt calls the expose method, regardless of 
whether or not the contents need redrawing. (It is a basic characteristic of the X server that it 
generates Expose events when a window is resized.) 

A Label widget whose text is centered would reset the starting position of its text in the 
resize method. 

In some widgets, it takes some thought to determine the correct response to resizing. Take 
BitmapEdit, for example. BitmapEdit is designed to be able to show only a portion of the bit 
map, so that scrollbars can pan around in the complete bitmap. When the application is 
resized, should BitmapEdit show more cells or increase the cell size? Up to the point where 
the entire bitmap is shown, it is easier to increase the number of cells shown. When Bitmap- 
Edit is resized larger than necessary to show the entire bitmap, it should probably increase 
the cell size. We will use this strategy in the resize method of the BitmapEdit widget, 
which is shown in Example 6-5. 

This resize strategy does have one problem. It never reduces the cell size. This is not a seri 
ous problem because BitmapEdit has a resource that controls the cell size. Therefore, the 
application that uses this widget could provide a user interface for setting the cell size if the 
application writer was concerned about this problem. 

Example 6-5. BitmapEdit: the resize method 

/* ARGSUSED */ 
static void 
Resize (cw) 

BitmapEditWidget cw; 
{ 

/* 

* resize does nothing unless new size is bigger 

* than entire pixmap 
*/ 

if ( (cw->core .width > 

cw->bitmapEdit .pixmap_width_in_pixels) && 
(cw->core .height > 



*Also note that the application may be resized when it is first mapped on the screen, when the user sizes the rubber- 
band outline of the application provided by most window managers. (You may not think of this as resizing, but it is.) 
When this happens, the application has already created its widgets and the widgets have created windows. Therefore, 
the re si ze method of a widget will be called if its parent widget is forced to resize it. 



Basic Widget Methods 1 77 



Example 6-5. BitmapEdit: the resize method (continued) 

cw->bitmapEdit .pixmap height in oixels) ) { 
/* 

* Calculate the maximum cell size that will allow 

* the entire bitmap to be displayed. 
*/ 

Dimension w_temp_cell_size_in_pixels, 

h_t emp_c e 1 l_s i z e_i n_p i xe 1 s ; 
Dimension new_cell_size_in_pixels; 

w_temp_cell_size_in_pixels = cw->core .width / 
cw->bitmapEdit . pixmap_width_in_cells; 

h_temp_cell_size_in_pixels = cw->core .height / 
cw->bitmapEdit . pixmap_height_in_cells; 

if (w_temp_cell_size_in_pixels < 

h_temp_cell_size_in_pixels) 
new_cell_size_in_pixels = 

w_temp_cell_size_in_pixels; 
else 

new_cell_size__in_pixels = 

h_temp_cell_size_in_pixels; 

/* if size change mandates a new pixmap, make one */ 
if (new_cell_size_in_pixels != cw-> 

bitmapEdit . cell_size_in_pixels) { 
ChangeCellSize (cw, new_cell_size_in_pixels) ; 

} 



static void 

ChangeCellSize (cw, new_cell_size) 

BitmapEditWidget cw; 

int new_cell_size; 

{ 

int x, y; 

cw->bitmapEdit .cell_size_in_pixels = new_cell_size; 

/* recalculate variables based on cell size */ 

cw->bitmapEdit .pixmap_width_in_jpixels = 

cw->bitmapEdit .pixmap_width_in_cells * 
cw->bitmapEdit . cell_size_in_pixels; 

cw->bitmapEdit .pixmap_height_in_pixels = 

cw->bitmapEdit .pixmap_height_in_cells * 
cw->bitmapEdit . cell_size_in_pixels; 

/* destroy old and create new pixmap of correct size */ 
XFreePixmap (XtDisplay (cw) , cw->bitmapEdit .big_picture) ; 
CreateBigPixmap (cw) ; 

/* draw lines into new pixmap */ 
DrawIntoBigPixmap (cw) ; 

/* draw current cell array into pixmap */ 



X Toolkit Intrinsics Programming Manual 



Example 6-5. BitmapEdit: the resize method (continued) 

for (x = 0; x < cw-> 

bitmapEdit .pixmap_width_in_cells; x++) { 
for (y = 0; y < cw-> 

bitmapEdit .pixmap_height_in_cells; y++) { 
if (cw->bitmapEdit .cell [x + 

(y * cw->bitmapEdit .pixmap_width_in_cells) ] == DRAWN) 

DoCell(cw, x, y, cw->bitmapEdit .draw_gc) ; 
else 

DoCelKcw, x, y, cw->bitmapEdit .undraw_gc) ; 



static void 

DoCell (w, x, y, gc) 

BitmapEditWidget w; 

int x, y; 

GC gc; 

{ 

/* draw or undraw a cell */ 

XFillRectangle (XtDisplay (w) , w->bitmapEdit .bigjpicture, gc, 
w->bitmapEdit .cell_size_in_pixels * x + 2, 
w->bitmapEdit .cell_size_in_pixels * y + 2, 
(unsigned int) w->bitmapEdit . cell_size_in_pixels - 3, 
(unsigned int) w->bitmapEdit . cell_size_in_pixels - 3) 



Because of the two-phase resize strategy used by BitmapEdit, and because BitmapEdit uses a 
pixmap in its repaint strategy, this resize method is more complicated than most. When 
the widget is resized larger that necessary to show the entire bitmap in the current 
cell_size, it destroys the current pixmap and creates a new one. Since this should not 
happen very often and because resizing does not require extremely fast response, the time it 
takes to recreate the pixmap and draw into it is acceptable. 

One difficulty in writing the resize method is that you do not have access to the old size or 
position of the window. The widget instance structure passed in has already been updated 
with the current size and position. If you need the old information, you can cache the old 
size in an instance part field, set first in the initialize method, and again at the end of 
the resize method. 

It is also important to note that the resize method is not allowed to request that the parent 
resize the widget again to get a better size. (How to suggest properly to the parent that your 
widget be resized is described in Chapter 11, Geometry Management.) 

In the set_values method shown in Section 6.4, changes to BitmapEdit s xtNcell- 
SizelnPixels resource were not allowed. Now that we have a working ChangeCell- 
Size function, a small change to the code that handles cell size changes in set_values 
will allow the cell size to be changed at any time. The new code is shown in Example 6-6. 



Basic Widget Methods 179 



Example 6-6. BftmapEdit: modification to set_values method to support changing cell size 

if (curcw->bitmapEdit .cell_size_in_pixels != 
newcw->bitmapEdit . cell_size_in_pixels) { 

ChangeCellSize (curcw, newcw->bitmapEdit .cell_size_in_pixels) ; 
do_redisplay = TRUE; 



6.6 The query_geometry Method 

When your widget is used in an application, its parent widget will be a composite or con 
straint widget that manages its size and position. Parent widgets need to know the preferred 
size of a widget so they can make good decisions about the size of each child. The 
query_geometry method is called when the parent is about to make a size change to 
some of its children but is not yet sure which ones and by how much. (How geometry man 
agement works is described in Chapter 11, Geometry Management. For now, we are concen 
trating on what you need to do to write a simple widget.) 

If your widget specifies NULL in the class structure for the query_geomet ry method, the 
parent will be told that your widget s current geometry is its preferred geometry. This is 
often wrong information. For example, if your widget has already been resized to be one- 
pixel-by-one-pixel because the user has resized an application to be very small, the parent 
would receive the message that your widget prefers to be that small. When the application is 
resized to be larger again, the parent will have no information on which to base its resizing 
decisions. Even if your widget has no particular preference for size, it is a good idea to spec 
ify the widget s default size in query_geometry. Then, at least, the parent has a ballpark 
figure for typical sizes for your widget. The parent could at least find out that BitmapEdit is 
intended to be larger than a Label widget. 

The query_geometry method is passed pointers to two copies of the XtWidget- 
Geometry structure, one containing the parent s intended size for your widget, and the 
other to contain your reply to the parent s suggestion. The xt widget Geometry structure 
is shown in Example 6-7. 

5s;;?s 

Example 6-7. The XtWidgetGeometry structure 

typedef struct { 

XtGeometryMask request_mode; 

Position x, y; 

Dimension width, height; 

Dimension border_width; 

Widget sibling; 

int stack_mode; 
} XtWidgetGeometry; 

The request_mode field is a mask that indicates which other fields in the structure are set 
It is a bitwise OR of any or all of the symbolic constants shown in Table 6- 1 . 



180 X Toolkit Intrinsics Programming Manual 



Table 6-1. XtWidgetGeometry request_mode Symbols 



Symbol 



Description 



cwx 
CWY 

CWWidth 
CWHeight 
CWBorderWidth 
CWSibling 

CWStackMode 



The x coordinate of the widget s top left corner is specified 

The y coordinate of the widget s top left corner is specified 

The widget s width is specified 

The widget s height is specified 

The widget s borderwidth is specified 

A sibling widget is specified, relative to which this widget s stacking 

order should be determined 

A stack_mode value is present, specifying how this widget should 

be stacked relative to the widget identified as sibling 



The sibling and stack_mode fields are used together to indicate where in the stacking 
order of its siblings your widget will be placed. The symbols for stack_mode are Above 
Below, Toplf , Bottomlf , Opposite, and XtSMDontChange. (These symbols are 
used singly, not combined with OR.) Their meanings are summarized in Table 6-2. 

Table 6-2. XtWidgetGeometry stack_mode Symbols 



Stacking Flag 



Position 



Above 



Below 



Toplf 



Bottomlf 



Opposite 



XtSMDontChange 



vr is placed just above sibling. If no sibling is specified, w is 
placed at the top of the stack. 

w is placed just below sibling. If no sibling is specified, w is 
placed at the bottom of the stack. 

If sibling obscures w, then w is placed at the top of the stack. If no 
sibling is specified, then if any sibling obscures w, w is placed at 
the top of the stack. 

If w obscures sibling, then w is placed at the bottom of the stack. If 
no sibling is specified, then if w obscures any sibling, wis placed at 
the bottom of the stack. 

If sibling occludes w, w is placed at the top of the stack. If w 
occludes sibling, w is placed at the bottom of the stack. If no 
sibling is specified, then if any sibling occludes w, w is placed at 
the top of the stack, or if w occludes any sibling, w is placed at the bot 
tom of the stack. 

Current position in stacking order is maintained. 



Note that Xt s handling of stacking order is currently imcomplete, and these symbols might 
not be honored. 



Basic Widget Methods 



One more issue about the query_geometry method must be raised before showing an 
example; the method s return value. The query_geometry method must return one of 
the three enum values Xt Geometry Yes, XtGeometryAlmost, or XtGeometryNo. 
xtGeometryResult is an enum name, and it is the returned type of 
query_geometry. 

If the proposed geometry is acceptable without modification, query_geometry 
returns Xt Geometry Yes. 

If the proposed geometry is not acceptable, your widget returns XtGeometryAlmost 
and sets its suggested changes to the proposed geometry back in the reply structure. 

If the proposed geometry is the same as the current geometry, query_geometry 
returns XtGeometryNo. This symbol is slightly misleading think of it as xt- 
GeometryNoChange (a symbol that is not defined). The symbol is XtGeometryNo 
because all three of these symbols are used in another context within composite and con 
straint widgets, as is described in Chapter 11, Geometry Management. 

Note that, in all three cases, query_geometry must set any fields in the reply structure 
that it potentially cares about, even if it is only accepting the proposed geometry. 

Example 6-8 shows the query_geometry method from BitmapEdit. All widgets should 
have at least this code in the method, substituting their initial size, or their current preferred 
size if known. (For example, a Label widget would set its preferred size based on the width 
and height of the current string.) 

Example 6-8. BitmapEdit: the query_geometry method 

static XtGeometryResult QueryGeometry (w, proposed, answer) 
BitmapEditWidget w; 

XtWidgetGeometry *proposed, *answer; 
{ 

answer->request_mode = CWWidth | CWHeight; 

/* initial width and height */ 

answer->width = (w->bitmapEdit . pixmap_width_in_pixels > 300) 

? 300 : w->bitmapEdit .pixmap_width_in_pixels; 
answer->height = (w->bitmapEdit .pixmap_height_in_pixels > 300) 

? 300 : w->bitmapEdit .pixmap_height_in_pixels; 

if ( ( (proposed->request_mode & (CWWidth | CWHeight)) 
== (CWWidth | CWHeight)) && 
proposed->width == answer->width && 
proposed->height == answer->height ) 
return XtGeometryYes; 
else if (answer->width == w->core .width && 

answer->height == w->core .height) 
return XtGeometryNo; 
else 

return XtGeometryAlmost; 



182 X Toolkit Intrinsics Programming Manual 



6.7 The destroy Method 

When a widget is destroyed by the application, its destroy methods are invoked in sub 
class to superclass order. Therefore, the destroy method for any given class need free 
only memory allocated by itself; it need not worry about memory allocated by superclasses. 

Any server resources created by Xt (such as GCs requested through xtGetGC) should be 
freed in the destroy method. In addition, if you called any Xlib routines, such as 
XCreateGC, that allocate server- or client-side resources, be sure to free them here. 
BitmapEdit creates pixmaps for use in the drawing process, so it must free them. It must also 
free the GCs it allocated with XCreateGC. 

If this is not done, then the server resources allocated for the widget will not be freed until 
the application exits. This is not a fatal problem. It matters only in applications that destroy 
widgets and then continue running for a while before they exit, which is unusual. Example 
6-9 shows the destroy method code from the BitmapEdit widget. It frees the pixmaps 
created in the initialize method shown in Example 6-1 above. 

Example 6-9. The destroy method 

static void 
Destroy (cw) 
BitmapEditWidget cw; 

{ 

if (cw->bitmapEdit .big_picture) 

XFreePixmap (XtDisplay (cw) , cw->bitmapEdit .big_picture) ; 

if (cw->bitmapEdit .draw_gc) 

XFreeGC (XtDisplay (cw) , cw->bitmapEdit .draw_gc) ; 

if (cw->bitmapEdit .undraw_gc) 

XFreeGC (XtDisplay (cw) , cw->bitmapEdit .undraw_gc) ; 

if (cw->bitmapEdit .copy_gc) 

XtReleaseGC (cw, cw->bitmapEdit .copy_gc) ; 

/* This memory allocated with XtCalloc in initialize method */ 
XtFree (cw->bitmapEdit .cell) ; 

11 } 

If your widget allocated memory for any of its instance variables (or other global variables) 
using the Toolkit routines xtMalloc or XtCalloc (which operate just like the C library 
but add error checking), then it should free that memory here with XtFree. 

If your widget called xtAddE vent Handler or xtAddTimeOut, then you should call 
XtRemoveEventHandler and XtRemoveTimeOut, respectively (here these routines 
are described in Chapter 8, More Input Techniques). 



Basic Widget Methods 183 



6.8 Actions in the Widget Framework 

Although actions, strictly speaking, are not methods, writing them is part of the process of 
writing a simple widget Fortunately, you have already seen action routines added from the 
application. Action routines look and work the same in the widget framework as in the appli 
cation, except that they use instance structure fields as data instead of the application data 
structure fields. Example 6-10 shows the actions of BitmapEdit. 

Example 6-10. BitmapEdit: action routines 

static void 
DrawCell (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 

DrawPixmaps (w->bitmapEdit .draw_gc, DRAW, w, event); 

static void 
UndrawCell (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 

DrawPixmaps (w->bitmapEdit .undraw_gc, UNDRAW, w, event); 

static void 
ToggleCell (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 

static int oldx = -1, oldy = -1; 

GC gc ; 

int mode; 

int newx, newy; 

if (event->type != ButtonPress) 

tXtWarning ("BitmapEdit: ToggleCell action invoked\ 
by wrong event type."); 

newx = (w->bitmapEdit .cur_x + event->x) / 

w->bitmapEdit . cell_size; 
newy = (w->bitmapEdit .cur_y + event->y) / 

w->bitmapEdit ,cell_size; 

if ((mode - w->bitmapEdit .cell [newx + newy * w-> 

bitmapEdit.pixmap_width_in_cells] ) == DRAWN) { 
gc = w->bitmapEdit .undraw_gc; 
mode = UNDRAW; 

else { 

gc = w->bitmapEdit .draw_gc; 
mode = DRAW; 

if (oldx != newx | | oldy != newy) { 
oldx = newx; 
oldy = newy; 



184 X Toolkit Intrinsics Programming Manual 



Example 6-10. BitmapEdit: action routines (continued) 

DrawPixmaps (gc, mode, w, event); 



static void 

DrawPixmaps (gc, mode, w, event) 

GC gc ; 

int mode; 

BitmapEditWidget w; 

XButtonEvent *event; 

int newx = (w->bitmapEdit .cur_x + event->x) / 

w->bitmapEdit .cell_size; 
int newy = (w->bitmapEdit .cur_y + event->y) / 

w->bitmapEdit .cell_size; 

XExposeEvent fake event; 



/* if already done, return */ 
if (w->bitmapEdit .cell [newx + newy * 

w->bitmapEdit .pixmap_width_in_cells] == mode) 
return; 

/* otherwise, draw or undraw */ 

XFillRectangle (XtDisplay (w) , w->bitmapEdit .big_picture, gc, 
w->bitmapEdit .cell_size*newx + 2, 
w->bitmapEdit .cell_size*newy + 2, 
(unsigned int) w->bitmapEdit . cell_size - 3, 
(unsigned int) w->bitmapEdit .cell_size - 3) ; 

w->bitmapEdit .cell [newx + newy * 

w->bitmapEdit .pixmap_width_in_cells] = mode; 
info. mode = mode; 
info. newx = newx; 
info. newy = newy; 

fake_event.x = w->bitmapEdit .cell_size * newx 

- w->bitmapEdit . cur_x; 
fake_event.y = w->bitmapEdit . cell_size * newy 

- w->bitmapEdit . cur_y; 

fake_event .width = w->bitmapEdit .cell_size; 
fake_event .height = w->bitmapEdit .cell_size; 

Redisplay (w, &fake_event) ; 
XtCallCallbacks(w, XtNcallback, sinfo) ; 

Notice that as in methods, the widget instance pointer passed in is cast to the desired type by 
declaring the argument as type BitmapEditWidget. In other widgets you will also see 
the argument declared as type widget, and then, in the first line of the action, cast to the 
desired type. 



Basic Widget Methods 185 



An action routine in widget code can set and read fields in the widget instance structure 
passed in, while an action added from the application can access its own application data 
structure but not the widget s internal data structure because of the encapsulation rule (see 
Section 2.1.6.3). This is one of the advantages of moving this code into a widget. 

You should now be ready to go back to the end of Chapter 5, Inside a Widget, and follow the 
directions to write your first widget You will need to review parts of both Chapter 5 and this 
chapter as the process of actually writing a widget raises new questions. 



186 X Toolkit Intrinsics Programming Manual 



7 



Events, Translations, and Accelerators 



This chapter describes the complete syntax of translation tables, and 
describes a mechanism called accelerators for mapping events in one widget 
to actions in another. 



In This Chapter: 

Translation Table Syntax 190 

The Directive 191 

Selecting the Events to Translate 191 

Details in Keyboard Events 194 

Details in Other Event Types 195 

Modifiers 196 

Physical Keys Used as Modifiers 197 

Default Interpretation of the Modifier List 198 

Prohibiting a Modifier 199 

Requiring an Exact Match 200 

Paying Attention to the Case of Keysyms 200 

Event Sequences 201 

Special Considerations Involving Motion Events 202 

Modifiers and Event Sequences 202 

Using Modifiers to Specify Button Event Sequences 202 

Key Event Sequences 203 

Interactions Between Translations 203 

Order of Translations 203 

Event Sequences Sharing Initial Events 204 

Event Sequences Sharing Noninitial Events 204 

Accelerators 205 

Event Propagation 207 

Installing Accelerators in Multiple Widgets 209 

Defining the Accelerator Table in the Code 210 

The display_accelerators Method 21 1 



7 

Events, Translations, 
and Accelerators 



Events drive the application. They send a great variety of information from the server to the 
client, and from the user to the application. More knowledge of events is necessary both to 
use existing widgets successfully in large applications and to write widgets. 

Events are sufficiently central to X that we ve devoted two chapters in this book to them. 
This chapter provides a closer look at translations and actions; Chapter 8 looks at lower-level 
event handlers, as well as at other sources of input. 

The basic concept and use of translations and actions has already been described. But trans 
lation tables have a complicated syntax which can be used to do much more than the simple 
mappings you have seen up to now. Translation tables can detect user-interface idioms such 
as double- and triple-button clicks or key combinations such as Shift-Meta-M. This chapter 
focuses on the more advanced features of translation tables. 

Next, we discuss a variation of translations called accelerators. Accelerators, which were 
introduced in Release 3, bind events that occur in one widget to actions in another. This is a 
flexible feature with many uses. One common use is to supply a keyboard interface to a nor 
mally pointer-driven application. By adding accelerators to the top-level window of the 
application, a keyboard event typed with the pointer anywhere in the application can be 
translated into an action in the correct widget The name "accelerator" comes from the fact 
that many advanced users find it faster to use keyboard shortcuts instead of menus. 

As mentioned in Chapter 3, More Widget Programming Techniques, it is a very good idea to 
specify translation tables (and accelerator tables, too) in the application-defaults file instead 
of hardcoding them in the application, especially while an application is under development. 
This lets you develop the translations and accelerators without recompiling the application 
every time you want to make a change. 




Events, Translations, and Accelerators 189 



7.1 Translation Table Syntax 

If you are reading this book in sequence, you ve already seen translations used many times. 
However, we haven t given a formal description of their syntax or a complete listing of the 
events you can translate. 

A translation table consists of an optional directive, which specifies how the table should be 
merged with any other existing translation tables, followed by a series of production rules, of 
the form: 

[ modifier _list] <event> [ , <event> ... ] [ (count) ] [detail] : action ( [arguments] ) [ action... ] 

where brackets ([ ]) indicate optional elements, an ellipsis (...) indicates repetition, and 
italics indicate substitution of an actual modifier, event, detail, or action name. 

At a minimum, a translation must specify at least one event, specified by a predefined event 
name or abbreviation enclosed in angle brackets; a colon separator; and at least one action. 
However, a sequence of events can be specified; likewise, more than one action can be 
invoked as a result. The scope of event matching can be limited by one or more optional 
modifiers, and in the case of some events, by a "detail" field that specifies additional informa 
tion about the event (For example, for key events, the detail field specifies which key has 
been pressed.) Repeated occurrences of the same event (e.g., a double-click) can be specified 
by a count value in parentheses. A colon and optional white space separates the translation 
and the action. 

The examples below are all valid translations: 

<Enter>: doit() invoke doit() on an EnterWindow event 

<BtnlDown>, <BtnlUp>: doit() invoke doit() on a click of Button 1 

<BtnlUp>(2): doit() invoke doit() on a double-click of Button 1 

Buttonl<Btn2Down>, <Btn2Up> : doit ( ) 

invoke doit() on a click of Button 2 
while Button 1 is held down 
Shi f t <BtnDown> : doit ( ) invoke doit() on a click of any button while 

the shift key is held down 
<Key>y : doit ( ) invoke doit() when the y key is pressed 

A translation table is a single string, even when composed of multiple translations. If a trans 
lation table consists of more than one translation, the actual newlines are escaped with a 
backslash (except for the last one), and character newlines are inserted with the \n escape 
sequence, as you ve seen demonstrated in examples throughout this book. 

The following sections provide additional detail on each of the elements of an event transla 
tion. We ll talk first about the directive, followed by event specifiers, details, modifiers, and 
counts. We ll also provide some pointers on the proper sequence of translations, and discuss 
what happens when translations overlap. 



190 X Toolkit Intrinsics Programming Manual 



7.1.1 The Directive 

As we ve already seen, the three possible directives are treplace, #override, or 
^augment. 

# replace says to completely replace the value of the translations resource in the 
widget If no directive is specified, # replace is the default. 

The difference between ^override and #augment is more subtle. They differ in how 
they treat event combinations in the new translation that also appear in the old. With 
#override, the new translation takes priority, while with #augment, the old one does. 

For example, say a widget has a default translation table that includes a translation for the 
Return key, and an application that uses this widget has an application-defaults file consisting 
of a translation table that applies to this widget If the translation table in the application- 
defaults file began with #override, any translation for the Return key would take priority 
over the default translation for the Return key. On the other hand, if the translation table in 
the application-defaults file began with #augment, the default translations would take pri 
ority. 

Remember that the difference between ^augment and #override is only in the treat 
ment of overlapping translations. Any translations added with either directive for events that 
do not akeady appear in the existing translation table will always be added. 

Because of potential overlap between translations, when you are debugging your intended 
translations it is best to use #replace at first, then test with #augment or ^override 
as appropriate once you are sure that the translations themselves have the desired effect. 

7.1.2 Selecting the Events to Translate 

An X event is a packet of data sent by the server to a client in response to user behavior or to 
window system changes resulting from interactions between windows. There are 33 different 
types of events defined by X. Most (though not all*) events can be thought of as occurring in 
a window: the pointer entering or leaving a window, pointer motion within a window, 
pointer button presses, key presses, and so on. However, most events are not sent to a win 
dow unless the window has explicitly selected that event type; events are selected on a per- 
window basis. In Xlib programming, events are selected by specifying an event mask as a 
window attribute. Some events, which are sent to all windows regardless of whether a win 
dow has selected them or not are called non-maskable events. One of the most complex 
aspects of Xlib programming is designing the event loop, which must take into account all of 
the possible events that can occur in a window. 

Xt s translation manager selects the events that are specified in the current translation table 
for each widget In translations, events can be specified either by their actual names, as 
shown in column 1 of Table 7-1, or by means of the abbreviations shown in column 2. A 



"Others reflect internal changes in the window system not related to any window. For example, a KeymapNot i f y 
event occurs in response to a change in the mappings of keysyms (portable key symbols) to keycodes (actual codes 
generated by physical keys). 



Events, Translations, and Accelerators 



191 



complete reference to each event type is provided in Appendix C, Event Reference, in Vol 
ume Five, X Toolkit Intrinsic* Reference Manual. 

Table 7-1. Event Type Abbreviations in Translation Tables 



Event Type 


Abbreviations 


Description 


ButtonPress 


BtnDown 


Any pointer button pressed 




BtnlDown 


Pointer button 1 pressed 




Btn2Down 


Pointer button 2 pressed 




BtnSDown 


Pointer button 3 pressed 




Btn4Down 


Pointer button 4 pressed 




BtnSDown 


Pointer button 5 pressed 


But tonRe lease 


BtnUp 


Any pointer button released 




BtnlUp 


Pointer button 1 released 




Btn2Up 


Pointer button 2 released 




Btn3Up 


Pointer button 3 released 




Btn4Up 


Pointer button 4 released 




Btn5Up 


Pointer button 5 released 


KeyPress 


Key 


Key pressed 




KeyDown 


Key pressed 




Ctrl 


KeyPress with Ctrl modifier 




Meta 


KeyPress with Meta modifier 




Shift 


KeyPress with Shift modifier 


KeyRelease 


KeyUp 


Key released 


MotionNotify 


Motion 


Pointer moved 




PtrMoved 


Pointer moved 




MouseMoved 


Pointer moved 




BtnMotion 


Pointer moved with any button held down 




BtnlMotion 


Pointer moved with button 1 held down 




Btn2Motion 


Pointer moved with button 2 held down 




BtnSMotion 


Pointer moved with button 3 held down 




Btn4Motion 


Pointer moved with button 4 held down 




BtnSMotion 


Pointer moved with button 5 held down 


EnterNotify 


Enter 


Pointer entered window 




EnterWindow 


Pointer entered window 


LeaveNotify 


Leave 


Pointer left window 




LeaveWindow 


Pointer left window 


Focusln 


Focusln 


This window is now keyboard focus 


FocusOut 


FocusOut 


This window lost keyboard focus 


KeymapNot i f y 


Keymap 


Keyboard mappings changed 


Expose 


Expose 


Part of window needs redrawing 


GraphicsExpose 


GrExp 


Source of copy unavailable 


NoExpose 


NoExp 


Source of copy available 


ColormapNotify 


Clrmap 


Window s colormap changed 


PropertyNotify 


Prop 


Property value changed 


VisibilityNotify 


Visible 


Window has been obscured 


ResizeRequest 


ResReq 


Redirect resize request to window manager 



192 



X Toolkit Intrinsics Programming Manual 



Table 7-1. Event Type Abbreviations in Translation Tables (continued) 



Event Type 


Abbreviations 


Description 


CirculateNotify 


Circ 


Stacking order modified 


Conf igureNotify 


Configure 


Window resized or moved 


DestroyNotify 


Destroy 


Window destroyed 


GravityNotify 


Grav 


Window moved due to win gravity attribute 


MapNotify 


Map 


Window mapped 


Great eNot if y 


Create 


Window created 


ReparentNotify 


Reparent 


Window reparented 


UnmapNotify 


Unmap 


Window unmapped 


CirculateRequest 


CircRec 


Redirect stacking order change to window manager 


ConfigureRequest 


ConfigureReq 


Redirect move or resize request to window manager 


MapRequest 


MapReq 


Redirect window map request to window manager 


MappingNotify 


Mapping 


Keyboard mapping changed 


ClientMessage 


Message 


Client-dependent 


Select ionClear 


SelClr 


Current owner is losing selection 


SelectionNotify 


Select 


Selection is ready for requestor 


Select ionRequest 


SelReq 


Request for selection to current owner 



Many of these events are handled automatically by the Toolkit separately from the translation 
mechanism. For example, Expose events are automatically sent to the expose method of 
the appropriate widget* When there is also a translation for Expose events, the action is 
called in addition to the expose method. The only reason you would need a translation for 
Expose events is to add drawing to a Core widget Since the Core widget doesn t have an 
expose method, there is rarely if ever a case where there is both an expose method and a 
translation for Expose events for the same widget The point to remember is that any event 
can be specified in a translation, even when that event is also used in some other way by Xt. 

Several of the *Notif y events are automatically handled by the Toolkit Xt places this 
information in internal structures so that it can satisfy queries for widget positions and 
geometries without querying the server. MappingNotify events are automatically han 
dled; Xt gets the current keyboard mapping from the server. visibilityNotif y events 
are handled automatically if the visible_interest field in the Core structure is set to 
TRUE (see Section 8.4.1). 

With the exception of Select ionRequest, the *Request events are intended for use 
only by window managers. The selection events are described in Chapter 10, Inter-Client 
Communications . 




GraphicsExpose and NoExpose events are not handled automatically by XL If you are writing a widget, you 
must explicitly select GraphicsExpose and NoExpose events by setting the graphics_exposures GC 
component in a GC. These events are useful when your application copies from a visible window with XCopyArea 
or XCopyP 1 ane. They notify the application when part of the source of the copy is obscured. (While xbitmap and 
BitmapEdit use XCopyArea and XCopyP lane, they copy from an off-screen pixmap that cannot be obscured, 
and therefore GraphicsExpose and NoExpose events are not needed. For a description of these events, see 
Chapter 5, The Graphics Context, in Volume One, Xlib Programming Manual.) 



Events, Translations, and Accelerators 



193 



Whether or not they are already handled by Xt or in translations, events can also be selected 
explicitly by installing event handlers in a widget (as described in Chapter 8, More Input 
Techniques). 

7.1.3 Details in Keyboard Events 

As you ve seen, Xt provides special event abbreviations to specify which pointer button was 
pressed or released. With key events, this approach would be a little impractical, since there 
are so many keys. Instead, the Translation Manager allows you to follow the event specifica 
tion with an optional detail field. That is: 

<Key>: doit() 

means that you want the doit () action to be invoked when any key has been pressed, 
while: 

<Key>y: doit() 

means that you want the doit ( ) action to be invoked only if the y key has been pressed. 

What you actually specify as the detail field of a Key event is a keysym, as defined in the 
header file <Xlllkeysymdef.h>* Keysyms begin with an XK_ prefix, which is omitted when 
they are used in translations. 

Before we explain any further, we need to review X s keyboard model, which, like many 
things in X, is complicated by the design goal of allowing applications to run equally well on 
machines with very different hardware. 

The keyboard generates KeyPress events, and may or may not also generate Key- 
Release events. These events contain a server-dependent code that describes the key 
pressed, called a keycode. Modifier keys, such as Shift and Control, generate events just like 
every other key. In addition, all key events also contain information about which modifier 
keys and pointer buttons were held down at the time the event occurred. 

Xt provides a routine that translates keycode and modifier key information from an event into 
a portable symbolic constant called a keysym. A keysym represents the meaning of the key 
pressed, which is usually the symbol that appears on the cap of the key. For example, when 
the a key is pressed, the keysym is XK_a; when the same key is pressed while the Shift key is 
held down, the resulting keysym is XK_A (upper case). Note that even though both the a and 
the A events have the same keycode, they generate a different keysym because they occurred 
with different modifier keys engaged. (The mapping between keycodes and keysyms is dis 
cussed further in Section 13.4.) 

You may specify either the keysym name, omitting the XK_ prefix, or its hexadecimal value 
(also shown in <Xlllkeysymdef.h>), prefixed by Ox or Ox (zero followed by x orX). 



*Note, however, that this file includes foreign language keysym sets that are not always available. Only the MIS 
CELLANY, LATTN1 through LATTN4, and GREEK sets are always available. 



194 X Toolkit Intrinsics Programming Manual 



This is fairly straightforward, though there are several provisos: 

The keysym for nonalphanumeric keyboard keys may not always be obvious; you will 
need to look in <Xlllkeysymdef.h>. For example, the keyboard for the Sun workstation 
has keys labeled "Left" and "Right" Their keysyms are XK_Meta_L and 
XK_Meta_R, respectively. Fortunately, most common named keys have mnemonic 
keysym names (XK_Return, XK_Linefeed, XK_BackSpace, XK_Tab, 
XK_Delete, and so on) so you can often get by without looking them up. Notice, 
though, the small things that can trip you up: Backspace, not Backspace, but Linefeed, 
not LineFeed. You can t count on consistency. 

The definitions in <Xlllkeysymdef.h> spell out keysym names for punctuation and other 
special characters. For example, you ll see XK_question rather than XK_?, and so 
on. Nonetheless, you need not use this long keysym name; the Translation Manager will 
accept the equivalent single character, as long as it is a printing character. This is also 
true of digits. There are a few exceptions, namely the characters that have special mean 
ing in a translation table. If you ever need a translation for colon, comma, angle brackets, 
or backslash, you ll have to use the keysym name rather than the single printing charac 
ter. 

The keycode-to-keysym translator built into the Translation Manager makes case distinc 
tions only if the key event is prefaced with the colon (:) modifier. This means that 
<Key>a and <Key>A will be treated identically by default. We ll return to this subject 
when we discuss modifiers. 

In sum, the following are all valid key event translations: 

<Key>q : quit ( ) invoke quit() when q or Q is pressed 

: <Key > ? : he lp ( ) invoke help() when 1 (but not / ) is pressed 

<Key>Return : newline ( ) invoke newline() when the Return key is pressed 

<Key>: insert_char () invoke insert_char() when any key is pressed 



7.1.4 Details in Other Event Types 

Key events are the most likely to require details, but they are also available for several other 
event types. 

Trivially, the detail values Buttonl through Buttons can be supplied as details for 
ButtonPress or But tonRe lease events; because of the available abbreviations, 
though, these should not often be necessary. It is easier to say: 

<BtnlDown>: quit() 

than: 

<BtnDown>Buttonl : quit() 

The EnterNotify, LeaveNotify, Focus In, and FocusOut events can take as 
details any of the notify mode values shown in Table 7-2. 




Events, Translations, and Accelerators 195 



Table 7-2. Notify Mode Values for Enter, Leave, and Focus Events 



Detail 



Description 



Normal 

Grab 

Ungrab 



Event occurred as a result of a normal window crossing 
Event occurred as a result of a grab 
Event occurred when a grab was released 



Normally, EnterNotify and LeaveNotify events are generated when the pointer 
enters or leaves a window. Focus In and FocusOut events are generated when a window 
gains or loses the keyboard focus. When this occurs depends on the style of window man 
ager being used. With a "real-estate-driven" window manager like uwm, the keyboard focus 
automatically follows the pointer, so Focus In and FocusOut events will occur at the 
same time as EnterNotify and LeaveNotify events. Other window managers, such 
as the Motif window manager, mwm, support a "click-to-type" style of interaction similar to 
that used by the Macintosh. The user clicks in a window to give it the keyboard focus. 
Thereafter, keyboard events are sent to that window regardless of the pointer position. A 
grab, which is usually implemented by a pop-up window or a window manager, has a similar 
effect, causing keyboard and/or pointer input to be constrained to a particular window. 

The detail values for these event types correspond to the mode member of the appropriate 
event structures. See Appendix C, Event Reference, in Volume Five, X Toolkit Intrinsics Ref 
erence Manual, for more details. 

Details for additional events are being added in Release 4. 



7.1.5 Modifiers 



Certain events include as part of their data the state of the pointer buttons and special key 
board modifier keys at the time the event was generated. The events for which this state is 
available include ButtonPress, ButtonRelease, MotionNotify, KeyPress, 
KeyRelease, EnterNotify, and LeaveNotify. 

For these events, you can specify a desired modifier state using one or more of the modifier 
keywords listed in Table 7-3. An error is generated if you specify modifiers with any other 
types of events. 

Table 7-3. Modifiers Used in Translation Tables 



Modifier 


Abbreviation* 


Description 


Ctrl 


c 


Control key is held down 


Shift 


s 


Shift key is held down 


Lock 


1 


Caps Lock is in effect 


Meta 


m 


Meta key is held down 


Hyper 


h 


Hyper key is held down 


Super 


su 


Super key is held down 



196 



X Toolkit Intrinsics Programming Manual 



Table 7-3. Modifiers Used in Translation Tables (continued) 



Modifier 



Abbreviation* 



Description 



Alt 

Modi 

Mod2 

Mod3 

Mod4 

Mod5 

Buttonl 

Button2 

Buttons 

Button4 

Button5 



Alt key is held down 
Modi key is held down 
Mod2 key is held down 
Mod3 key is held down 
Mod4 key is held down 
Mod5 key is held down 
Pointer Button 1 is held down 
Pointer Button 2 is held down 
Pointer Button 3 is held down 
Pointer Button 4 is held down 
Pointer Button 5 is held down 



7.1 .5.1 Physical Keys Used as Modifiers 

The meaning of the Meta, Hyper, Super, Alt, and Modi through Mod5 keywords may 
differ from server to server. Not every keyboard has keys by these names, and even if 
keysyms are defined for them in <Xlllkeysymdef.h>, they may not be available on the physi 
cal keyboard.! 

For example, the file <Xlllkeysymdef.h> includes the following definitions: 

/* Modifiers */ 



#define XK_Shift_L 
tdef ine XK_Shift_R 
#define XK_Control_L 
#define XK_Control_R 
fdefine XK_Caps_Lock 
#define XK Shift Lock 



#def ine 
#define 
#def ine 
#define 
tdef ine 
tdef ine 
#define 
#def ine 



XK_Meta_L 

XK_Meta_R 

XK_Alt_L 

XK_Alt_R 

XK_Super_L 

XK_Super_R 

XK_Hyper_L 

XK_Hyper_R 



OxFFEl /* Left shift */ 

OxFFE2 /* Right shift */ 

OxFFE3 /* Left control */ 

OxFFE4 /* Right control */ 

OxFFES /* Caps lock */ 

OxFFE6 /* Shift lock */ 

OxFFE7 /* Left meta */ 

OxFFES /* Right meta */ 

OxFFE9 /* Left alt */ 

OxFFEA /* Right alt */ 

OxFFEB /* Left super */ 

OxFFEC /* Right super */ 

OxFFED /* Left hyper */ 

OxFFEE /* Right hyper */ 




"Though these abbreviations are defined in the Translation Manager specification, and may be implemented by some 
vendors, they don t work in MIT s sample implementation, and thus probably aren t present in others as well. This 
may change in Release 4. 

fThe contents of <Xll/keysymdef.h> are the same on every machine. What is different is the default mapping of 
keysyms to physical keycodes, which occurs in the server source. The only way to find out the mappings is through 
documentation (which is usually not available) or experimentation (as described in Chapter 1 1 of Volume Three, X 
Window System User s Guide, Second Edition). 



Events, Translations, and Accelerators 



197 



There are two things you must learn before you can use these modifiers: 

1. Which physical key generates a given keysym, if it is not obvious from the name. 

2. Which modifiers are valid on your server. 

The best way to find out what keysym a key generates is with the xev client, which prints 
detailed information about every event happening in its window. To find out a keysym, run 
xev, move the pointer into its window, and then press the key in question. 

On the Sun-3, there is only one control key, on the left side of the keyboard. It generates the 
keysym XK_Control_L. There are two shift keys, one on each side, which generate the 
keysyms XK_Shift_L and XK_Shift_R. The Meta modifier is mapped to the keys 
labeled "Left" and "Right" Even though there is an Alternate keyboard key, which gener 
ates the keysym XK_Alt_R, this key is not recognized as a modifier. There are no Super 
and Hyper keys. 

The list of valid modifiers can be displayed with the xmodmap client, as follows: 

isla% xmodmap 

xmodmap: up to 2 keys per modifier, (keycodes in parentheses) : 

shift Shift_L (Ox6a) , Shift_R (0x75) 

lock Caps_Lock (Ox7e) 

control Control_L (0x53) 

modi Meta_L (Ox7f ) , Meta_R (0x81) 

mod2 

mod3 

mod4 

mod5 

That is, either of the two shift keys will be recognized as the Shift modifier, the Caps Lock 
key as the Lock modifier, and either the Left or Right keys as the Meta modifier. The Left 
and Right keys are also mapped to the Modi modifier. The Alt key is not recognized as a 
modifier. 

xmodmap also allows you to add keysyms to be recognized as the given modifier. For 
example, the following command would cause the Fl function key to be recognized as mod2: 

isla% xmodmap - add xnod2 Fl 

For more information on xmodmap and xev, see Chapter 1 1 of Volume Three, X Window Sys 
tem User s Guide (Second Edition). 

7.1 .5.2 Default Interpretation of the Modifier List 

If no modifiers are specified in a translation, the state of the modifier keys and pointer buttons 
makes no difference to a translation. For example, the translation: 

<Key>q: quit() 

will cause the quit action to be invoked when the q key is pressed, regardless of whether 
the Shift, Ctrl, Meta, or Lock key is also held, and regardless of the state of the pointer but 
tons. 



198 X Toolkit Intrinsics Programming Manual 



Likewise, if a modifier is specified, there is nothing to prohibit other modifiers from being 
present as well. For example, the translation: 

Shift <Key>q : quit { ) 

will take effect even if the Ctrl key is held down at the same time as the Shift key (and the q 
key). 

There are a number of special modifier symbols that can be used to change this forgiving 
state of affairs. These symbols are shown in Table 7-4. 

Table 7-4. Modifier Symbols 



Symbol 



None 



Description 



No modifiers may be present 

No modifiers except those explicitly specified may be present 

Apply shift modifier to key event before comparing 

The modifier immediately following cannot be present 



The syntax of these special modifiers symbols is somewhat inconsistent, and made clearest 
by example. 

M.5.3 Prohibiting a Modifier 

The tilde (~) is used to negate a modifier. It says that the specified modifier may not be 
present For example, 

Buttonl<Key>: doit{) 

says that doit () should be invoked by a press of any key when button 1 is being held 
down, while 

~Buttonl<Key>: doit{) 

says that doit ( ) should be invoked by a press of any key except when button 1 is being 
held down. 

A ~ applies only to the modifier that immediately follows it For example, 
"Shift Ctrl<Key>: doit() 

says that doit ( ) should be invoked when Ctrl is held down in conjunction with any key, 
except if Shift is depressed at the same time. 




Events, Translations, and Accelerators 



7.1.5.4 Requiring an Exact Match 

An exclamation point at the start of a modifier list states that only themo difiers in that list 
may be present, and must match the list exactly. For example, if the translation is specified 
as: 

!Shift<Key>q: quit() 

the translation will take effect only if the Shift key is the only modifier present; if Caps Lock 
were in effect, or if a pointer button were depressed at the same time, the translation would 
no longer work. 

The modifier None is the same as ! with no modifiers specified. That is: 

None<Key>q : quit ( ) 
or 

!<Key>q: quit() 

will invoke quit only if no modifier keys at all are pressed. 

7.1 .5.5 Paying Attention to the Case of Keysyms 

The : modifier, like !, goes at the beginning of the modifier list and affects the entire list. This 
one is really in a category by itself, since it applies only to Key events. 

Normally, the translations: 

<Key>a: doit() 
and 

<Key>A: doit() 

have identical results: both will match either a lower-case or an upper-case A. Preceding 
the translation with a colon makes the case of the keysym significant. For example, to create 
commands like those in the UNIX vi editor, you might specify the following translations: 

:<Key>a: append () \n\ 
:<Key>A: appendToEndOfLine () 

In this case, a and A are distinct. You could achieve somewhat the same result by specifying: 

"Shift <Key>a: append () \n\ 
Shift<Key>a: appendToEndOfLine () 

However, this second example is both more complex and less effective. While the colon syn 
tax will match an upper-case character generated as a result of either the Shift or Lock modi 
fiers, the example shown immediately above will handle only Shift. You could use the fol 
lowing translation to prohibit both Shift and Lock from being asserted, but there is no way to 
specify that either Shift or Lock may be present 

~ Shift ~Lock<Key>a: append () \n\ 
Shift<Key>a: appendToEndOfLine () 

Note that you cannot specify both the Shift or Lock modifier and an upper-case keysym. For 
example: 



200 X Toolkit Intrinsics Programming Manual 



Shift <Key>A: doit() 
will have no effect, since you cannot further shift an uppercase character. 

For more details on how the Toolkit handles the ins and outs of case conversion, see Chapter 
13, Miscellaneous Toolkit Programming Techniques. A more rigorous discussion of how the 
colon modifier works is also given in Appendix F, Translation Table Syntax, in Volume Five, 
X Toolkit Intrinsics Reference Manual. 

7.1.6 Event Sequences 

The left-hand side of a translation may specify a single event or a sequence of events that 
must occur for the action to be invoked. For example, we might want a certain action to be 
invoked only if the first button is clicked twice in succession. 

Each event specified in the sequence is one of the abbreviations for an event type enclosed in 
angle brackets, optionally led by any set of modifiers and special characters, as described in 
Section 7.1.5. Each modifier-list/event pair in the sequence is separated by a comma. 

For example, the translation to perform an action in response to a button press followed by a 
release of the same button (a button click) is the following: 

<BtnDown>,<BtnUp> : doit() 

Button press events may be specified in the translation table followed by a count in parenthe 
ses to distinguish a multiple click. Xt uses a timing technique to distinguish multiple clicks. 
The translation to detect a double click is: 

<BtnlDown>(2) : doit() 
or 

<BtnlUp>(2) : doit() 

Notice that though they have the same effect for the user, these two translations are actually 
interpreted differently. The first is equivalent to saying: 

<BtnlDown>, <BtnlUp>, <BtnlDown> : doit { ) 

while the second is equivalent to: 

<BtnlDown>, <BtnlUp>, <BtnlDown>, <BtnlUp> : doit ( ) 

A plus (+) may appear immediately after the count inside the parentheses to indicate that any 
number of clicks greater than the specified count should trigger the action. 

The following translation detects two or more clicks: 

<BtnlDown>(2+) : doit() 
The maximum count that can be specified is 9. 



Events, Translations, and Accelerators 201 



7.1.6.1 Special Considerations Involving Motion Events 

Beware of interaction between pointer motion events and double clicking. If no motion 
events are specified in a translation table, these events are never selected, so there is no prob 
lem if they occur between other events. This allows a double click to be detected even if the 
user inadvertently jiggled the pointer in the course of the click. However, if motion events 
are selected for anywhere in the table, they may interfere with the expansion of events speci 
fied with the repeat notation. By definition, multiple clicks are detected only if there are no 
intervening events. Motion events would usually occur between the button presses and 
releases. 

Multiple motion events will match any single motion event selected in the translation. That 
is: 

<Motion>: doit() 

will cause doit ( ) to be invoked many times, once for each motion event generated by the 
pointer movement, unless the compressjmotion event filter is turned on in the Core 
class structure. (This filter is described in Section 8.6.2.) 

7.1 .6.2 Modifiers and Event Sequences 

A modifier list at the start of an event sequence applies to all events in the sequence. That is: 

Shift <BtnDown>,<BtnUp> : doit() 

is equivalent to: 

Shift <BtnDown>, Shift <BtnUp> : doit() 

However, if modifiers and events are interspersed, the modifier applies only to the event 
immediately following. As an extreme case to demonstrate this behavior, consider the fol 
lowing translation: 

Ctrl<Btn2Down>, ~Ctrl<Btn2Up>: doit() 

which requires that the CTRL key be depressed when pointer button 2 is pressed, but must not 
be depressed when it is released. 

7.1 .6.3 Using Modifiers to Specify Button Event Sequences 

Remember that there are modifiers for specifying the state of pointer buttons as well as modi 
fier keys. This provides another way of expressing some event sequences. For example, the 
following translation would invoke the action when the Fl key is pressed while button 1 is 
being held down: 

Buttonl<Key>Fl: doit() 

This is equivalent to: 

<BtnlDown>,<Key>Fl: doit() 

The following translations could be used to call an action when both the first and second 
pointer buttons are down, regardless of the order in which they are pressed. 



202 X Toolkit Intrinsics Programming Manual 



! Buttonl<Button2> : doC ( ) \n\ 
!Button2<Buttonl>: doC () 



7.1.6.4 Key Event Sequences 

The Translation Manager specification provides a special syntax for specifying a sequence of 
Key events as a string. That is: 

"yes": doit() 
is theoretically equivalent to: 

<Key>y,<Key>e,<Key>s: doit () 

We say "theoretically" because, at least in the R3 sample implementation from MIT, the 
"yes" syntax does not work. It may or may not work in other implementations. 

Within a sequence of key events expressed as a string (on systems where the "yes" syntax 
does work, if any), the special character * (circumflex) means Ctrl and $ means Meta. These 
two special characters, as well as double quotes and backslashes, must be escaped with a 
backslash if they are to appear literally in one of these strings. 



7.1.7 Interactions Between Translations 

One of the most difficult things to learn about translations is how to predict the interactions 
between overlapping translations. 

7.1 .7.1 Order of Translations 

The order of translations in a table is important, because the table is searched from the top 
when each event arrives, and the first match is taken. Therefore, more specific events must 
appear before more general ones. Otherwise, the more specific ones will never be reached. 

For example, consider a text entry widget that wants to close itself and dispatch a callback 
once the user presses the Return key, indicating that entry is complete. The widget s transla 
tions might be: 

<Key>Return: gotData ( ) \n\ 
<Key>: insertCharO 

If the translations were specified in the reverse order: 

<Key>: insertCharO \n\ 

<Key>Return: gotData () 

insertCharO would be called in response to a press of the Return key, and got 
Data ( ) would never be called 

Remember that the translations you specify will be merged with the widget s default transla 
tions unless you are using the default #replace directive. However, note that if several 
resource files contain translation tables for the same widget only the one that takes priority 
according to resource matching and precedence will have any effect even if all of them 



Events, Translations, and Accelerators 203 




specify ^augment or ^override. This is because the translation table is the value of the 
resource, and the last value specified will override earlier values. 

7.1 .7.2 Event Sequences Sharing Initial Events 

An exception to this rule of more specific translations being placed earlier in the translation 
table occurs with event sequences. One translation can contain an event or event sequence 
that appears in another translation. If the leading event or event sequence is in common, both 
will operate correctly. For example, the translations: 

<BtnlDown>, <BtnlUp> : actionB { ) \n\ 
<BtnlDown>: actionAO 

execute actionA ( ) when button 1 is pressed and actionB ( ) when it is then released. 
This is true regardless of which translation appears first in the table. 

This is the reason, alluded to in Chapter 2, why it is not possible to bind two different actions 
to a single and a double click of the same button in the same widget Specifying: 

<BtnlUp>(2): quit() \n\ 
<BtnlDown>, <BtnlUp>: confirm () 

will invoke the confirm () action on a single click and both the confirm () and 
quit ( ) actions on a double click. 

This behavior was a design decision on the part of the X Consortium. Otherwise, the Intrin- 
sics could never dispatch the single-click action until the double-click interval had passed, 
since it would have no way of knowing if a second click was coming. Applications needing 
to have single and double clicks in the same widget must do so by designing the two actions 
appropriately, rather than relying on the Translation Manager to make the distinction. 

7.1.7.3 Event Sequences Sharing Noninitial Events 

If a noninitial event sequence is common between two translations, each translation will 
match only event sequences where the preceding event does not match the other translation. 
Consider the translation: 

<BtnlDown>, <BtnlUp> : actionB ( ) \n\ 

<BtnlUp>: actionAO 

When a BtnlUp event occurs, it triggers actionA { ) only if not preceded by BtnlDown. 

The way this works is that Xt keeps a history of recent events. When each event arrives, Xt 
compares this event and its immediate history to the event sequences in a translation table. 
An event in the sequence may have already triggered an action, but that is irrelevent. Any 
translation whose final event in the event sequence matches the current event and whose ear 
lier event sequence matches the event history is matched. If there are two translations that 
can match a particular event sequence, then the translations are considered overlapping, the 
latter will override the former, and Xt will print a run-time warning message at startup (not 
waiting for the overlapping actions to be invoked). This is an exception to the rule stated 
earlier that the translation manager executes the first match. 



204 X Toolkit Intrinsics Programming Manual 



7.2 Accelerators 



Accelerators are simply translation tables registered to map event sequences in one widget to 
actions in another.* This is a general mechanism, but its name is based on a common 
use adding a keyboard interface for menus and Command widgets because for advanced 
users a keyboard interface is often faster. 

Every widget has an xtNaccelerators resource, inherited from the Core widget class, 
so the actual event-action pairs are specified through the resource mechanism, just like trans 
lations. But before the XtNaccelerators resource can be used, the application must 
call XtlnstallAccelerators or XtlnstallAllAccelerators to specify 
which widget will be used as the source of the actions to be invoked, and which will be the 
source of the events that invoke them. 

The MIT Intrinsics documentation refers to these two widgets as the "source" and "destina 
tion." This can be confusing, especially since the arguments are referenced in reverse order 
in the call to XtlnstallAccelerators: 



void XtlnstallAccelerators (destination, 
Widget destination; 
Widget source; 



source) 



Just remember that the source is the widget whose actions you want executed, and the desti 
nation is the widget you want the events to be gathered in. To understand the use of the 
phrase install accelerators, think of the accelerators as the XtNaccelerators resource 
of the source widget, together with the actions of that widget, and the destination as 
the widget to which these actions are transplanted (i.e., "installed"). 

XtlnstallAccelerators is always called from the application. (Widgets never 
install accelerators, because by definition they don t know about any other widgets.) In 
applications, this can be done any time, before or after the widgets are realized. Just before 
the xtMainLoop call is a good place. 

As an example, we ll add accelerators to the xboxl application from Chapter 3. This applica 
tion displays two Command widgets in a Box, as shown in Figure 7-1. 



Quit 




Press Me 



Figure 7-1. xboxl: two Command widgets in a Box 



* Accelerators made their debut in Release 3. 



Events, Translations, and Accelerators 



205 



To add accelerators requires a single line of code a call to xt installAccelerators, 
as shown in Example 7-1. 

Example 7-1. Installing accelerators in an application 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, box, quit; 



/* allow the quit widget s actions to be invoked by events 

* in box. */ 
XtlnstallAccelerators (box, quit) ; 

XtMainLoop () ; 
} 

The actual value of the accelerator table is set through the resource mechanism. The xt- 
Naccelerators resource is set for the widget whose actions are to be invoked from 
another widget Xt stores this accelerator table, in compiled form, in the widget s instance 
structure when the widget is created. When the application calls Xtlnstall 
Accelerators, the accelerator table stored in the widget is merged with the translation 
table of the widget that will be capturing the events. (If xtRemoveAccelerators is 
called, the original translation table, prior to merging with the accelerators from the source 
widget, is restored.) 

Example 7-2 shows a possible application-defaults file. 

Example 7-2. Specifying the XtNaccelerators resource from the application-defaults file 

*quit. label: Quit 
*pressme . label : Press me 
*quit .accelerators : \n\ 

<KeyPress>q: set { ) notify () 

This resource setting will allow a q typed anywhere in the Box widget that comprises the 
xboxl application window to invoke the quit widget s notify () action (which, as you 
may recall from Section 2.4, in turn invokes the Quit callback installed by the application.) 
Notice that the accelerators are specified as a resource of the source widget, even though 
the events that invoke them will come from the destination widget 

There are some differences in the translation tables that can be used for accelerators. 

Abbreviations for event types are not valid. Only the event names that were shown in 
column 1 of Table 7-1 may be used (although key works in place of KeyPress). 

The None, Meta, Hyper, Super, Alt, or ANY modifier symbols are not valid. 



206 X Toolkit Intrinsics Programming Manual 



The default directive for accelerator tables is faugment rather than #replace. If 
specified, the # replace directive is ignored. It is important to realize that accelerators 
are merged with the source widget s translations. #override thus says that the accel 
erators take priority over any matching translations in the source widget, and #augment 
says that the accelerators have lower priority. 

Parameters passed to actions must be quoted with double quotes. 



7.2.1 Event Propagation 

If you install accelerators in the box widget as shown in Example 7-1, you will notice that 
even though the destination widget is box, keyboard input will also be accepted in the chil 
dren of box, including not only the quit widget but also the pressme widget This is 
because of a characteristic of X called event propagation. 

The server sends to the client only the types of events the client selects. Internally, Xt selects 
events using the Xlib call XSelect Input. From a Toolkit application, this is hidden 
because the translation mechanism automatically selects the appropriate event types speci 
fied in the translation table. (As we will see in Chapter 8, More Input Techniques, Xt pro 
vides a low-level event-handling mechanism that exposes event selection more directly.) 

Event selection reduces the amount of network traffic, the number of events the server has to 
generate, and the number of unneeded events the client must process only to throw away. 

Events are selected on a per-window basis. Every event that arrives at the client contains the 
window ID of the window it was selected for. (Non-maskable events are the exception, since 
they have not been selected by a window.) 

Pointer and keyboard events propagate through windows that have not selected them, as 
shown below in Figure 7-2. That is, if the pressme widget s window has not selected 
KeyPress events, any key events that occur in that window will be passed on to its parent, 
the box widget If the box widget s window didn t select them either, they would be passed 
on to the window created by the top-level Shell widget, and so on. Events propagate through 
the window hierarchy all the way to the root window, until they reach a window that selected 
them. (If no window has selected them, they are never sent by the server.) Xt treats an event 
that originally occurred in some descendent widget, just like it actually happened in the 
widget that selected the event 




Events, Translations, and Accelerators 207 




Key pressed with 
pointer in pressme 
widget . . . 



No translation for 
keyboard events on 
pressme widget, event 
propagated to box . . . 



box widget has accelerator for keyboard 
events, and processes event propagated from 
pressme. box has installed accelerator that 
maps keyboard event into the notify and 
set actions of the quit widget 



Figure 7-2. Key event propagation in xbox 



Propagation is a characteristic of ButtonPress, ButtonRelease, KeyPress, Key- 
Release, MotionNotif y, EnterNotif y, and LeaveNotif y events only. As men 
tioned earlier, keyboard events are the events most often used as accelerators. 

In the version of xbox we just looked at, keyboard events propagate through the Command 
widgets to the Box widget, because they are not selected by the Command widgets. When 
they reach the Box widget, they match the events specified in the accelerator table and 
invoke actions from the quit widget 

The Command widgets have a default translation table that includes pointer button events 
and enter/leave events. Xt, therefore, selects these events for each Command widget Before 
accelerators are installed, the Box widget has no translation table and therefore has no events 
selected for it When the accelerators are installed, the accelerator table is merged with the 
(nonexistent) translation table of the Box widget and becomes the Box s translation table. 
Xt then selects keyboard events for the Box widget 



208 



X Toolkit Intrinsics Programming Manual 



But consider the resource settings in Example 7-3. 

Example 7-3. Conflicting translations and accelerators 

*quit. label: Quit 

*pressme . label : Press me 

*pressme .translations : #override\n\ 

<KeyPress>p: set() notify () 
*quit . accelerators : \n\ 

<KeyPress>q: set() notify () 

No key event will propagate through a widget that has a translation for any key event With 
the resource settings in Example 7-3, since pressme has a translation for the p key, the q 
key will not propagate through the widget Therefore, it is often better to specify all key 
events as accelerators and install them on a common ancestor. 

Accelerators are just merged into translations they are not a completely different mecha 
nism. The #augment (default) or #override directives used in accelerator tables spec 
ify whether the accelerator should override or augment existing translations for the destina 
tion widget For example, if box had a translation of its own that matched the event 
sequence in the accelerator installed on the same widget, whether the translation or the accel 
erator would be invoked depends on whether #augment (the default) or #override had 
been specified as the accelerator directive. (This example is a little farfetched, since the Box 
widget defines no actions or translations but it illustrates the point.) 

When using or writing widgets, event propagation is usually important only for accelerators, 
because widgets are rarely layered in such a way that any of the ones that accept input are 
obscured. 



7.2.2 Installing Accelerators in Multiple Widgets 

If you want to install accelerators from more than one widget, you can call xtlnstall- 
Accelerators once for every widget whose actions you want executable from the desti 
nation. Alternatively, you can call xtlnstallAHAccelerators just once for a 
whole application, specifying the application s top-level window as both the destination and 
the source. xtlnstallAHAccelerators recursively traverses the widget tree rooted 
at the source, and installs the accelerators of each widget onto the destination. 

For example, to install accelerators from both the quit and pressme widgets onto box, 
you could replace the call to xtlnstallAccelerators shown in Example 7-3 with:* 

Example 7-4. Installing accelerators from both command widgets 
XtlnstallAllAccelerators (box, box) ; 



*In a more complex application, where the box widget was not the main window but only a subarea containing com 
mand buttons, you might instead use the call: 

XtlnstallAllAccelerators (topLevel, box) ; 
which would make the actions from only the widgets contained in box available from anywhere in the application. 



Events, Translations, and Accelerators 



You could then define an application-defaults file such as the following: 

Example 7-5. Accelerators resource settings for two widgets 

*quit. label: Quit 
*pressme . label : Press me 
*pressme . accelerators : \n\ 

<KeyPress>p: set() notify () 
*quit .accelerators: \n\ 

<KeyPress>q: set() notify () 

Note that if there were any actions available in the box widget, they too would be available 
for specification in an accelerator resource setting. 

Because you would be most likely to specify distinct KeyPress events to invoke the 
actions in each Command widget, you would normally specify each accelerator resource sep 
arately, as shown above. But in the unlikely case that you wanted actions of multiple Com 
mand widgets to be invoked by the exact same event, you could do this instead. For 
example: 

*Command. accelerators : \n\ 

<KeyPress>: set() notify () 

would invoke the set and notify actions of every Command widget, but not of widgets 
belonging to other classes. 

Or assuming that there were multiple Box widgets in an application, one containing options, 
and the other commands, you might specify something like this: 

*optionsbox*accelerators : \n\ 

<KeyPress>: set() notify () 

to invoke the actions of every Command widget in optionsbox only. 

The point is that, like any resource setting, an accelerator table can apply to only one widget, 
to a group of children of a widget, or to an entire class, depending on how you identify the 
widgets for which you are setting the xtNaccelerators resource. 

7.2.3 Defining the Accelerator Table in the Code 

If you want to install a default accelerator table from within a program, you must follow sim 
ilar steps to those used for translations, but with the following differences: 

You must set the XtNaccelerators resource instead of XtNtranslations. 

Instead of using xtParseTranslationTable to convert the ASCII translation table 
into Xt s internal form, use XtParseAcceleratorTable. 

There are no accelerator equivalents of XtOverrideTranslations or xt- 
AugmentTranslations. Instead you can use xtSetValues and use the acceler 
ator directive by specifying faugment or toverride. 



210 X Toolkit Intrinsics Programming Manual 



7.2.4 The display accelerators Method 

Xt calls the source widget s display_accelerators method when the accelerators are 
installed. The purpose of this method is to display to the user the installed accelerators. The 
method is passed a string representation of the accelerator table, which the method can theo 
retically manipulate into a form understandable by the user. 

All of the Athena widgets inherit the Core widget s display_accelerators method 
by initializing the appropriate member of the class structure to xtlnheritDisplay- 
Accelerators. This default method, as implemented in the MIT distribution, does noth 
ing. 



Events, Translations, and Accelerators 



8 



More Input Techniques 



This chapter describes how to handle events with event handlers, and how to 
use information from the event structure inside an event handler or action rou 
tine. It also describes how to get file, pipe or socket input, how to use 
timeouts to call a function after a delay or at particular intervals, and how to 
use work procedures to do background processing. Finally, it discusses some 
low-level features of Xt lor directly interacting with the event queue. 



In This Chapter: 



Event Handlers 216 

Adding Event Handlers 218 

Adding Nonmaskable Event Handlers 219 

Removing Event Handlers 220 

Adding Raw Event Handlers 220 

Writing Routines That Use Specific Event Data 221 

Event Types and Structure Names 222 

File, Pipe, and Socket Input 224 

Getting File Input 224 

Getting Pipe Input 226 

Timeouts 227 

Visibility Interest 230 

Work Procedures 231 

Low-level Management of the Event Queue 233 

XtPending and XtPeekEvent 234 

Event Filters 234 

Input Sensitivity 235 



8 

More Input Techniques 



In addition to translations, there is a lower-level mechanism called event handlers. Event 
handlers can be used from application or widget code. An event handler is a function regis 
tered with xt AddEventHandler to be called in response to a particular event or group of 
events (but not an event sequence or combination, as is possible with translations). This is a 
low-level, non-user-configurable means of getting events. Event handlers provide no addi 
tional capabilities over translations and actions. But they allow Xt to skip the step of search 
ing a translation table before dispatching the event to an event handler. This speed advantage 
is possibly significant for events that come in large numbers, such as pointer motion events, 
or in applications with large translation tables. (Despite this, good performance in tracking 
pointer motion can be achieved with translations.) 

Both event handlers and actions are passed as an argument the actual event structure that 
caused them to be invoked. Many event handlers and actions use data in the event For 
example, a routine handling motion events may want to obtain the current pointer position 
from the event structure. After describing how to add and remove event handlers, we discuss 
the event structures, and show a routine that uses specific event data. 

Next, this chapter discusses three ways to register functions Xt will call for input other than 
events, since some programs do not live by X events alone. 

XtAddlnput registers a procedure to be called when input is available from a file (or 
pipe or socket). This can be used to perform code necessary when reads, writes, or 
exceptions are detected. 

xtAddTimeOut registers a function to be called at a particular relative time. This can 
be used to implement delays or to execute code repeatedly at known intervals. 

XtAddWorkProc registers a work procedure. Work procedures are called when input 
from other sources is not available. They perform background tasks while the application 
is waiting for user input. 

Finally, we provide more background on how the Toolkit dispatches events from xtMain- 
Loop, and describe the low-level routines that can be used to construct your own main loop. 
We also describe Xt s event filters, which are controlled by flags in the Core class structure. 
These filters tell Xt whether or not to compress multiple motion, enter, leave, or expose 
events occurring in the same widget. 



More Input Techniques 



8.1 Event Handlers 

An event handler is a function you provide to handle a particular type of event or group of 
event types. You register this function with a call to xtAddE vent Handler, specifying 
the widget in which the events are to be monitored. You can later stop the function from 
being called with XtRemoveEventHandler. On any widget, you can register as many 
event handlers as you want, each for the same or for different types of events. When more 
than one routine is registered for an event, the order in which they are invoked is undefined. 

Event handlers are infrequently used in application or widget code. None of the Athena 
widgets uses them, and only xterm and xman, out of the 40 applications in MIT s core distri 
bution use them. As mentioned earlier, event handlers are useful for handling high-volume 
events, such as MotionNotify events, with maximum speed. An event handler for 
motion events would probably be the best way to implement a drawing program. However, 
translation tables provide good speed even for motion events on most systems. 

Event handlers would also be useful when the type of events being handled changes fre 
quently, because there is some overhead involved in compiling and merging translation 
tables. Event handlers can also be used to handle events for which the user-configurability of 
translations is not needed or wanted, such as EnterWindow, LeaveWindow, Focus In, 
and Focus Out events. 

Another possible use of event handlers is to speed the handling of certain events when there 
is a very large translation table. For example, editors typically have a large number of trans 
lations for various key combinations. If an editor was to accept pointer motion as well (to 
allow drawing of simple graphics), it might pay to handle motion events in an event handler 
instead of through translations. 

The call to xtAddEventHandler specifies which events trigger the event handler func 
tion. This is done with an event mask argument* In an event mask, each bit represents one 
or more event types. Symbolic constants are defined by Xlib for each event mask bit. Multi 
ple types of events can be selected at the same time by ORing together different masks with 
the bitwise OR operator (|). Note that there is not a one-to-one correspondence between 
event masks and event types. Some event masks select only one event, but others select mul 
tiple events. Furthermore, several of the masks select the same event type, but specify that it 
be delivered only when it occurs under special conditions. Table 8-1 shows the event masks 
and the event types they select. 

Table 8-1. Event Masks and Event Types 



Event Mask 


Event Type 


KeyPressMask 
KeyReleaseMask 
ButtonPressMask 
ButtonReleaseMask 
OwnerGrabButtonMask 


KeyPress 
KeyRelease 
ButtonPress 
ButtonRe lease 
n/a 



*The event mask used in XtAddEventHandler is the same as the one used in the Xlib call XSelect Input. 



216 X Toolkit Intrinsics Programming Manual 



Table 8-1. Event Masks and Event Types (continued) 



Event Mask 



Event Type 



KeymapStateMask 

PointerMotionMask 

Point erMotionHintMask 

ButtonMotionMask 

ButtonlMotionMask 

Button2MotionMask 

ButtonSMotionMask 

Button4MotionMask 

ButtonSMotionMask 

EnterWindowMask 

LeaveWindowMask 

FocusChangeMask 

ExposureMask 

selected in GC by 

graph ics_expose component) 

ColormapChangeMask 

PropertyChangeMask 

VisibilityChangeMask 

ResizeRedirectMask 

StructureNotifyMask 



SubstructureNotifyMask 



SubstructureRedirectMask 



(always selected) 
(always selected) 
(always selected) 
(always selected) 
(always selected) 



KeymapNotify 
MotionNotify 



EnterNotify 

LeaveNotify 

Focusln 

FocusOut 

Expose 

GraphicsExpose 

NoExpose 

ColormapNotify 

PropertyNotify 

VisibilityNotify 

ResizeRequest 

CirculateNotify 

ConfigureNotify 

DestroyNotify 

GravityNotify 

MapNotify 

ReparentNotify 

UnmapNotify 

CirculateNotify 

ConfigureNotify 

CreateNotify 

DestroyNotify 

GravityNotify 

MapNotify 

ReparentNotify 

UnmapNotify 

CirculateRequest 

Conf igureRequest 

MapRequest 

MappingNotify 

ClientMessage 

Select ionClear 

Select ionNot if y 

Select ionRequest 



More Input Techniques 



217 



The events that are always selected are called nonmaskable events. These can also be han 
dled with an event handler, but not by specifying them in the event mask. An argument to the 
XtAddE vent Handler call, non_maskable, is a Boolean value that, if TRUE, specifies 
that the event handler should be called for nonmaskable events. This event handler then must 
branch according to which of the seven types of nonmaskable events it is passed. A typical 
nonmaskable event handler is shown in Section 8.1.2. 



8.1.1 Adding Event Handlers 

Event handlers are added with a call to xtAddEventHandler. This call takes five argu 
ments: the widget for which the handler is being added, an event mask, a flag that specifies 
whether or not this handler is for nonmaskable events (see below), the name of the handler, 
and optional client data. 

XtAddEventHandler may be called before or after a widget is realized. In application 
code, this means the call can appear anywhere before XtMainLoop. In a widget, XtAdd 
EventHandler calls are placed in the initialize or realize methods. 

Example 8-1 shows the code from xterm that registers an event handler for Focus In and 
FocusOut events, and a gutted version of the event handler itself. 

Example 8-1. Registering an event handler, and the handler function itself 
extern void HandleFocusChange (); 

static void VTInitialize (request, new) 
XtermWidget request, new; 

111 { 



XtAddEventHandler (topLevel, /* widget */ 

FocusChangeMask, /* event mask */ 
FALSE, /* non-maskable events */ 

HandleFocusChange, /* event handler */ 
(Opaque)NULL) ; /* client_data */ 



/*ARGSUSED*/ 

void HandleFocusChange (w, unused, event) 

Widget w; 

register XFocusChangeEvent *event; 

caddr_t unused; /* client_data */ 

{ 

if (event->type == Focusln) 

/* process Focusln */ 



else { 



218 X Toolkit Intrinsics Programming Manual 



Example 8-1. Registering an event handler, and the handler function itself (continued) 

/* process FocusOut */ 



In typical usage, either the event mask argument is a mask and the non_maskable argu 
ment is set to FALSE, or the event mask argument is set to zero and non_maskable is set 
to TRUE. Example 8-1 demonstrated the former case; now we ll look at the latter. 



8.1.2 Adding Nonmaskable Event Handlers 

The non_maskable argument of XtAddE vent Handler specifies whether the speci 
fied event handler should be called in response to the events that can t be selected as 
described above. The nonmaskable events are GraphicsExpose, NoExpose, 
MappingNotify, SelectionClear, SelectionRequest, Selection- 
Notify, and ClientMessage. The first two of these events are selected using the 
graphics_exposure component of the GC, and the rest are always sent to the client 
whenever they occur. MappingNotify is automatically handled by Xt, so it isn t passed 
to event handlers and you don t need to worry about it The selection events are described in 
Chapter 10, Inter-Client Communications. 

Because there are several nonmaskable event types, a nonmaskable event handler must be 
sure to branch according to the type of event, and throw away any event types not handled. 
You need not have all the code to handle all the types in a single event handler. Instead, you 
can handle each in a separate handler, each registered separately. However, each would still 
need to check the event type because the entire list of them would be called for every non 
maskable event 

Example 8-2 shows the registration of a nonmaskable event handler and the handler itself, 
from xman. 

Example 8-2. Adding a nonmaskable event handler 

static void 

Realize (w, valueMask, attributes) 

register Widget w; 

Mask *valueMask; 

XSetWindowAttributes * attributes; 

Illl { 



XtAddEventHandler (w, 0, TRUE, 

GExpose, NULL); /* Get Graphics Exposures */ 
} /* Realize */ 

/* ARGSUSED */ 
static void 



More Input Techniques 



219 



Example 8-2. Adding a nonmaskable event handler (continued) 

GExpose (w, junk, event) 
Widget w; 
caddr_t junk; 
XEvent *event; 
{ 

if (event->type == GraphicsExpose) 

Redisplay (w, event, NULL); /*call the expose method directly*/ 
} 

This event handler is necessary because Xt does not call the expose method in response to 
GraphicsExpose events. 

8.1.3 Removing Event Handlers 

xtRemoveEventHandler takes the same arguments as XtAddEventHandler; if 
there are parameter mismatches, the call is quietly ignored. For example, the client data 
argument may be used to distinguish between different event handlers; if the client data argu 
ment does not match that which was passed in the XtAddEventHandler, then Xt 
RemoveEventHandler will do nothing. XtRemoveEventHandler is also silent 
about failing to remove a handler that was never added or an incorrectly specified handler. 

8.1.4 Adding Raw Event Handlers 

Xt also allows you to add event handlers without actually selecting events. These are called 
row event handlers, and are added with xtAddRawEventHandler, which has the same 
calling sequence as XtAddEventHandler. The event mask in XtAddRawEvent 
Handler indicates which events the handler will be called in response to, but only when 
these events are selected elsewhere. Raw event handlers are supported mostly because they 
are used inside Xt. They are mentioned here only for completeness you are unlikely to 
need them. 

A raw event handler might be used to "shadow" another event handler (both added with the 
same event mask), such that until a primary event handler is added, the shadow handler will 
never be called. The primary handler will be added with XtAddEventHandler, which 
will select events, and then both handlers will be called when the appropriate events occur. 

However, the "shadowing" technique is not necessary to assure that multiple calls to Xt 
AddEventHandler don t result in wasted XSelect Input calls in which the event 
mask has not changed. Xt keeps a cache of the event masks of each widget, and calls 
XSelect input only when it is necessary to change the window s event mask attribute in 
the server. 

Raw event handlers are removed with a call to XtRemoveRawEventHandler. 



220 X Toolkit Intrinsics Programming Manual 



8.2 Writing Routines That Use Specific Event Data 

An event is a packet of information that the server sends to the client. Xlib takes this packet 
from the network and places it into an XEvent structure and places it on a queue until the 
client program requests it. Xt requests events from this queue, and dispatches the event to 
the appropriate action routine or event handler for the widget in which the event occurred. 
The event itself is passed as an argument to the routine.* 

Actually, XEvent is a C-language union of many event structures all the same size but with 
some different field names. The first member of the union, and of any of the individual event 
structures, is the event type. Table 8-2, later in this section, lists the event types and the 
matching event structure types. 

Many action routines are intentionally written not to depend on the detailed information 
inside any particular type of event, so that the user can specify translations to call the action 
in response to different types of events. For example, it is useful for an action routine nor 
mally triggered by a pointer click to work when called in response to a key instead. Such an 
action should not depend on the event structure fields unique to button events. 

However, many other action routines, and most event handlers, do use the detailed informa 
tion inside event structures. The first member, type, identifies which type of event this 
structure represents, and hence implies which other fields are present in the structure. 

To access event structure fields other than type you need to cast XEvent into the appropri 
ate event structure type. If you are expecting only one type of event to trigger this action, 
then you can simply declare the argument as the appropriate type, as shown in Example 8-3. 

Example 8-3. Casting the event structure by declaring action routine arguments 

static void 
Turn (w, event) 
TetrisWidget w; 
XButtonEvent *event; 
{ 

)/* we must now use only the fields in XButtonEvent */ 
if (event->type != ButtonPress) 
XtWarning( "TetrisWidget: Turn action invoked\ 
by wrong event type."); 



When an action routine or event handler depends on the fields in a particular event structure, 
it is a good practice to check the event type in that action unless you are sure that the user 
can t change the translation (and thus the events used to invoke the action). 

If the data in the event structure is important to an action, it is usually better to write the 
action so that it is called in response to only one type of event If you want the same code 
called for two event types, then you would do better to create two separate translations and 



*We ll lex* at the low-level routines Xt provides for manipulating the event queue later in this chapter. For now, this 
simplified discussion is sufficient 



More Input Techniques 221 



two separate actions that each call a common routine. However, it is sometimes more conve 
nient to have an action called by two different events. Example 8-4 shows the Toggle- 
Cell action from the BitmapEdit widget, which is called in response to either Motion- 
Notify or Button? re ss events. This action inverts a pixel in the bitmap either if the 
pointer is clicked on a cell in the widget, or if it is dragged across the cell with the pointer 
buttons held down. 

Example 8-4. Handling multiple event types in an action routine 

static void 
ToggleCell (w, event) 
BitmapEditWidget w; 
XEvent * event; 
{ 

static int oldx = -1, oldy = -1; 

GC gc; 

int mode; 

int newx, newy; 

if (event->type == ButtonPress) { 

newx = (w->bitmapEdit .cur_x + ( (XButtonEvent *) event )->x) / 

w->bitmapEdit . cell_size_in_pixels; 
newy = (w->bitmapEdit .cur_y + ((XButtonEvent *)event)->y) / 

w->bitmapEdit . cell_size_in_pixels; 

} 

else if (event->type == MotionNotify) { 

newx = (w->bitmapEdit .cur_x + ( (XMotionEvent *)event)->x) / 

w->bitmapEdit . cell_size_in_pixels; 
newy = (w->bitmapEdit . cur_y + ((XMotionEvent *) event ) ->y) / 

w->bitmapEdit . cell_size_in_pixels; 
} 
else 

XtWarning ("BitmapEdit : ToggleCell called with wrong 
event type\n") ; 



Notice that some code is repeated to cast the event structure to the two different event types. 
With the current MIT implementation of Xlib, the positions of the x and y fields in the 
XButtonEvent and XMotionEvent structures are the same, and therefore this casting 
is unnecessary. However, it is improper to depend on any particular implementation of Xlib. 
The order of the fields in one of these events could be different in a vendor s implementation 
of Xlib. 



8.2.1 Event Types and Structure Names 

Table 8-2 lists the event types and the matching event structure types. The event descriptions 
in the table will give you a general idea of what each event is for. Many of these events are 
not often used in applications, and more of them are automatically handled by Xt. We ve 
already discussed how to use the most common event types and their abbreviations in transla 
tion tables in Chapter 7, Events, Translations, and Accelerators. Appendix C, Event 



222 X Toolkit Intrinsics Programming Manual 



Reference in Volume Five, X Toolkit Intrinsic* Reference Manual, provides a complete refer 
ence to the circumstances under which each event is generated, what it is for, and the fields in 
each of the event structures. You will need this information to write action routines that use 
event-specific data. 



Table 8-2. Event Types and Event Structures 



Event Type 



Structure 



Description 



KeyPress 

KeyRelease 

ButtonPress 

ButtonRelease 

KeymapNotify 

MotionNotify 

EnterNotify 

LeaveNotify 

Focusln 

FocusOut 

Expose 

GraphicsExpose 

NoExpose 

ColormapNotify 

PropertyNotify 

VisibilityNotify 

ResizeRequest 

CirculateNotify 
ConfigureNotify 
DestroyNotify 
GravityNotify 

MapNotify 
ReparentNotify 
UnmapNotify 
CirculateRequest 

ConfigureRequest 
MapRequest 

MappingNotify 
ClientMessage 
Select ionClear 
SelectionNotify 
Select ionRequest 



XKeyPressedEvent 

XKeyReleasedEvent 

XButtonPressedEvent 

XButtonReleasedEvent 

XKeymapEvent 

XPointerMovedEvent 

XEnterWindowEvent 

XLeaveWindowEvent 

XFocusInEvent 

XFocusOutEvent 

XExposeEvent 

XGraphicsExposeEvent 

XNoExposeEvent 

XColormapEvent 

XPr ope rtyE vent 

XVisibilityEvent 

XResizeRequestEvent 

XCirculateEvent 
XConfigureEvent 
XDestroyWindowEvent 
XGravityEvent 

XMapEvent 
XReparent Event 
XUnmapEvent 
XCirculateRequest Event 

XConfigureRequestEvent 
XMapRequest Event 

XMappingEvent 

XClientMessageEvent 

XSetSelectClearEvent 

XSelectionEvent 

XSelectionRequestEvent 



Key pressed 
Key released 
Pointer button pressed 
Pointer button released 
State of all keys when pointer entered 
Pointer motion 
Pointer entered window 
Pointer left window 
This window is now keyboard focus 
This window was keyboard focus 
Part of window needs redrawing 
Source of copy unavailable 
Source of copy available 
Window s colormap changed 
Property value changed 
Window has been obscured 
Redirect resize request to window 
manager 

Stacking order modified 
Window resized or moved 
Window destroyed 

Window moved due to win gravity 
attribute 

Window mapped 
Window reparented 
Window unmapped 
Redirect stacking order change to 
window manager 

Redirect move or resize request to 
window manager 

Redirect window map request to win 
dow manager 

Keyboard mapping changed 
Client-dependent 
Current owner is losing selection 
Selection is ready for requestor 
Request for selection to current owner 



More Input Techniques 



223 



8.3 File, Pipe, and Socket Input 

xtAddlnput allows a program to obtain input from a file. This is not merely reading the 
file once, but monitoring it for further activity.* Under UNIX this can be used to get input 
from pipes and sockets, since they are variations of files. We will demonstrate getting file 
and pipe input in this section. 

The XtAddlnput routine takes four arguments: a file descriptor, a flag (see below), your 
function, and client_data. 

xtAddlnput returns an ID that uniquely identifies the XtAddlnput request. You can 
use the ID to cancel the request later with xt Remove Input. 

One argument of XtAddlnput is a file descriptor (this file must be open before calling 
xtAddlnput). Since implementation of files varies between operating systems, the actual 
contents of the parameter passed as the file descriptor argument to these routines is operating 
system-dependent. Therefore, this code is inherently nonportable. 

Possible values for the mask and their meanings are as shown in Table 8-3. 
Table 8-3. Other Input Source Masks 



Mask 



XtlnputReadMask 
XtlnputWriteMask 
Xt InputExceptMask 
Xt InputNoneMask 



Description 



File descriptor has data available 
File descriptor available for writing 
I/O errors have occurred (exceptions) 
Never call function registered 



Calling these argument values masks is something of a misnomer, since they cannot be ORed 
together. However, you can call XtAddlnput additional times to register a separate func 
tion for each of these masks on the same file descriptor. 

8.3.1 Getting File Input 

In Example 8-5, a program called xfileinput reads new characters from a file whenever they 
appear. In other words, the program will initially print to the standard output the contents of 
the file specified on the command line, and it will print any characters that are later appended 
to that file. Try the program xfileinput as follows: 

echo "test string" > testfile 

xfileinput testfile & 

echo "more text" testfile 



*A bug in R3 prevented the function registered with XtAddlnput from being called unless normal X events were 
available. This effectively makes the feature useless under R3. The examples in this section work under R4 only. 



224 X Toolkit Intrinsics Programming Manual 



A program such as this functions similarly to the UNIX command tail -f. It could be used to 
monitor system log files, or other similar files that grow. 

The code shown in Example 8-5 opens the file and calls XtAddlnput in main. The 
get_f ile_input function registered with XtAddlnput reads and prints characters 
from the file.* 

Example 8-5. Getting file input with XtAddlnput 
/* header files */ 



/* ARGSUSED */ 

get_file_input (client_data, fid, id) 

caddr_t client_data; /* unused */ 

int *fid; 

Xtlnputld *id; 

{ 

char buf [BUFSIZ] ; 

int nbytes; 

int i; 

if ((nbytes = read(*fid, buf, BUFSIZ)) == -1) 
perror ("get_file_input") ; 

if (nbytes) 

for (i = 0; i < nbytes; i++) 

putchar (buf [i] ) ; 
} 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, goodbye; 

FILE *fid; 

String filename; 

topLevel = Xtlnitialize (argv [0] , "XFilelnput", NULL, 
0, sargc, argv) ; 

if (argv[l] = = NULL) { 

fprintf (stderr, "xfileinput: filename must be specified on\ 
command line.Xn"); 

exit (1) ; 
} 
filename = argv[l]; 



/* open file */ 

if ((fid = f open (filename, "r") ) == NULL) 

fprintf (stderr, "xfileinput: couldn t open input file") ; 



*Note that the code for opening and reading files is probably not portable to operating systems other than UNIX. 



More Input Techniques 225 



Example 8-5. Getting file input with XtAddlnput (continued) 

/* register function to handle that input, NULL arg 

* is client_data */ 
XtAddlnput (fileno (fid) , XtlnputReadMask, get file input, NULL); 



XtRealizeWidget (topLevel) ; 
XtMainLoopO ; 



I 



The function registered with XtAddlnput is called with client_data (used for passing 
in any application data), a pointer to the file descriptor, and the ID of the XtAddlnput 
request You can use a call to Xt Remove Input in the function registered with XtAdd 
lnput if that function is only to be called once. One argument of the xt Remove Input 
call is the ID of the XtAddlnput request* 

8.3.2 Getting Pipe Input 

The code to get pipe input is almost identical to the code just shown that gets file input. The 
only difference is that we us&popen instead of f open, and change the various error messages. 
Now instead of treating the command-line argument as a filename, it is treated as a program 
run under a shell. This program s output is piped into our application. For example, here is 
an example of how to invoke this version of xpipeinput: 

spike% xpipeinput "cal 11 1989" 

November 1989 
S M Tu W Th F S 
1234 
5 6 7 8 9 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 
(Program continues to monitor pipe for further input until application exits.) 

Note that xpipeinput is reading the string "cal 11 1989" from the command line, invoking a 
shell, running the command specified by the string under this shell, reading the output of the 
shell, and then printing it on the standard output This is an easy way to use all kinds of shell 
scripts and utilities from within a program. 

If you want your application to accept standard input, this is even easier. Remove the code 
that reads the filename from the command line and remove the popen call to open the pipe, 
since the pipe from stdin is always open. Then use the XtAddlnput shown in Example 
8-6. 



*Under the beta release of R4, the function registered with XtAddlnput ii called very frequently even when no 
new input is available. The examples shown work, but they load down the system much more than necessary. It is 
difficult to tell whether this is a bug or the intended behavior. If this "feature" is still present in your version of Xt, 
you may wish to add your input handler periodically using timeouts (to be described next), and have the input han 
dler remove itself each time. 



226 X Toolkit Intrinsics Programming Manual 



Example 8-6. Reading stdin from an Xt application 

XtAddlnput (f ileno (stdin) , XtlnputReadMask, get_f ile_input , NULL); 

Once you have done this, you can invoke xpipeinput as follows: 

spike% cal 11 1989 I xpipeinput 

November 1989 
S M Tu W Th F S 
1234 
5 6 7 8 9 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 
(Program continues to monitor pipe for further input until application exits.) 

Note that in this case, xpipeinput is reading directly from stdin, and then printing the output 
to stdout. With more code, it could display this calendar in a Text widget instead. 



8.4 Timeouts 

A program may wish to be notified when a period of time has elapsed, while being able to do 
other things during that time. For example, a clock widget requires a periodic nudge to 
change the time it is displaying, but must also be able to redisplay itself at any time in case of 
exposure. 

This is done by using xtAddTimeOut. This routine is passed a time interval in milli 
seconds, and the address of a function to be invoked when the time interval expires. As 
usual, a clie/it_data argument can also be registered. The xtAddTimeout routine 
returns a handle that can be used to cancel the timeout before it triggers, if necessary. 

A timeout is automatically removed when the registered function is called. Therefore, to 
have a function called repeatedly, every N milliseconds, the registered function must add the 
timeout again by calling XtAddTimeOut. 

One of the major applications of timeouts other than clocks is in real-time games. Figure 8-1 
shows the appearance of a game called xtetris after it has been played for a couple of min 
utes. 

The object of the game is to steer falling blocks and rotate them so that they fit well into the 
existing fallen blocks.* The game is over when the blocks pile up to the top of the window. 
Every time a row is completely filled, it is removed and all the blocks above it move down 
one row. The window in which the blocks fall is a specialized widget This game uses 
timeouts to time the falling of the blocks. 



*This game is provided with the example joarce code. It is an X version of a game available on the Macintosh called 
Tetris, trademark of AcademySoft-ELORG, copyright and trademark licensed to Andromeda Software Ltd. The ong- 
inal concept of the game is by Alexi Pazhimov and Vadim Gerajimov. 



More Input Techniques 



Score: 32 I [Quit] [ Start Neui Game | [ Level: 3 1 1 Shoui High Scores | [ Contirj 




Figure 8-1. xtetris in play 

Example 8-7 is an excerpt from a widget used by xtetris that adds the timeout The timeout 
function itself is also shown. 

Example 8-7. xtetris: registering a timeout, and the timeout function 

static Xtlntervalld timer; 

static void 
StartBlock(w) 
BitmapEditWidget w; 
{ 

w->bitmapEdit.cur_x = 9; 

w->bitmapEdit .cur_y = 0; 



228 



X Toolkit Intrinsics Programming Manual 



Example 8-7. xtetris: registering a timeout, and the timeout function (continued) 

w->bitmapEdit.type = PickType(); 
DrawBlock (w, DRAW) ; 

timer = XtAddTimeOut (w->bitmapEdit .delay, MoveDown, w) ; 
} 

static void 

MoveDown (w) 

BitmapEditWidget w; /* client_data */ 

{ 

if (CanMoveDown (w) ) { 

DrawBlock (w, UNDRAW); 

w->bitmapEdit . cur_y++; 

DrawBlock (w, DRAW) ; 

CopyBlock (w) ; 

timer = XtAddTimeOut (w->bitmapEdit .delay, 

MoveDown, w) ; 
} else { /*block has hit bottom or other stationary blocks*/ 

UpdateCellArray (w) ; 

KillRows(w) ; 

Score (w) ; 

w->bitmapEdit .delay -= 5; 

StartBlock(w) ; 



Notice that a timeout function is called with only one argument, clent_data. Inside a 
widget, this argument is commonly used to pass in the widget instance pointer. Also notice 
that every time a block hits the bottom, the instance variable delay is decremented by 5, 
which reduces the number of milliseconds of delay used when XtAddTimeOut is next 
called. In other words, the blocks fall progressively faster. 

xtetris also needs to remove a timeout in one of its routines. The user can "drop" a block to 
score extra points (if there is enough time). Whenever a block is dropped, the block is imme 
diately moved down as far as it will go, and a new block is started. If the Drop action did 
not remove the timeout, the new block would be started with a new timeout while an existing 
timeout was already in force. This would mean that the MoveDown timeout function would 
be invoked twice in quick succession when each of these timeouts expired. Example 8-8 
shows the XtRemoveTimeOut call in the Drop action. 

Example 8-8. xtetris: calling XtRemoveTimeOut 

static void 
Drop (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 
{ 

XtRemoveTimeOut (timer) ; 

while (CanMoveDown (w) ) { 

DrawBlock (w, UNDRAW); 
w->bitmapEdi t . cur_y++ ; 
DrawBlock (w, DRAW); 
CopyBlock (w) ; 



More Input Techniques 229 



Example 8-8. xtetris: calling XtHemoveTimeOut (continued) 

UpdateCellArray (w) ; 
KillRows(w) ; 
score++; 
Score (w) ; 

w->bitmapEdit .delay -= 5; 
StartBlock(w) ; 
} 

Notice that the timer ID returned from the calls to xtAddTimeOut is a global variable. 
Xt calls the timeout function with only one argument, and that argument passes in the widget 
instance pointer. We could have created a structure containing the widget instance pointer 
and the timer ID and passed its pointer to the timeout function. But this wouldn t help, 
because the action routine in which we remove the timeout is passed with no 
client_data argument. (It has string parameters, but these are hardcoded in the actions 
table.) Therefore, we are forced to have a global variable for the timer ID. 

Note that between the time when the timeout is registered and when it triggers, the applica 
tion processes events in xtMainLoop. Therefore, all the widget s actions and expose 
method are in operation between the invocations of the timeout function. 



8.4.1 Visibility Interest 

Timeouts operate regardless of the visibility of the application. Since it is pointless for most 
games to continue operating while obscured, it makes sense to remove the game s timeouts 
when the game is partially or fully obscured (or iconified). To do this, you can set the vis - 
ible_interest field in the Core class structure to TRUE, and then check the visible 
field of the Core instance structure periodically. When the application is fully obscured, you 
add a separate timeout to continue testing the visibility status. When the visibility status is 
satisfactory once again, the game can add its timeout again. All these changes are in the 
widget s .c file. First we set the visible_interest field to TRUE in the Core structure: 

BitmapEditClassRec bitmapEditClassRec = { 
{ 
/* core class fields */ 



/* visible_interest */ TRUE, 



Second we change: 

timer = XtAddTimeOut (w->bitmapEdit .delay, MoveDown, w) ; 



230 X Toolkit Intrinsics Programming Manual 



to: 

if (w->core. visible == FALSE) 

timer = XtAddTimeOut (250, CheckVisibility, w) ; 
else 

timer = XtAddTimeOut (w->bitmapEdit .delay, MoveDown, w) ; 

And finally, we add the timeout function that continues to check the visibility status. 

static void 

CheckVisibility (w) 

BitmapEditWidget w; /* client_data */ 

{ 

if (w->core. visible == FALSE) 

timer = XtAddTimeOut (250, CheckVisibility, w) ; 
else 

timer = XtAddTimeOut (w->bitmapEdit .delay, 

MoveDown, w) ; 
} 

Unfortunately, the Core visible field is TRUE even if a tiny sliver of the widget is visible. 
The only way to get around this is to add an event handler (or translation) for 
VisibilityNotify events, and to add an instance variable to maintain the visibility 
state. The event handler or action would check the state field of the event, and put the 
game into hibernation if the window is only partially obscured. However, this approach has 
the opposite problem; it disables the game even when only a sliver is obscured. 

There is nothing you can do about the game continuing to run while being moved or resized 
with the window manager. However, using the Core visible_interest field does stop 
the game when it is iconified. 



8.5 Work Procedures 



A work procedure is an application-supplied function that is executed while an application is 
idle waiting for an event Work procedures are registered with xtAddWorkProc. They 
can perform any calculation that is short enough that the routine will return in a small frac 
tion of a second. If the work procedure is too long, the user s response time will suffer. 

If a work procedure returns TRUE, then Xt will remove it and it will not be called again. But 
if one returns FALSE, it will be called repeatedly every time there is idle time, until the appli 
cation calls XtRemoveWorkProc. A work procedure would return TRUE if it performs a 
one-time setup such as creating a pop-up widget It would return FALSE if it were continu 
ously updating a disk file as security against a system crash or server connection failure. 

You can register multiple work procedures, and they will be performed one at a time. The 
most recent work procedure added has the highest priority. Therefore, for example, if you 
want to create ten pop-up widgets during idle time, you should add ten work procedures. The 
pop up that you expect to need first should be added in the last work procedure registered. 

The call to register a work procedure is shown in Example 8-9. 



More Input Techniques 



Example 8-9. Registering an Xt Work Procedure 
static Boolean create_popup () ; 



main(argc, argv) 
int argc; 
char **argv; 
{ 

XtWorkProcId popup_work_ID 

Widget topLevel; 



/* Xtlnitialize, create widgets, etc. */ 
popup_work_ID = XtAddWorkProc (create_popup, topLevel) 



XtRealizeWidget (topLevel) ; 
XtMainLoopO ; 
} 

Notice that xtAddWorkProc returns an ID of type XtWorkProcId, which is used only 
in any subsequent call to xtRemoveWorkProc. You can cast the returned value to void 
if you do not intend to explicitly remove the work procedure. 

The client_data argument passes application data into the work procedure. It is used 
just like the same argument in callback functions. Example 8-10 shows a work procedure to 
create a pop-up widget. 

Example 8-10. A work procedure to create a pop-up widget 
Widget pshell; 

/* work procedure */ 
Boolean 

create_popup (parent) 
Widget parent; 
{ 

Widget dialog, dialogDone; 

pshell = XtCreatePopupShell ( 
"pshell", 

transient She HWidget Class, 
parent, 
NULL, 

); 

dialog = XtCreateManagedWidget ( 

"dialog", /* widget name */ 

dialogWidgetClass, /* widget class */ 
pshell, /* parent widget */ 

NULL, /* argument list */ 

/* arglist size */ 



232 X Toolkit Intrinsics Programming Manual 



Example 8-10. A work procedure to create a pop-up widget (continued) 

dialogDone = XtCreateManagedWidget ( 

"dialogDone", /* widget name */ 
commandWidgetClass, /* widget class */ 
dialog, /* parent widget */ 

NULL, /* argument list */ 

/* arglist size */ 

XtAddCallback (dialogDone, XtNcallback, DialogDone, dialog); 
return (True) ; /* makes Xt remove this work proc automatically */ 

Remember that Xt cannot interrupt a work procedure while it is running; the procedure must 
voluntarily give up control by returning, and it must do so quickly to avoid slowing user 
response. 



8.6 Low-level Management of the Event Queue 

As you know, an X Toolkit application simply calls xtMainLoop to begin processing 
events. XtMainLoop itself is quite simple: it consists of an infinite loop calling two 
lower-level routines, XtNextEvent and xtDispatchEvent. XtNextEvent extracts 
the next event from the application s event queue; XtDispatchEvent actually uses the 
event to invoke the appropriate actions or event handlers. (The callbacks for pseudo-events 
registered by XtAddlnput and xtAddTimeOut are dispatched directly by XtNext 
Event; if no events are available, XtNextEvent flushes the X output buffer, and calls 
any work procedures registered by xtAddWorkProc.) 

An application can provide its own version of this loop, as shown in Example 8-11. For 
example, it might test some application-dependent global flag or other termination condition 
before looping back and calling XtNextEvent. Or for fine-grained debugging, it might be 
worthwhile to insert a routine that prints out each event dispatched. 

II Example 8-11. Skeleton of a custom main loop 

void MyMainLoopO 
{ 

XEvent event; 

for (;;) { 

XtNextEvent (Sevent) ; 
XtDispatchEvent (&event) ; 

/* Do application-specific processing here */ 



More Input Techniques 233 



8.6.1 XtPending and XtPeekEvent 

All event sources depend on idle time in the application to return to XtMainLoop where Xt 
can check to see if input is available from any of the various sources. If an application has 
long calculations to make, the program may not return to XtMainLoop frequently enough 
to detect important input in a timely fashion. The application itself should, if possible, sus 
pend lengthy calculations for a moment to check whether input is available. Then it can 
determine whether to process the input before continuing, or finish the calculation. 

To detect whether input from any input source is available, you can call XtPending. This 
function returns a mask composed of a bitwise OR of the symbolic constants xtiMXEvent, 
xtiMTimer, and xtlMAlternatelnput. These constants refer to X events, timer 
events, and alternate input events, respectively. 

To find out what the first event in the queue contains, you can call XtPeekEvent. This 
function returns an event structure without removing the event from Xlib s queue. 

It is also possible to remove and process a single event xtProcessEvent combines 
some (but not all) of the functions from XtNextEvent and XtDispatchEvent. That 
is, while XtNextEvent takes the next event from the queue, whatever it is, XtProcess 
Event allows you to specify as a mask a bitwise OR of the symbolic constants xt- 
iMXEvent, XtiMTimer, and XtlMAlternatelnput. This lets you select only some 
of these event types for processing. In addition, XtProcessEvent actually calls Xt 
DispatchEvent to dispatch X events, so only this one call is necessary. 



8.6.2 Event Filters 

As you saw in Chapter 5, Inside a Widget, the class structure contains three Boolean fields 
that control Xt s event filters. These are compress_motion, compress_enter- 
leave, and compress_exposure. Widgets set these fields to TRUE when repeated 
events of these types are unwanted. Each would be used in different situations. If turned on, 
they tell Xt to search Xlib s queue for a certain event sequence and then remove repeated 
occurrences of those events from the queue. 

When the compress_motion filter is set to TRUE, and there is a series of Motion- 
Notify events on the queue (which occurs when the application gets behind in processing 
them), the filter throws out all but the last one (the most recent position). This is useful for 
widgets that need the most up-to-date position but do not need a complete history of pointer 
positions. 

The compress_enterleave filter throws out all EnterNotify/LeaveNotify 
pairs on the same window in which there are no intervening events. This would be used by a 
widget that is interested in enter and leave events, but not if the application falls behind. For 
example, even the Command widget sets compress_enterleave to TRUE. It highlights 
its border when the pointer enters, and clears it when the pointer leaves. But if for some rea 
son the widget falls behind and has not highlighted the border by the time the Leave- 
Notif y event arrives with no intervening events, the border will not be highlighted. To see 



234 X Toolkit Intrinsics Programming Manual 



this, move the pointer quickly across a large panel of Command widgets such as in xmh, and 
you will see that not all of them draw and then undraw the border. 

When the compress_exposure filter is set to FALSE, a widget s expose method is 
called repeatedly in response to each Expose event in a contiguous series. Each event 
would normally specify a different rectangle of the widget that needs redrawing. With com- 
press_exposure set to TRUE, however, this contiguous series is compressed into a single 
modified Expose event and the expose method is called only once. This modified 
Expose event contains the bounding rectangle of the union of all the rectangles in the indi 
vidual events. In addition, only when compress_exposure is TRUE is the expose 
method passed an Xlib Region that describes in detail the area exposed. All widgets except 
those that display a large amount of text set this filter to TRUE. Text widgets can very effi 
ciently redraw only the needed parts of the window because each character is in a fixed loca 
tion. (Characters are in fixed locations in the Text widget because it uses fixed-width 
fonts this is not applicable to widgets that display proportional fonts.) 

8.6.3 Input Sensitivity 

There are times when some widgets should be insensitive to events in which they are usually 
interested. For example, a Command widget should be insensitive when the command that it 
executes is invalid because a pop-up widget is in control. 

Widget sensitivity is inherited. For example, if a parent widget is insensitive, then its chil 
dren are too. In other words, an entire box full of widgets can be set insensitive by simply 
setting the box widget insensitive. Note, however, that this process can be a little slow 
because all the widgets in the box that honor sensitivity will redraw themselves dimmed or 
grayed. A widget is made insensitive from an application by calling xtSetSensitive 
with the sensitive argument set to FALSE, or using XtSetValues on the Xt- 
Nsensitive resource (XtSetSensitive is slightly faster). 

Any widget that may need to be disabled for a time by the application should change its visi 
ble appearance when insensitive. 

The widget that has one of the xt Callback* standard pop-up callback functions regis 
tered on its callback list will be set insensitive when the callback is triggered. If the xt- 
CallbackPopdown callback function is registered on this widget it will be set sensitive 
again when this callback is invoked. 



More Input Techniques 23S 



9 



Resource Management 
and Type Conversion 



This chapter is a more thorough discussion of how resources work and how 
they should be used. This chapter describes in detail the resource file format 
and the rules that govern the precedence of resource settings. It also 
describes how to add your own type converter so that you can have applica 
tion or widget-specific data set through resources. Finally, it describes 
subresources and how to use them. 



In This Chapter: 

Review of Resource Fundamentals 239 

How the Resource Database Works 243 

Form of Resource Specifications 243 

Merging of Resource Files 245 

Resource Matching Algorithm 246 

Resource Precedence Rules 249 

Type Conversion 251 

Conversions from XtRString 251 

Other Built-in Type Conversions 254 

Special Resource Defaults That Do Not Use Conversion 255 

Registering Type Converters 257 

Passing Arguments to a Type Converter 259 

Type Converter Caching 260 

Explicitly Invoking a Converter 261 

Writing a Type Converter 262 

Defining the Default Value 264 

Subparts and Subresources 264 

The Hook Methods 265 

Managing Subresources 266 



9 

Resource Management 
and Type Conversion 



This chapter provides a thorough discussion of how resources work and how they should be 
used. First, we describe how to define resources, the complete syntax of resource files, and 
the rules that describe the precedence of one resource setting over another. For the sake of 
completeness, and to make sure that the ideas are presented in context, there is some repeti 
tion of material that has been presented earlier. 

Next, the chapter describes the resource conversions performed automatically by Xt. As you 
may recall from the discussion in Chapter 2, Introduction to the X Toolkit, a value converter 
is invoked by Xt to convert a resource from the string form specified in resource files to the 
representation type actually used in the application or widget For the representation types 
understood by Xt, simply listing the representation symbol (a constant beginning with xtR) 
in the resource list is enough to make Xt automatically perform the conversion. But if you 
create a representation type unknown to Xt, you need to write a type converter routine and 
register it with Xt before the automatic conversion can take place. We discuss both the stan 
dard converters and how to write a new one. 

Finally, the chapter describes a mechanism Xt provides whereby widgets or applications may 
have subparts with separate sets of resources. Special routines are provided for setting and 
getting these resources. This feature is rarely used. However, the R3 Athena Text widget 
uses subparts. It has replaceable units that provide the source or sink for text data. This 
allows the same central code to edit a disk file or a string. 



9.1 Review of Resource Fundamentals 

As we ve previously discussed, widgets and applications can declare some or all of their 
variables as resources. Not every variable need be a resource, only those for which values 
need to be supplied by the user (or for a widget, also by the application programmer) through 
the Resource Manager. Both applications and widgets may use nonresource variables for 
internal bookkeeping, or for storing values calculated or otherwise derived from resources. 

Resources are defined using an Xt Re source structure, which is declared as follows: 



Resource Management and Type Conversion 239 



typedef struct { 

String resource_name; /* specify using XtN symbol */ 

String resource_class; /* specify using XtC symbol */ 

String resource_type; /* actual data type of variable */ 

Cardinal resource_size; /* specify using sizeof () */ 

Cardinal resource_of f set;/* specify using XtOffset () */ 

String default_type; /* will be convrted to resrce_type */ 

caddr_t default_address; /* address of default value */ 

} XtResource, *XtResourceList; 

For example, Example 9-1 shows two of the resources defined by the Athena Label widget 

Example 9-1. Two resources defined by the Athena Label widget 

static XtResource resources [] = { 

XtNforeground, /* Resource name is foreground */ 

XtCForeground, /* Resource class is Foreground */ 

XtRPixel, /* Resource type is Pixel */ 

sizeof (Pixel) , /* allocate enough space to hold a Pixel value */ 

XtOffset (LabelWidget, label . foreground) , /*where in instnce strct*/ 

XtRString, /*Default val is a String (will need conversion) */ 

XtDefaultForeground /* Default address */ 



XtN label, 
XtCLabel, 

XtRString, 

sizeof (String) , 

XtOffset (LabelWidget, label . label) , 

XtRString, 

NULL 



The fields in the XtResource structure are used as follows: 

The resource name is usually similar to the name of the variable being set by the 
resource; by convention, it begins with a lower-case letter, and no underscores are used to 
separate multiple words. Instead, the initial character of subsequent words is given in 
upper case. For example, the resource name for a variable named border_width 
would be backgroundPixel, and the defined constant used to refer to this name 
would be XtNborderWidth. 

As described previously, the name, class, and representation type of resources are speci 
fied in the resource list (and elsewhere in Xt code, but not in user database files) using 
symbolic constants defined in <Xll/StringDefs.h>, and consist of the actual name, class, 
or type preceded by the characters XtN, XtC, or xtR, respectively. Use of these con 
stants provides compile-time checking of resource names, classes, and types. Without the 
constants, a misspelling would not be noticed by the compiler, since resource names, 



240 X Toolkit Intrinsics Programming Manual 



classes, and representation types are simply strings. The misspelling would be considered 
a real resource at run time. Nothing would happen if it were set from the application, 
because no widget would actually use it If, on the other hand, the misspelling were in 
the widget resource list, the application s setting of the intended resource would have no 
effect. 

Newly-defined resources may use a name, class, or type constant defined in <XlllString- 
Defs.h>, if an appropriate one exists. Otherwise, the constant is defined in the widget s 
public header file, or for application resources, in the application itself, or in the applica 
tion header file, if any.) 

For many resources, the class name is simply the same as the resource name, except that 
the XtC prefix is used, and, by convention, the first letter of the name is capitalized. For 
example, the class name constant for the xtNbackgroundPixel resource is xt- 
CBackgroundPixel. However, when appropriate, a single class can be used for a 
group of related resources. This allows a single setting in the resource database to control 
the value of multiple resources. 

For example, a widget can have several elements that use pixel values (i.e., colors) as 
resource settings: background, foreground, border, block cursor, pointer cursor, and so 
on. Typically, the background defaults to white and everything else to black. If the 
background resource has a class of Background, and all the other pixel resources a 
class of Foreground, then a resource file needs only two lines to change all back 
ground pixels to offwhite and all foreground pixels to darkblue: 



*Background: 
*Foreground: 



offwhite 
darkblue 



The representation type of the resource is specified by the resource_type field of the 
resource list, using a symbolic constant prefixed by xtR. Table 9-1 lists the correspon 
dence between the xtR symbols defined by Xt, and actual C data types or X data types 
and structures. 

Table 9-1. Resource Type Strings 



Resource Type 



XtRAcceleratorTable 

XtRBoolean 

XtRBool 

XtRCallback 

XtRColor 

XtRCursor 

XtRDimension 

XtRDisplay 

XtRFile 

XtRFloat 

XtRFont 

XtRFontStruct 

XtRFunction 



Datatype 



Xt Accelerators 

Boolean 

Bool 

XtCallbackList 

XColor 

Cursor 

Dimension 

Display* 

FILE* 

float 

Font 

XFontStruct * 

(*) () 



Resource Management and Type Conversion 



241 




Table 9-1. Resource Type Strings (continued) 



Resource Type 



Datatype 



XtRInt 

XtRPixel 

XtRPixmap 

XtRPointer 

XtRPosition 

XtRShort 

XtRString 

XtRTranslationTable 

XtRUnsignedChar 

XtRWidget 

XtRWindow 



int 

Pixel 

Pixmap 

caddr_t 

Position 

short 

char* 

XtTranslations 

unsigned char 

Widget 

Window 



As we ll discuss in detail in Section 9.3, Xt automatically converts values in the resource 
database (which usually have the type XtRString, since resource files are made up 
entirely of strings) into the target type defined by resource_type. 

The resource_size field is the size of the resource s actual representation in bytes; 
it is normally specified as sizeof ( type) (where type is the C-language type of the 
resource) so that the compiler fills in the value. 

The resource_of f set field is the offset in bytes of the field within the widget 
instance structure or application data structure. The xtOf f set macro is normally used 
to obtain this value. This macro takes as arguments a pointer to the data structure, and 
the name of the structure field to be set by the resource. 

If no value is found in the resource database, the value pointed to by the 
def ault_address field will be used instead. The type of this default value is given 
by the default_type field. If the default_type is different from the 
resource_type, a conversion will be performed automatically in this case as well. 

There are two special resource types that can be used only in the def ault_type. 
xtRimmediate means that the value in the def ault_address field is to be used 
as the actual resource value, rather than as a pointer to it xtRCallProc is a pointer to 
a function that will supply the default value at run time. We ll demonstrate the use of 
these values in Section 9.3.3. 



242 



X Toolkit Intrinsics Programming Manual 



9.2 How the Resource Database Works 

Xt s resource handling is based on the resource manager built into Xlib, but Xt adds a great 
deal. While using the resource manager from Xlib is cumbersome, from Xt it is easy: to use 
resources in existing widgets, all you have to do is write the application-defaults file. 

Xt s handling of resources occurs in two stages: 

1. When the application starts up, with a call to Xtlnitialize, xtApplnitialize, 
orxtToolkitlnitialize.Xt reads the application-defaults file, along with several 
other resource files, command line options, and the RESOURCE_MANAGER property 
stored in the server by the user with xrdb. (Any, all, or none of these may contain data.) 
It merges all these sources of data into one internal database that is used when each 
widget is created. 

2. Whenever you create a widget, the call to xtCreateWidget or xtCreate- 
Managedwidget reads the resource database and automatically sets widget resources 
to the values in the database. In order to explain this stage more clearly, we further 
divide it into two separate steps in the sections that follow. First, Xt compares the set 
tings in the database to the widget s class and instance hierarchy, to find which settings 
apply to the widget being created. Second, Xt decides which of the (possibly conflicting) 
settings that apply to that widget should actually be used. 

If the value of a resource is hardcoded into an ArgList passed as an argument to xt- 
CreateWidget, XtCreateManagedWidget or xtSetValues, the hardcoded 
value overrides the value looked up from the resource database. 

To retrieve the value of application resources from the database, an application must make an 
explicit call to XtGetApplicationResources, as described in Section 3.5.3. 

9.2.1 Form of Resource Specifications 

As discussed in Chapter 2, each entry in the merged database (and in the source databases) is 
a resource specification/value pair. For application resources, the specification is the applica 
tion name followed by a period and the resource name. The value to which the resource is to 
be set follows, after a colon and optional white space.* For example: 

xterm.scrollBar : on 
An asterisk can be used as a "wildcard" in place of the application name. For example: 

*scrollBar: on 

would set a resource named scrollBar to "on" in any application that recognized a 
resource of that name. 



*Note the distinction between what we are calling the resource specification (the fully qualified name of the resource, 
up to the colon), and the value (the actual value to which the resource is to be set). We refer to both the specification 
and the value together as a resource setting. 



Resource Management and Type Conversion 243 




For widget resources, the specification leading up to the resource name may contain a widget 
instance or class hierarchy (or a mixed instance/class hierarchy). Some examples are shown 
below. 

specification value 

I I 

xbitmap . box . quit . label : Quit fully-specified instance hierarchy 

XBitmap .Box. Command. Foreground: blue fully-specified class hierarchy 

XBitmap. Box. quit . foreground: blue mixed class and instance hierarchy 

An instance hierarchy describes the instance names of the widget s ancestors. A class hierar 
chy describes the class names of the widget s ancestors. This portion of the resource specifi 
cation may consist of a mixture of instance names and class names (each of which describes 
one generation in the widget s hierarchy), separated by periods or asterisks. 

A period (.) is referred to as a tight binding. 

An asterisk (*) is referred to as a loose binding. 

A tight binding means that the left component must be the parent of the right component in 
the instance hierarchy. A loose binding means that the left component must only be an 
ancestor of the right component; there can be any number of levels in the hierarchy between 
the two. 

Loose bindings are preferable because they stand a better chance of working when the 
instance hierarchy changes. Tight bindings are rarely necessary at every position in the 
resource specification, since widget names are usually unique and single widgets can be iden 
tified by name. Furthermore, it takes more text to specify the complete instance hierarchy for 
every widget to be set 

Using loose bindings, the instance, class, or instance/class hierarchy may be abbreviated to 
the point where specifying the hierarchy as a single asterisk would indicate that any instance 
or class hierarchy (any widget in the application) will match. 

The resource name must be the string that appears in the resource name or resource class field 
in a resource list. This is the value of the xtN or xtC symbolic constant used in that field of 
the resource list. 

Any entry that is not a resource specification/value pair or does not match any resource for 
any widget in the application or any application resource is quietly ignored (no warning mes 
sage is printed). This means that a slight error in the resource specification of an entry will 
cause that entry to be quietly and completely ignored. It is often difficult to detect such 
errors. 

Lines beginning with an exclamation point (!) are treated as comments. Many people use # 
instead, which is currently supported in MIT s sample implementation of Xt, but is not man 
dated in the Xt specification and therefore may be eliminated in future sample implementa 
tions from MIT or in a vendor s implementation. You are advised to use the exclamation 
point. (Even in the MIT implementation, # elicits warning messages from xrdb.) 



244 X Toolkit Intrinsics Programming Manual 



9.2.2 Merging of Resource Files 

xt initialize, among others, constructs the resource database by consulting the follow 
ing sources of resource settings, in this order: 

1. A file in the directory lusrlliblXlllapp-defaults on the machine running the client. The 
name of this file is the application class (specified in the xt initialize call), usually 
the same as the application name except with the first letter capitalized. If the application 
name begins with x, then the first two letters are capitalized. (This latter convention is 
not always followed.) This is the application-defaults file, intended to be written by the 
application developer. The installation procedure for the application should install this 
file in the correct directory. 

2. Files with the same name as the file in lusrlliblXlllapp-defaults, except in the directory 
named by the shell environment variable XAPPLRESDIR on the system running the client, 
or if the variable is not set, in the user s home directory. This file is intended to be the 
user s, or possibly the site administrator s, customization for the particular application. 
The application developer can also set XAPPLRESDIR so that resource files for an appli 
cation can be in the same directory as the application. (This is particularly useful when 
debugging the application-defaults file.) Note that the value of this variable must end 
with a slash (/).* 

3. Resources loaded into the RESOURCE_MANAGER property of the root window with xrdb. 
Unlike any of the resource files, these resources are accessible regardless of the machine 
on which the client is running. Therefore, xrdb saves you from having to keep track of 
resource files on several different systems. Typically, the user arranges to have xrdb run 
automatically from jcinitrc or its equivalent under xdm, the display manager. This is 
intended to be the method whereby the user specifies server-wide resources (to apply to 
all clients no matter which system they are running on). 

If the RESOURCE_MANAGER property is not set, the resource manager looks for an Xde- 
faults file in the user s home directory. Support for Xdefaults is mostly for compatibility 
with earlier releases of X. (See Volume Three, X Window System User s Guide, for more 
information on using xrdb.) 

4. Next, the contents of any file (on the system running the client) specified by the shell 
environment variable XENVIRONMENT will be loaded. The difference between this and 
APPLRESDIR above is that this is a complete path name including the file name. 

If this variable is not defined, the resource manager looks for a file named Xdefaults- 
hostname (with a hyphen) in the user s home directory, where hostname is the name of 
the host where the client is running. (On systems with a network file system, the home 
directory may be on a system different from the one where the application is running, the 
one where the server is running, or both.) 

*If you break the conventions by giving your program binary a capitalized name, or by giving your application-de 
faults file a lower-case name, it is possible to have the binary accidentally interpreted as an application default file. 
The entire binary will be searched for resource lines! Since the binary is so large, your application will start up very 
slowly. No error will be reported because the resource manager quietly ignores entries it doesn t understand. 



Resource Management and Type Conversion 245 



5. Any values specified on the command line with the -xrm option will be loaded for that 
instance of the program. 

6. If the application has defined any command-line options by passing an options table to 
xtlnitialize, values from the command line will override those specified by any 
other resource settings. 

The order in which these various sources are loaded, as shown in the list above, is the reverse 
order of their priority. That is, those that are loaded first will be overridden by those loaded 
later if an identical specification is found. 

If a widget is created with a resource value hardcoded in an ArgList, that value takes pre 
cedence over the value for that resource in the resource database. If a widget is created and 
no setting exists in the database for a particular resource, the value pointed to by the 
def ault_address field of the resource list is used. This is also true for application 
resources and subresources. 

In practice, few users use more than one or two of these sources of resource settings. 

9.2.3 Resource Matching Algorithm 

When a widget is created, its expanded instance hierarchy and class hierarchy together with 
its resource names and classes are compared to each entry in the merged resource database. 
To demonstrate how matches are made, we ll look at a sample widget hierarchy and follow 
the process of finding the value for one resource of one widget from the merged resource 
database. Figure 9-1 shows the widget instance hierarchy for the quit widget in the xbox 
application shown in Chapter 3, More Widget Programming Techniques. The figure also 
shows the corresponding fully specified instance and class names for the quit widget This 
section describes how this widget s resources are set by the resource manager. 

We know that quit is a Command class widget and therefore that Xt will be searching the 
resource database for each resource in Command s resource list (and the resources in its 
superclasses resource lists). It will search for one resource at a time. To demonstrate the 
conflicts that can occur, we ll use the Core resource xtNbackground, which is common 
to all widgets. It will appear in the resource database as background. 

The matching process can be thought of as a process of elimination. Let s assume the 
merged resource database is as shown in Example 9-2. 



*The actual algorithm used by Xt differs slightly from that described here, because there are shortcuts that the re 
source manager takes that are hard to follow even if you have the source code. However, the algorithm described 
here gives the same result, with more clarity. 



246 X Toolkit Intrinsics Programming Manual 



instance name: xbox 
class name: XBOX 



instance name: box 
class name: BOX 



instance name: quit 
class name: Command 




Fully-specified instance name: 
Fully-specified class name: 



xbox . box . quit 
XBox . Box . Command 



Figure 9-1. The quit widget in a sample widget hierarchy 

Example 9-2. A sample merged resource database 

*box. background: blue (entry 1) 

*background: red (entry 2) 

*quit .background: green (entry 3) 

*quit. label: Quit (entry 4) 

*Command. background: yellow (entry 5) 

* Box. Command, background: violet (entry 6) 

*box*background: pink (entry?) 

xbox. background: orange (entry 8) 

Only resource database entries that specify background as the last element before the 
colon are possible matches. That eliminates entry 4. The fully specified instance and class 
hierarchies are then compared with each possible match, beginning with the first component 
in each hierarchy. 

1. Every entry beginning with the asterisk wildcard binding (*) as well as the one beginning 
with xbox, matches xbox, the first component of the fully specified instance name. All 



Resource Management and Type Conversion 



those beginning with * also match the first component of the fully specified class name, 
XBox. Since entry 8 actually contains the string xbox, the xbox component is removed 
for comparison at the next level. Entry 8 now begins with . background. 

2. The first component of each resource specification (after removal of previously matched 
components) is now compared to the second element in the widget s class and instance 
hierarchies. This should be either box or Box. All the entries that begin with * still 
match, because * matches any number of levels in the hierarchy. However, there is no 
second element in entry 8, once the resource name background is removed. There 
fore, entry 8 is eliminated. Also, since entries 1,6, and 7 actually contain the strings box 
or Box, the leading asterisk and the strings box and Box are removed before compari 
son of the next level. Example 9-3 shows the resource database as it would appear after 
the components and entries eliminated so far. 

Example 9-3. Sample resource database with eliminated entries and components 

.background: blue (entry 1) 

^background: red (entry 2) 

*quit .background: green (entry 3) 

*Command. background: yellow (entry 5) 

. Command. background: violet (entry 6) 

*background: pink (entry?) 

Note that entries 2 and 7 are now duplicates except for the resource value. The resource 
manager actually eliminates one of these entries based upon the levels at which each 
entry matched, whether the instance name or class name matched, whether a tight or 
loose binding was used, and which had more elements specified. These are the prece 
dence rules to be described in the next section. In order to keep the example clearer, 
we ll pretend that the resource manager keeps the information necessary to apply all the 
precedence rules, and keeps all the entries, until the end. 

3. Now the contents of the resource database are compared to the third component in the 
widget s instance and class hierarchies, quit and Command. As usual, anything begin 
ning with an asterisk or anything beginning with a period (.) followed by either the 
expected class or instance name is a match. This matches all but entry 1, which is elim 
inated. 

Before going on to the next comparison, any components that matched specifically (a . or 
* followed by either string) are removed, which results in the resource database shown in 
Example 9-4. 

Example 9-4. Resource database after final elimination of entries and components 

*background: red (entry 2) 

.background: green (entryS) 

.background: yellow (entry 5) 

.background: violet (entry 6) 

*background: pink (entry?) 

Now you see that we are left with only the resource names and tight or loose bindings. The 
matching process is finished, and the precedence analysis begins. The next section describes 
the precedence rules and then finishes this example to determine the priority of the finalist 
entries. 



248 X Toolkit Intrinsics Programming Manual 



9.2.4 Resource Precedence Rules 

Because of the way merging works, no two resource specifications in the merged resource 
database will be alike. (Remember that we are using the term specification for the part of the 
resource setting up to and including the colon.) For example, the merged database could 
never contain both of the following: 

XBitmap*box*background: green 
XBitmap*box*background: red 

because the merging process would remove the setting that appeared earlier in the list of 
database sources. 

However, the database could contain two or more resource settings that apply to the same 
resource of the same widget, because of differences in the widget class or instance hierarchy 
or the bindings. For example, the database could contain: 

XBitmap*box*background: green 
XBitmap*quit .background: red 

If the quit button is a child of box, both settings apply to the quit button s background. 

The resource manager provides a set of rules that govern which setting takes precedence in 
cases where there are two settings for the same resource of the same widget. Here are the 
four rules: 

1. A specification that includes higher components in the instance or class hierarchy takes 
precedence over one that includes only lower ones. 

*topLevel*quit .background: takes precedence over 

* box* quit .background: 

2. Instance names take precedence over class names at the same level in the hierarchy. 

*guit .background: takes precedence over 

*Command . background : 

3. Tight bindings take precedence over loose bindings at the same level in the hierarchy. 

*box . background : takes precedence over 

*box*background : 

4. A name or class that is explicitly stated takes precedence over one that is omitted. 

*box*quit .background: takes precedence over 

*box*background : 

To understand the application of these rules, let s return to our extended example. In the 
course of developing that example, we eliminated information about the level at which com 
ponents occurred. However, the actual process of matching applies the precedence rules at 
each step. As a result, let s start again with the original appearance of the entries that pass 
the matching test. The remaining five as they appeared originally are shown in Example 9-5. 




Resource Management and Type Conversion 249 



Example 9-5. Resource database finalists in original form 

background: red (entry 2) 

*quit .background: green (entry 3) 

^Command, background: yellow (entry 5) 

*Box. Command. background: violet (entry 6) 

*box*background: pink (entry?) 

From here on, we will determine not only which one of these five will take effect, but the 
actual precedence of the five. In other words, once the one with highest precedence is deter 
mined, we ll see which would take effect if that one was commented out, and so on. 

The precedence rules are applied in order to determine the order of the finalist entries. 

1. Rule 1 specifies that a specification that contains higher components in the instance or 
class hierarchy takes precedence over one that contains only lower ones. The highest 
components that appear in our example are box and Box in entries 6 and 7. Therefore, 
these two have higher priority than any others. 

2. To choose between these two, we continue to Rule 2. Instance names (box) take prece 
dence over class names (Box). Therefore, entry 7 has the highest precedence, followed 
by entry 6. Note that the precedence comparison of two finalists proceeds in the same 
manner as the original matching from left to right in the entry, one component at a 
time. 

3. To determine the precedence of the remaining three entries, 2, 3, and 5, we begin again 
with Rule 1. However, Rule 1 does not apply because no two entries here specify differ 
ent levels in the hierarchy. Entries 3 and 5 contain the quit level and entry 2 nothing 
(an asterisk does not count for Rule 1 because it is not a specified level it is any level). 
Rule 2 specifies that the instance name quit takes precedence over the class name 
Command, and therefore entry 3 has higher priority than entry 5. Rule 3 does not apply, 
because no two entries are identical except for binding. Because of Rule 4 we know that 
both entries 3 and 5 are higher priority than entry 2, because 3 and 5 state a name or class 
that is omitted in 2. 

Therefore, the final precedence is as shown here: 

1. *box*background: pink (entry?) 

2. *Box. Command, background: violet (entry 6) 

3. *quit .background: green (entry 3) 

4. *Command. background: yellow (entry 5) 

5. *background: red (entry 2) 

Rules 2, 3, and 4 are fairly easy to understand and apply, but many people forget or are con 
fused by Rule 1. People get used to the fact that they can set the resources of all the children 
of box with something like entry 7, but then are shocked to find that nothing happens when 
they attempt to override entry 7 with entry 3 entry 3 seems more specific to them. Even the 
following entry (using a class name) takes precedence over entry 3 because the rule about 
being higher in the widget hierarchy carries more weight than the rule that instance names 
take precedence over class names: 

*Box*background: pink (entry?) 

The moral of this story is that there is only one way to be sure you are setting a particular 
resource of a particular widget in such a way as to override all other settings that might apply 



250 X Toolkit Intrinsics Programming Manual 



to that resource: you must specify all the levels in the instance hierarchy, with tight bindings 
between each component. (But of course, this will not work when another resource file that 
is merged later also specifies the same resource and all components of the same widget with 
the instance hierarchy separated by tight bindings.) Since there are no messages telling you 
which resource specifications are actually being used, you can be tricked into thinking that 
you have set resources that you actually haven t. Using only tight bindings in the applica 
tion-defaults file, while more trouble initially, is probably wise in the long run. 

Figure 9-2 illustrates the entire process of resource matching. 



9.3 Type Conversion 

You already know that Xt is capable of converting resource values from the string representa 
tion specified in resource files to the actual type required in code. In fact, Xt does so auto 
matically if the resource list is properly written. This section describes this process in more 
detail, and tells you how to create converters for converting your own data types. 

9.3.1 Conversions from XtRString 

The primary purpose of converters is to allow resource files to contain string values for non- 
string program variables. (They are also used internally to convert default values that cannot 
be specified easily in the desired data type.) Secondly, converters confine the details of data 
conversion to a single routine that is registered with Xt. This is a big benefit because users of 
the converted types need not know the details of how the conversion takes place, or the inter 
nal definition of the target type. 

Xt provides converters from XtRString to the representation types listed in Table 9-2. 
These are the representation types that you can use as target types in resource lists in applica 
tions or widgets, without having to register them or do anything else, if you want the user to 
be able to specify the resource in a resource file. 



Resource Management and Type Conversion 251 




Select entries from resource data base whose last 
element is the background resource being set. 



>/ 

Determine fully-specified class and instance name for 
widget. 



4- 

Compare first element of each entry to first element of full 
class and instance name, xbox and xBox . 



xclock . background : 

*Box . Command . background : 

*box*background: 

xbO3C . background : 




yellow 

violet 

pink 

orange 



Eliminate entries that don t match and eliminate 
matching elements that specify the instance or class 
name, xbox is removed. 

*Box .Command. background: violet 
*box*background: pink 

.background: orange 




Loop back to LzJ , comparing first element of each entry 
(after removal of matching elements) to second element of 
full class and instance name, box and BOX . 
Repeat using each level in full class or instance hierarchy 
until database consists of tight or loose bindings and 
resource names only. 



Using original form of remaining database entries, apply 
precedence rules. 



Figure 9-2. Steps in matching resource entries for one resource of widget being created 



252 



X Toolkit Intrinsics Programming Manual 



Table 9-2. Built-in Type Converters from XtRString 



Target Type 



Description of Converter 



XtRAcceleratorTable 



XtRBoolean 

XtRBool 
XtRCursor 
XtRDimension 
XtRDisplay 

XtRFile 

XtRFloat 

XtRFont 



XtRFontStruct 



XtRInt 
XtRPixel 



XtRPosition 

XtRShort 

XtRTranslationTable 

XtRUnsignedChar 



Compiles a string accelerator table into internal accelerator 
table format (no need to call XtParseAccelerator- 
Table). 

Converts strings "true," "false," "yes," "no," "on," "off to cor 
responding Boolean value (case insensitive). 
Same as for XtRBoolean. 
Given a standard X cursor name, returns a cursor ID. 
Converts a width or height value to a Dimension. 
Given a display name, opens the display and returns a Dis 
play structure. 

Given a filename, opens the file and returns the file descriptor. 
Converts a numeric string to floating point 
Given a font name, loads the font (if it is not already loaded), 
and returns the font ID. See Appendix C, Specifying Fonts 
and Colors, for more information on legal values. The value 
xtDef aultFont will return the default font for the screen. 
Given a font name, loads the font (if it is not already loaded), 
and returns a pointer to the Font Struct containing font 
metrics. The value XtDef aultFont will return the default 
font for the screen. 

Converts a numeric string to an integer. 
Converts a color name string (e.g., "red" or "#FFOOOO") into 
the pixel value that will produce the closest color possible on 
the hardware. See Appendix C, Specifying Fonts and Colors, 
for more information on legal values. The two values xtDe- 
faultBackground and XtDefaultForeground are 
always guaranteed to exist, and to contrast, on any server. 
Converts an x or y value to a Position. 
Converts a numeric string to a short integer. 
Compiles string translation table into internal translation table 
format (no need to call XtParseTranslationTable). 
Converts a string to an unsigned char. 



If there is no converter from XtRString to a particular resource type, it may not be pos 
sible to specify that resource type in a resource file. For example, there is no converter for 
xtRCallback since it would be meaningless to specify a function in a resource file. The 
proper way to set a callback resource is with xtAddCallback or a static callback list 
declared in the application. 

Some converters that are widely needed, however, are not provided by Xt. For example, 
many applications need a converter from a filename (string) to a pixmap suitable for use as 
an icon or background pximap. Fortunately, the Xmu library contains several commonly 



Resource Management and Type Conversion 



253 



used converters. Even though Xmu (like Xaw) is not part of the X Consortium standard, it is 
part of MIT s core distribution and is available on most systems. 

However, because the Xmu converters are not built into Xt, you need to register them with a 
call to xtAddConverter before using them in an application or widget (We ll describe 
the converters and show how to register them in Section 9.3.4.) 



9.3.2 Other Built-in Type Conversions 

While the conversions from xtRString are the most widely used, because they allow a 
resource to be specified from a resource file, there are also a number of built-in converters 
between other data types, for use internally within Toolkit programs. 

Most commonly, these converters are used to convert between the resource_type and 
def ault_type fields of a resource definition. 

Table 9-3 lists those converters automatically recognized by Xt. 
Table 9-3. Other Built-in Converters 



From 


To 


Description of Converter 


XtRColor 


XtRPixel 


Converts an XGolor structure to a pixel value. 


XtRPixel 


XtRColor 


Converts a pixel value to an XGolor structure. 


XtRInt 


XtRBoolean 


Converts an int to a Boolean. 




XtRBool 


Converts an int to a Boolean. 




XtRColor 


Converts an int to an XColor. 




XtRDimension 


Converts an int to a Dimension. 




XtRFloat 


Converts an int to a float. 




XtRFont 


Converts an int to a Font. 




XtRPixel 


Converts an int to a pixel value. 




XtRPixmap 


Converts an int to a Pixmap. 




XtRPosition 


Converts an int to a Position. 




XtRShort 


Converts an int to a short. 




XtRUnsignedChar 


Converts an int to an unsigned char. 



For example, the Core resource xtNborderPixmap has its default value set as shown in 
Example 9-6. 

Example 9-6. A resource definition converting an int to a pixmap 
static XtResource resources!] = { 



XtNborderPixmap, 

XtCPixmap, 

XtRPixmap, 



254 



X Toolkit Intrinsics Programming Manual 



Example 9-6. A resource definition converting an int to a pixmap (continued) 

sizeof (Pixmap) , 

XtOffset (WindowObj, win_obj .border_pixmap) , 
XtRInt, 
(caddr_t) &XtUnspecif iedPixmap 



The specified default value xtUnspec if iedPixmap is an integer defined to have a value 
that does not equal the constant CopyFromParent or any valid Pixmap ID. The ini 
tialize method for the Core widget class checks for this value, and does not set the 
background window attribute unless the application or a resource file has set the Xt- 
Nborder Pixmap resource to some value other than the default. 



9.3.3 Special Resource Defaults That Do Not Use Conversion 

There are two special values, xtRlmmediate and xtRCallProc that can be used only 
in the def ault_type field of a resource definition. These values require no type conver 
sion. The value provided in the def ault_address field must be of the correct type. 

The type XtRlmmediate means that the value in the def ault_address field is the 
default value itself, not its address. 

In Example 9-7, the value in the def ault_address field of the xtNheight resource 
definition is the actual default in this case, zero. 

Example 9-7. A resource definition using XtRlmmediate 

static XtResource resources [] = { 



XtNheight, 
XtCHeight, 
XtRD intension, 
sizeof (Dimension) , 

XtOffset (RectObj, rectangle .height ) , 
XtRlmmediate, 
(caddr_t) 



Resource Management and Type Conversion 255 




The type xtRCallProc means that the value in the default_address field is the 
name of a function. This function is of type xtResourceDefaultProc, and it is 
expected to retrieve the desired default value at run time.* When the widget instance is 
created, the function is automatically invoked with these parameters: the widget ID, the 
resource offset, and a pointer to the XrmValve in which to store the result. The function 
should fill in the addr field of the XrmValue with a pointer to the default data in its cor 
rect type. 

In Example 9-8, the value in the def ault_address field of the xtNscreen resource 
definition is the name of a function that will retrieve the screen on which the widget is 
displayed. 

Example 9-8. A resource definition using XtRCallProc 

static XtResource resources [] = { 



XtNscreen, 

XtCScreen, 

XtRPointer, 

sizeof (int) , 

XtOf f set (WindowOb j, win_ob j . screen) 

XtRCallProc, 

(caddr_t) XtCopyScreen 



Example 9-9 shows an example of an XtResourceDefaultProc. 
Example 9-9. An example of an XtResourceDefaultProc 

/*ARGSUSED*/ 

void XtCopyScreen (widget, offset, value) 

Widget widget; 

int offset; 

XrmValue *value; 
{ 

value->addr = (caddr_t) (&widget->core .screen) ; 



*The def ault_address field in the resource structure is declared in R3 as a caddr_t. On some machine ar 
chitectures, this type may be too small to hold procedure variables. In R4, all caddr_t fields have been changed to 
type XtPo inter, so that architectures with large pointers can redefine this type. 



256 X Toolkit Intrinsics Programming Manual 



9.3.4 Registering Type Converters 



As noted earlier, not every resource type symbol defined in StringDefs.h is supported by a 
built-in converter, though the Xmu library does provide some of the most important missing 
converters. In addition, you can define your own resource types, and write converter routines 
to convert from a string representation in a resource file to the appropriate data type. 

Table 9-4 lists the converters from XtRString provided by the Xmu library. 
Table 9-4. Xmu Converters 



From 


To 


Description of Converter 


XtRString 


XtRBackingStore 


The XmuCvtStringToBackingStore converter 






converts the strings "NotUseful," "WhenMapped," and 






"Always" (in any case) into the corresponding con 






stants (in proper case) for use in setting the 






backing store window attribute. (See Volume 






One, Xlib Programming Manual, for details on 






backing store.) 




XtRCursor 


The XmuCvtStringToCursor converter converts 






one of the standard cursor names (from <Xlllcursor- 






font.h\ a font name and glyph index of the form 






"FONT fontname index [[font] index]", or a bitmap 






file name as in XtRPixmap below, and converts it to 






anX Cursor. 




XtRJustify 


The XmuCvtStringToJustify converter con 






verts the strings "right," "left," or "center," in any case, 






to an enumeration constant suitable for use by a justify 






resource. This converter is used by the Athena Label 






widget. 




XtROrientation 


The XmuCvtStringToOrientation converter 






converts the strings "horizontal," or "vertical," in any 






case, to an enumeration constant suitable for use by an 






orientation resource. This converter is used by the 






Athena Scroll widget. 




XtRPixmap 


Given a string representing a filename in standard XI 1 






bitmap file format, the XmuCvtStringToPixmap 






converter creates a depth- 1 pixmap suitable for win 






dow manager icons or for tiling a window background 






or border. The filename may be an absolute pathname, 






or may be relative to a pathname specified in the glo 






bal resource bitmapFilePath, class Bitmap- 






FilePath. If the resource is not defined, its default 






value is the directory lusrlliblXl I/bitmaps. 




Resource Management and Type Conversion 



257 



Table 9-4. Xmu Converters (continued) 



From 



To 



Description of Converter 



XtRWidget 



XtRFunction 



XtRCallback 



The XmuCvtStringToWidget converter converts 
a widget name into the corresponding widget ID. This 
is commonly done to specify the relative positions of 
the children of constraint widgets, as in the Athena 
Form widget resources fromHoriz and from- 
Vert. 

Converts a function pointer to a callback list contain 
ing that function. 



Whether defined in Xmu or in your own program, a converter other than those built into Xt 
must be registered with a call to xtAddConverter before a resource list is used that ref 
erences the converted types. Resource lists are used when widgets are created or when the 
application calls xtGetApplicationResources. In the application, a converter must 
be registered after Xt Initialize but before XtGetApplicationResources. 

Within a widget, the class_initialize method is the standard place to register type 
converters. This method is responsible for doing processing that should be done only once 
when the first instance of a particular class is created. 

Example 9-10 shows the code needed to register the XmuCvtSt ringTo Just if y conver 
ter in a widget As noted above, this converter would be used for a resource (such as the 
Athena Label widget s label resource) designed to give the user the option of justifying 
text (or a graphic object) to the right, left, or center of a widget* 

Example 9-10. Registering a type converter 

static void 
Classlnitialize () 



XtAddConverter (XtRString, /* source type */ 
XtRJustify, /* target type */ 

XmuCvtStringTo Justify, /* converter routine 
NULL, 
0); 



/* args for converter routine */ 
/* I args for converter routine */ 



The first two arguments of XtAddConverter are the source and target type, respectively, 
specified using xtR symbolic constants defined in <Xll/StringDefs.h> (or defined in an 
application header file or the widget public header file if the type is not standard in Xt). 



*While it may seem a little backwards to describe how to add a converter before we say how to write one, the avail 
ability of the Xmu converters makes it likely that you would in fact want to add converters you haven t written. 



258 



X Toolkit Intrinsics Programming Manual 



The third argument is the name of the converter routine, which by convention contains the 
string Cvt. The Xmu converters all add the prefix Xmu. 

The fourth and fifth arguments of xtAddConverter are an argument list that will be 
passed to the converter routine when it is called. Some converter routines require informa 
tion about the context in which the converter is called. This is usually passed in via an xt- 
ConvertArgRec structure, as described in the next section. If no arguments are needed, 
the fourth and fifth arguments of XtAddConverter can be NULL. 

9.3.4.1 Passing Arguments to a Type Converter 

A few type converters need additional arguments. For example, XmuCvtString- 
Towidget needs to be passed the parent of the current widget in the application, so that it 
can compare the name specified in the resource to the names of the children of the passed 
parent Example 9-11 shows the code used by the Athena Form widget to register the Xmu 
string-to-widget converter. 

Example 9-11. Adding a converter with arguments 

static void Classlnitialize () 
{ 

static XtConvertArgRec parentCvtArgs [ ] = { 
{ 

XtBaseOffset, 

(caddr_t) XtOf f set (Widget, core .parent) , 
sizeof (Widget) 



XtAddConverter (XtRString, 
XtRWidget, 

XmuCvtStringToWidget, 
parentCvtArgs, 
XtNumber (parentCvtArgs) ) ; 
} 

The format of the argument list for XtAddConverter shown in Example 9-12 looks com 
plicated, but in practice almost all converter argument lists will look very similar to the one 
in this example. The argument list is specified as an XtConvertArgRec: 

typedef struct { 

XtAddressMode address_mode; 

caddr_t address_id; 

Cardinal size; 
} XtConvertArgRec, *XtConvertArgList ; 

The address_mode field specifies how the address_id field should be interpreted. 
The size field specifies the length of the data in bytes. 

By specifying the address mode as XtBaseOffset (see below), you can use XtOf f set 
to find the appropriate widget resource, much as you do in an ArgList. All you have to do 
is change the name of the instance structure field (in this case core . parent), and the type 



Resource Management and Type Conversion 259 




of that field (in this case widget). Note that the type appears twice, as an argument to both 
xtOf f set and sizeof . 

The enumerated type XtAddressMode <XUIConvert.h>) specifies the possible values for 
the address_mode field: 

typedef enum { 

/* address mode parameter representation */ 

XtAddress, /* address */ 

XtBaseOffset, /* offset */ 

Xtlmmediate, /* constant */ 

XtResourceString, /* resource name string */ 

XtResourceQuark /* resource name quark */ 

} XtAddressMode; 

XtAddress causes address_id to be interpreted as the address of the data. 

XtBaseOffset causes address_id to be interpreted as the offset from the widget 
base address. 

Xt Immediate causes address_id to be interpreted as a constant. 

XtResourceString causes address_id to be interpreted as the name of a 
resource that is to be converted into an offset from the widget base address. 

XtResourceQuark causes address_id to be interpreted as a quark that is, as an 
internal compiled form of an XtResourceString. 

In most cases, you will use XtBaseOffset, as shown in Example 9-11. 

When registering a type converter in an application rather than a widget, the structure field 
specified in the argument list shown in the example would be a field of the AppData struc 
ture instead of the instance part structure, and widget would be replaced by AppData. 

If any conversion arguments of type XtBaseOffset, XtResourceString, Xt 
ResourceQuark and xtwidgetBaseOf f set are specified for conversions performed 
by XtGetApplicationResources, XtGetSubresources, XtVaGet- 
ApplicationResources or xtVaGetSubresources, the arguments are computed 
with respect to the specified widget, not the base address or resource list specified in the call. 

9.3.4.2 Type Converter Caching 

Some type conversions are computationally expensive or require a round-trip request to the 
server. Xt caches the data returned from these conversions so that a subsequent conversion 
of the same source data can be satisfied immediately without invoking the converter routine 
at all. In other words, each converter routine is not responsible for caching its own returned 
data. 

Xt caches the results of only those built-in converters that it is necessary to cache. However, 
it caches the results of all non-built-in converters registered with XtAddConverter. 



260 X Toolkit Intrinsics Programming Manual 



9.3.5 Explicitly Invoking a Converter 

Converters are normally invoked by Xt because the types they convert are specified in a 
resource list. But this is not the only way in which converters can be invoked. It is possible 
to manually invoke type converters using Xt Convert. Converter routines can themselves 
invoke other converters directly. 

One possible manual use of type converter routines is in the processing of the string parame 
ters passed to action routines. Perhaps in the action routine itself it is more convenient to 
have some parameters converted to another form. For example, if an action is passed the 
string TRUE," the action code might prefer to convert this parameter to a Boolean value. 
The CvtStringToBoolean converter understands many strings that would be inter 
preted as Boolean, such as "Off," "On," "TRUE," "FALSE," "No," and "Yes," in upper, 
lower, or mixed case. It saves code to use the converter rather than comparing a string to all 
these strings in your own code. Example 9-12 shows an action routine of the Athena Text 
widget in which a converter is manually invoked. 

Example 9-12. Manually invoking a type converter 

static void 

DisplayCaret (w r event, params, num_params) 

Widget w; 

XEvent *event; /* CrossingNotify special-cased */ 

String *params; /* Off, FALSE, No, On, TRUE, Yes, etc. */ 

Cardinal *num_params; /* 0, Ior2*/ 



if (*num_params > 0) { /* default arg is "TRUE" */ 
XrmValue from, to; 

from. size = strlen (from. addr = params [0]); 
XtConvert(w, XtRString, &from, XtRBoolean, &to) ; 
if (to. addr != NULL) 

if (* (Boolean*)to.addr) { 

; /* parameter has boolean value, do something here */ 



Note that the from and to arguments of Xt Convert are pointers to structures containing 
length/pointer pairs they are not values. The actual data is passed as a pointer to a pointer. 
Thus the cast to Boolean references the pointer twice. 

The widget argument of Xt Con vert is used internally by Xt as the argument for xt- 
Di splay, to get the pointer to the display structure, and for other purposes. In normal 
applications you can pass any widget here. (For some converters, the widget may need to be 
realized.) 

xtConvert calls a lower-level routine called XtDirectConvert. If you prefer, you 
can use this routine. Instead of passing it the widget and the source and destination type, you 
pass it the name of the conversion routine, and any arguments to the routine. See Volume 
Five, X Toolkit Intrinsics Reference Manual, for details. 



Resource Management and Type Conversion 261 




9.3.6 Writing a Type Converter 

If your application or widget has a data type that you would like the user to be able to set 
through resource files, you will need to write (and register) a type converter from xt- 
RString to your type. 

The first step in creating a converter is to decide upon the characteristics of the string you 
will be converting from, and the C-language type you will be converting to. Then you can 
copy an existing similar converter and fill in the code to convert to your desired type. 
Example 9-13 shows the converter added by the Athena Form widget to convert the "edge 
type" values for its xtNright, xtNlef t, and xtNtop resources. 

This is a good example of the type of converter you are most likely to write. It allows the 
legal values for the desired constants to be provided in either case, and uses the Xlib quark 
mechanism to speed string comparison. Type converters (and the Xt and Xlib resource man 
agement facilities in general) use quarks extensively to speed string comparisons. A quark is 
a unique ID for a string, of type XrmQuark (defined by Xlib). A call to the Xlib routine 
XrmStringToQuark returns the quark for a string. See Volume Two, Xlib Reference 
Manual, for details. When a nonstandard type converter that uses quarks is defined and reg 
istered in widget code, the XrmStringToQuark calls are normally placed in the 
class_initialize method just before the xtAddConverter call. 

Example 9-13. The XtRString to XtREdgeType type converter 

/* This macro or something like it used by many resource converters 
tdef ine done (address, type) \ 

{ toVal->size = sizeof (type) ; \ 

toVal->addr = (caddr_t) address; \ 
return; \ 



/* This utility routine used by many converters */ 

void LowerCase (source, dest) 

register char *source, *dest; 
{ 

register char ch; 

for (; (ch = *source) != 0; source++, dest++) { 
if ( A <= ch && ch <= Z ) 
*dest = ch - A + a ; 
else 

*dest = ch; 
} 
*dest = 0; 



/* Quarks used to speed string comparisons */ 

static XrmQuark XtQChainLeft, XtQChainRight, XtQChainTop, 
XtQChainBottom, XtQRubber; 



262 X Toolkit Intrinsics Programming Manual 



Example 9-13. The XtRString to XtREdgeType type converter (continued) 

/* The converter itself */ 

/*ARGSUSED*/ 

static void _CvtStringToEdgeType (args, num_args, fromVal, toVal) 

XrmValuePtr args; /* unused */ 

Cardinal *num_args; /* unused */ 

XrmValuePtr fromVal; 

XrmValuePtr toVal; 
{ 

static XtEdgeType edgeType; 

XrmQuark q; 

char lowerName [1000] ; 

Lowercase ( (char*) f romVal->addr, lowerName) ; 
q = XrmSt ringToQuark ( lowerName ); 
if (q == XtQChainLeft) { 

edgeType = XtChainLeft; 

done (fiedgeType, XtEdgeType) ; 
} 
if (q == XtQChainRight) { 

edgeType = XtChainRight; 

done (SedgeType, XtEdgeType); 
} 
if (q == XtQChainTop) { 

edgeType = XtChainTop; 

done (SedgeType, XtEdgeType) ; 
} 
if (q == XtQChainBottom) { 

edgeType = XtChainBottom; 

done (& edgeType, XtEdgeType) ; 
} 
if (q == XtQRubber) { 

edgeType = XtRubber; 

done ( & edgeType , XtEdgeType ) ; 
} 

XtStringConversionWarning(fromVal->addr, "XtREdgeType") ; 
toVal->addr = NULL; 
toVal->size = 0; 
} 

Notice that the XrmValuePtr arguments passed into the converter are pointers to struc 
tures, not values. The XrmValue structure contains an address field and a size field. 

XtStringConversionWarning takes as arguments the string that could not be con 
verted, and the type to which it could not be converted, and issues a warning message with 
name conversionError, type string, class XtToolkitError, and the default 
message string "Cannot convert "src" to type dst_type." (See Chapter 13, Miscella 
neous Toolkit Programming Techniques, for more information on error and warning mes 
sages.) 



Resource Management and Type Conversion 263 




9.3.6.1 Defining the Default Value 

When performing conversions, such as from strings to fonts or colors, for which there is no 
string representation that all server implementations will necessarily recognize, a type con 
verter should define some set of conversion values that the converter is guaranteed to succeed 
on, so that these can be used as resource defaults. 

For example, the default string-to-pixel converter recognizes the symbols xt Default- 
Foreground and XtDef aultBaclcground. As part of its conversion, it tests for these 
values, and establishes the appropriate value based on the string value. The code is shown in 
Example 9- 14. 

Example 9- 14. Testing for a special-case default value 

if (Compare I SOLat in 1 (str, XtDefaultBackground) == 0) { 
*closure_ret = FALSE; 

if (pd->rv) done (Pixel, BlackPixelOf Screen (screen) ) 
else done (Pixel, WhitePixelOf Screen (screen) ); 
} 
11 if (ComparelSOLatinl (str, XtDefaultForeground) == 0) { 

*closure_ret = FALSE; 

|1 if (pd->rv) done (Pixel, WhitePixelOf Screen (screen) ) 
else done (Pixel, BlackPixelOfScreen (screen) ); 

111: } 



9.4 Subparts and Subresources 

A subpart is a section of a widget that is replaceable but that cannot operate independently. 
It is just a further subdivision of the widget object into smaller pieces. 

Subresources allow subparts of a widget to have separate sets of resources. Since the Athena 
Text widget is the only example of the use of Subresources in MIT s Core distribution as of 
Release 3, we ll describe how it uses subparts and Subresources so you can understand the 
motivation behind them. 

The Text widget has three parts: the source, the sink, and the coordinator widget The source 
manages the storage of data and the sink manages how it is displayed. The coordinator is the 
central widget that manages the communication between the source and the sink, and is inop 
erable without them. Both the source and the sink are replaceable pieces of code. Xaw pro 
vides only one source, which edits a string or disk file, and only one sink, which displays text 
in one color and in one font. The idea of providing the subparts in the first place is that they 
would allow enhancements to be made without changing the basic editor functionality that is 
in the coordinator. For example, only the source and sink would need replacing in order to 
implement a multifont and/or multicolor text widget 

Each subpart has its own resource list so that it truly can be replaced without any modifica 
tions to the central widget These are the Subresources. 



264 X Toolkit Intrinsics Programming Manual 



The Hook Methods 

The initialize_hook, set_values_hook and get_values_hook methods are 
used by widgets that have subparts. They have the same function as their nonhook counter 
parts, except that they process only the resources of a subpart, and any subpart instance fields 
that depend on the subpart resources. These methods are called immediately after their 
nonhook counterparts. 

The hook methods are called with different arguments than their nonhook counterparts. They 
are passed a single copy of the widget instance structure (the new copy already modified in 
the nonhook methods), and the argument list passed to the Xt routine that triggered the 
method. The set_values_hook and get_values_hook methods simply take this 
widget ID and argument list and pass them to xtSetSubvalues or xtGetSubvalues 
respectively. The initialize_hook method uses the contents of the argument list to 
validate resource settings for subparts and set nonresource subpart data. 

As of Release 4, the initialize_hook and set_values_hook methods are still 
called for backwards compatibility but are obsolete because the same information (the argu 
ment lists) has been added as arguments to the initialize and set_values methods. 
However, get_values_hook is still necessary. Example 9-15 shows the get_val- 
ues_hook for the AsciiSrc subpart of the Text widget (somewhat simplified to show the 
essential elements). 

Example 9- 15. Simplified get_values_hook method of the AsciiSrc subpart of the Text widget 

static void 

GetValuesHook (src, args, num_args) 

XawTextSource src; 

ArgList args; 

Cardinal * num_args; 



XtGetSubvalues ( (caddr_t) src, 
sour ceRe sources, 
XtNumber (sourceResources) , 
args, 

*num_args) ; 
} 

The set_values__hook method is similar to the set_values method, except that it is 
passed only the current widget instance structure and the arglist, instead of the old and new 
copies of the widget instance structure which are passed to set_values. As a result, 
set_values_hook needs to use a different technique for comparing the current 
subresource values with the values set by xt Setvalues. 

There are two ways to do this. One is to loop through the widget s resource list, using 
strcmp to compare each resource name in the argument list with the subresource names, 
and then comparing each argument value with the current value of the subresource. 



Resource Management and Type Conversion 265 




The other way is to copy the instance structure passed in using bcopy (after allocating 
memory for the new copy with xtNew, described in Chapter 13, Miscellaneous Toolkit Pro 
gramming Techniques). Then call xtSetSubvalues to set the actual values to those in 
the argument list. After this process, you can compare the old and new values the same way 
this is done in the set values method. 



9.4.2 Managing Subresources 

Managing subresources is very similar to managing application resources. Like the applica 
tion, the subpart must have a structure containing the fields to set through resources. In the 
application you call xtGetApplicationResources to set these fields. In a subpart 
the analogous call is xt Get Subresources, which is called from the 
initialize_hook method. 

Like widgets, the resources of subparts can be queried and set manually. xtGet- 
Subvalues queries the values, and XtSetSubvalues sets them. However, because 
subvalues are not part of any widget, these calls cannot identify what object is being queried 
or set simply by passing the widget ID. These calls have different arguments than xtSet- 
Values and xtGetValues. Instead of the widget ID, you pass the pointer to the data 
structure, the resource list, and the number of resources. Therefore, XtSetSubvalues 
and xtGetSubvalues can be invoked only from within the widget or subpart. Actually, 
all these routine do is set or get the value in the specified structure. 

Any application using the widget will use XtSetValues and XtGetValues as for nor 
mal resources, specifying only the coordinating widget as the first argument These calls are 
translated into XtSetSubvalues and XtGetSubvalues calls by the 
set_values_hook and get_values_hook methods. These methods are passed the 
arguments from the XtSetValues or XtGetValues calls and translate them into Xt 
SetSubvalues or XtGetSubvalues calls by adding the data structure and resource 
list arguments. But in addition, the set_values_hook method is responsible for validat 
ing the resource settings passed in before it calls XtSetSubvalues, and for changing any 
nonresource subpart structure fields like GCs that depend on resources. 



266 X Toolkit Intrinsics Programming Manual 



10 



Interclient Communications 



This chapter discusses communication through the X server between an appli 
cation and the window manager, and between two applications. The applica 
tion-window manager communication is performed by code in the Shell 
widget. The application sets shell resources to control this communication 
with the window manager. Application-application communication is usually 
done with a process called selections. This form of communication is already 
implemented in most widgets that display text, but you may want to implement 
it in your own custom widgets. Selections can also pass other kinds of data 
such as graphics. 

In This Chapter: 

Window Manager Interactions 270 

Shell Subclasses 270 

Setting Shell Resources 271 

Screen Space 273 

Input Model 274 

Colormaps 276 

Icons 277 

Window Manager Decorations 279 

Selections: Widget-To-Widget Communication 280 

How Selection Works 281 

Highlighting the Selected Data (Owner) 284 

Making the Selection with XtOwnSelection (Owner) 288 

Requesting the Selection (Requestor) 289 

Possible Target Type Atoms 290 

The Paste Action from BitmapEdit 292 

Converting the Selection (Owner) 293 

Finally Pasting the Selection (Requestor) 295 



If the Selection is Lost (Owner) 297 

When the Selection Transfer is Complete (Owner) 297 

ICCCM Compliance 298 

Xmu Atom Caching 299 

Converting the Standard Selections 300 

The Clipboard Selection 301 

Miscellaneous Selection Routines .. .. 302 



10 

Interclient Communications 




Applications share the server with other clients. Server resources, such as screen space and 
colormaps, must be used in a responsible, consistent manner so that applications can work 
effectively together. In most window systems, the window system itself embodies a set of 
rules for application interaction. However, the X protocol, Xlib, and Xt were all specifically 
designed to avoid arbitrary conventions, so that they provide "mechanism, not policy." 

Instead, the conventions covering interclient communication are described in a separate doc 
ument, adopted as an X Consortium standard in July, 1989, called the Inter-Client Commu 
nication Conventions Manual (ICCCM). This chapter will not fully describe the ICCCM, 
because the job of implementing its rules is given over to a special client called the window 
manager and a special widget class called Shell.* As a result the details of the ICCCM are, 
for the most part, irrelevant to the application writer s needs. 

In X Toolkit programs, the Shell widget returned by xtlnitialize and used as the top- 
level window of the application automatically handles most of the required interactions with 
the window manager. However, the Shell widget needs additional information in certain 
areas. For example, the application needs to provide an icon pixmap so that the window 
manager can iconify it properly. The first section in this chapter describes how to set Shell 
resources to control how an application interacts with the window manager. This portion of 
the chapter is for application writers, regardless of whether you need to write widgets for 
your application. 

In X Toolkit applications, widgets can communicate with other widgets using a mechanism 
called selections, which in turn is based on an X mechanism for common storage called pro 
perties. Whether the widgets involved in transferring selections are part of the same applica 
tion or different applications is irrelevant. The communication between widgets takes place 
without input from the application. However, it can be used as a means of communication 
between applications. The second major section in this chapter will describe these concepts 
and how to implement selections between your own custom widgets. Only if your applica 
tion requires a custom widget that must communicate with other widgets should you actually 
have to write this code. Thus, this part of the chapter is primarily for widget writers. 



*If you do need to look up certain details of the ICCCM, see Appendix F, Interclient Communication Conventions, in 
a version of Volume One, Xlib Programming Manual, printed on or after February, 1990 (the conventions have 
changed since earlier versions of Volume One). The ICCCM is also included in troff source form in the standard X 
distribution from MIT. 



Interclient Communications 269 



10.1 Window Manager Interactions 

The window manager was introduced in Chapter I, Introduction to the X Window System, but 
little mention of it has been made since then. You may recall that the window manager is just 
another client running on a server, except that it is given special authority to manage screen 
space and other limited server resources like colormaps.* To let the window manager do a 
better job of mediating competing demands of the various clients, each client gives the win 
dow manager information called window manager hints. These hints specify what resources 
each client would like to have, but they are only hints; the window manager is not obligated 
to honor them, and the client must not depend on them being honored. 

Application code has little to do to interact properly with the window manager. The Shell 
widget returned by xt Initialize takes care of setting the essential window manager 
hints. However, there are a number of optional window manager hints that the application 
may wish to have passed to the window manager. This is done mainly by setting resources of 
the Shell widget Also, there are variations in window managers and it takes some effort to 
make some applications work equally well under all of them. 

The next few sections describe the various resources of the Shell widget, including how and 
when they should be set Because the Shell widget is part of the Xt standard, these resources 
are present when writing applications with any widget set 

10.1.1 Shell Subclasses 

There are several types of Shell widgets. The Shell widget class itself, specified by the class 
structure pointer shellwidgetClass, is never instantiated directly in applications. Only 
its subclasses are used. You have seen two subclasses of the Shell widget used earlier in this 
book, the one used for the application s top-level widget and the one used for pop ups. The 
application s top-level widget is created by passing the class structure pointer 
applicationShellwidgetClass as the widget class argument to xtAppCreate- 
Shell; this call is also made internally by xt initialize. Pop-up shells for dialog 
boxes are created by passing transientShellWidgetClass as the widget class argu 
ment to XtCreatePopupShell. 

There are two other subclasses of Shell that are commonly used in applications. One is the 
OverrideShellwidgetClass, passed to XtCreatePopupShell when the shell is 
used for pop-up menus. The convention is this: the shell should be an OverrideShell when 
the pointer is grabbed to prevent other windows from getting input while the pop up is up, 
and the shell should be TransientShell for other pop ups. This will be discussed further in 
Chapter 12, Menus, Gadgets, and Cascaded Pop Ups. 

The other additional subclass of Shell is topLevelShellwidgetClass, which is used 
to create additional, non-pop-up, top-level shells. Some applications have multiple perma 
nent top-level windows. One of the top-level shells would be of the application- 



*Note that we are using the term resources here in a general sense, rather than implying its Xt-specific meaning. 



270 X Toolkit Intrinsics Programming Manual 



ShellwidgetClass, and the rest would be of the topLevelShellwidgetClass. 
Each would have a separate icon. 



10.1.2 Setting Shell Resources 

Shell resources are primarily a way for the user and the application to send in data to be com 
municated to the window manager. These window manager hints control several major areas 
of window manager activity: they manage screen space, icons, and keyboard input. We ll 
discuss these areas one at a time in the following sections. Table 10-1 lists the Shell widget s 
resources with a brief description of what they control, and whether the application, the user, 
or Xt normally sets them. 

As indicated in Column 3 of the table, some Shell resources are intended to be set only once. 
These set-once resources can be left to their default values, set in the application-defaults 
file, or they can be set in the code before the Shell widget is realized; but they should not be 
set with xtSetValues after realization. 




Table 10-1. Shell Resources 



Resource Purpose 



usually set by Shell itself, 

depending on the subclass : 

XtNargc 

XtNargv 

XtNoverrideRedirect 

XtNtransient 

XtNwaitForWm 

XtNwindowGroup 

XtNwmTimeout 

usually set by user : 

XtNiconX 

XtNiconY 

XtNiconic 

XtNgeometry 

XtNtitle 

usually set by application : 

XtNallowShellResize 

XtNbaseHeight 

XtNbasewidth 

XtNheightlnc 

XtNwidthlnc 

XtNiconMask 

XtNiconName 

XtNiconPixmap 

XtNiconWindow 

XtNinitialState 



Command-line args count 

Command-line args 

Set for pop-up shells not to be decorated 

Set for pop-up shells 

Whether to wait at all 

Links pop ups to main window 

Waiting time for slow wm 

Icon position 

Icon position 

Sets XtNinitialState to iconic 

Initial size and position 

String for tide bar 

Does shell ask wm for size change? 
Height of fixed components 
Width of fixed components 
Desired height increment 
Desired width increment 
Mask used with icon pixmap 
String for icon 
Picture for icon 
Window for icon 
Whether normal or iconic 



When Sellable 



Before realization 
Before realization 
Before realization 
Before realization 
Anytime 

Anytime 

Anytime 

Anytime 

Anytime 

Anytime 

Before realization 

Before realization 

Before realization 

Before realization 

Before realization 



Interclient Communications 



271 



Table 10-1. Shell Resources (continued) 



Resource 


Purpose 


When Sellable 


XtNinput 


Keyboard input model 


Before realization 


XtNmaxAspectX 


Maximum aspect ratio x/y 


Anytime 


XtNmaxAspectY 


Maximum aspect ratio x/y 


Anytime 


XtNmaxHeight 


Maximum acceptable height 


Anytime 


XtNmaxWidth 


Maximum acceptable width 


Anytime 


XtNminAspectX 


Minimum aspect ratio x/y 


Anytime 


XtNminAspectY 


Minimum aspect ratio x/y 


Anytime 


XtNminHeight 


Minimum acceptable height 


Anytime 


XtNminWidth 


Minimum acceptable width 


Anytime 


XtNsaveUnder 


Should server save under when mapped 


Before realization 



Several of the Shell resources are set automatically by Xt or the window manager, and under 
normal circumstances should not be modified by an application: 

The xtNargc and XtNargv resources are set by Xt to contain the command-line argu 
ments used to invoke the application. This may be used by the window manager or a ses 
sion manager to allow the user to reinvoke the application using the same arguments. 

The xtNwindowGroup resource is used to link pop-up windows to an application s 
main window. If not set explicitly, XtNwindowGroup is automatically set to the top- 
level ancestor of the pop-up shell, which is usually the application s top-level shell. 

The XtNtransient and XtNoverrideRedirect resources are set automatically 
by Xt depending on what kind of Shell widget you create. For top-level application 
shells, both are set to indicate that the window manager should treat this window as a top- 
level window. For Transients hell pop-up shells, XtNtransient is set automatically 
to the shell specified in XtNwindowGroup. When the top-level window is iconified, 
the Transients hell pop up will also be iconified. The Transients hell may also be 
decorated differently from main application shells. 

XtNoverrideRedirect defaults to TRUE in the OverrideShell class, indicating that 
the pop up can map itself completely without window manager intervention. This type of 
pop-up shell is typically used for pop-up menus, because it grabs the pointer and no other 
input to other applications is allowed while the menu is visible. This type of pop up is 
not decorated by the window manager. 

The xtNwaitForWm and xtNwmTimeout resources control the response to delays by 
the window manager in responding to geometry change requests. By default, xt- 
NwaitForWm is TRUE, and XtNwm_timeout is five seconds. When making a geom 
etry request to the window manager, the Shell widget will wait for five seconds for a 
response. If a response does not arrive within five seconds, the Shell widget will set Xt - 
NwaitForWm to FALSE, assume that the window manager is not functioning, and con 
tinue, without waiting for the event that should arrive to represent the size of the window, 
and without updating Xt s internal cache of window geometries. When this event does 
arrive later, Xt may set XtNwaitForWm back to TRUE and update its internal cache. 
These resources should normally be left to their default values. 



272 



X Toolkit Intrinsics Programming Manual 



The XtNgeometry and XtNiconic resources are intended to be specified by the user. 
Only these two resources have standard command-line options for setting them. The Xt 
Ngeometry resource is sellable using a command-line option of ihe form: 

-geometry [width[x}height][{+-}xposition{ + - 



(Eilher the size or position portion of the geomelry siring may be omitted, as indicated by ihe 
square brackels. In specifying ihe x or y position, a positive value, indicated by a plus sign, is 
relative to the lop or left side of the reference window, while a negative value, indicated by a 
minus sign, is relative lo Ihe bottom or right side.) 

The -iconic command-line option, if present, sels Ihe XtNiconic resource, indicating lo 
ihe window manager lhal ihe application should slart up as an icon. 

The xtNicon_x and xtNicon_y icon position hinls are besl left lo be specified by the 
user. Icons positions are determined by ihe window manager based on ihese hints or on an 
icon-positioning policy. An application wilh several lop-level windows could sel ihe icon 
position hinls in ils applicalion-defaulls file so that ihe icons for each lop-level window 
appear side-by-side. 

We will discuss ihe remaining resources in related groups. Section 10.1.3 discusses ihe ones 
related lo the size of ihe application s main window and other screen space issues. Section 
10.1.4 describes the keyboard input model hint. Section 10.1.5 describes how applications 
should handle colormaps lo cooperate wilh ihe window manager. Section 10.1.6 describes 
the ones that apply to the application s icon. 

10.1.3 Screen Space 

The window manager directly controls Ihe size and position of ihe lop-level windows (child 
ren of ihe rool window) on ihe screen, ihe Shell widgels of each application. The window 
manager does nol conlrol Ihe geomelry of olher widgels lhal are ihe descendants of ihe 
Shells, excepl indireclly ihrough ihe geometry management mechanism described in Chapter 
11, Geometry Management. 

The most basic size hinl, the one lhat specifies simply ihe desired initial height and width, is 
automatically sel by Xt based on ihe size of ihe child of ihe Shell widget. This hint is used 
by most window managers to display ihe outline of your application when it first appears on 
the screen, ready for the user lo place and/or size ihe application. If your application does 
not have specific size needs, you need nol sel any additional resources. 

The additional size hinls specify ihe application s range of desired sizes, desired incremenls 
of sizes, and desired range of aspecl ratios. These are set by the xtNbaseHeight, xt- 
NbaseWidth, XtNminWidth, XtNminHeight, XtNmaxWidth, XtNmaxHeight, 
XtNwidthlnc, XtNheightlnc, XtNminAspectX, XtNminAspectY, Xt- 
NmaxAspectX, and XtNmaxAspect Y resources. 

Size incremenl hinls are useful for applications lhat prefer to be in unils of a particular num 
ber of pixels. Window managers that listen for ihis hinl always resize ihe window lo ihe base 
size (for each dimension), plus or minus an integral multiple of ihe size increment hint for 
lhat dimension. If ihe base size resource has nol been sel, ihe minimum size is used as the 



Interclient Communications 273 




base. For example, xter/n uses the font, width, and height as width and height increment 
hints, because it prefers not to have partial characters or dead space around the edges. The 
bitmap editor application described in Chapter 4, An Example Application, should probably 
set both the width and height increments to the cell_size__in_jpixels, since the bit 
map cells are square. 

Most applications that use size increment hints redefine the interpretation of geometry speci 
fications (the xtNgeometry resource, sellable through the -geometry standard 
command-line option) to reflect the size increments. For example, the width and height in 
xterm geometry specifications are in units of characters, not pixels. The VtlOO widget within 
xterm implements this by having an XtNgeometry resource separate from the shell geom 
etry resource with that name. The entry for this resource in the widget resource list specifies 
the VtlOO instance structure field, not the shell instance structure field. Then the realize 
method for the VtlOO parses the geometry string with XParseGeometry (an Xlib routine 
that returns four separate variables containing the size and position from the geometry string) 
and sets the width and height fields of the core structure and the various size hints according 
to the returned variables. (The VtlOO within xterm is not a real, self-sufficient widget For 
one thing, it has no set_values method. For any real widget to implement this approach 
to interpreting geometry specifications, the set_values method would have to multiply 
the xtNwidth and XtNheight resource settings by the increment hints.) 

An aspect ratio is the ratio of the width measurement to the height measurement or vice 
versa. The xtNminAspectx and xtNminAspectY resources are used together to deter 
mine one extreme of acceptable aspect ratios, and xtNmaxAspectx and xt- 
NmaxAspectY determine the other extreme. For example, to suggest that the xmh applica 
tion never be more than four times larger in one direction than it is in the other, the following 
values (as they would appear in the application-defaults file) would suffice: 

xmh*topLevel .minAspectX: 1 

xmh*topLevel .minAspectY: 4 

xmh*topLevel.maxAspectX: 4 

xmh*topLevel .maxAspectY: 1 

Remember that every application must be able to do something reasonable given any size for 
its top-level window, even if the window is too small to be useful or if any of these hints are 
ignored by the window manager. 



10.1.4 Input Model 



Window managers also control which window keyboard input will be delivered to by setting 
the keyboard focus window (sometimes called just the keyboard focus) to an application s 
top-level window. The distribution of events according to the current keyboard focus is 
handled by the server; it is a basic feature of X, not of Xt. Some window managers, like 
UH?n, use the pointer-following (also called real-estate-driven) model of keyboard input; the 
window containing the pointer gets the keyboard input. Setting the keyboard focus once to 
the root window implements the pointer-following model. Other window managers use the 
click-to-type model, exemplified by the Macintosh user interface, requiring that the user 



274 X TboM Intrinsics Programming Manual 



click the pointer in the window where keyboard input is to go. The window manager sets the 
keyboard focus to the window the user clicks on. However, these basic window manager 
behaviors can be modified by the input model hint, which is set by the xtNinput resource. 

If XtNinput is set to TRUE, the window manager will set the keyboard focus to this appli 
cation or not, according to its pointer-following or click-to-type model of keyboard input. 
However, if it is set to FALSE, the window manager will not set the keyboard focus to this 
application. If the application sets this resource to FALSE and wants input, it will have to 
forcefully take the keyboard focus, and then put it back to the original window when fin 
ished. 

For historical, not logical, reasons, the Intrinsics default for the XtNinput resource is 
FALSE. However, there is a special internal Shell widget class called VendorShell, which 
sets appropriate resources for a given widget set The proper default for a given widget set 
(which usually has an accompanying window manager) is set by that widget set s Vendor- 
Shell. The majority of applications need xtNinput set to TRUE unless they don t require 
keyboard input (and expect never to have accelerators). 

There are four models of client input handling defined by the ICCCM: 

No Input. The client never expects keyboard input, xload is an example of such an 
output-only client. This type of client sets xtNinput to FALSE. 

Passive Input. The client expects keyboard input but never explicitly sets the input focus. 
This describes the vast majority of applications that always accept keyboard input in the 
window that contains the pointer. This type of client sets xtNinput to TRUE. 

Locally Active Input. The client expects keyboard input, and explicitly sets the keyboard 
focus, but only does so when one of its windows already has the focus. An example 
would be a client with subwindows defining various data entry fields that uses Next and 
Prev keys to move the keyboard focus between the fields, once its top-level window has 
received the keyboard focus. This type of client sets XtNinput to TRUE. 

Globally Active Input. The client expects keyboard input, and explicitly sets the input 
focus even when the focus is in windows the client does not own. An example would be 
a client with a scrollbar that wants to allow users to scroll the window without disturbing 
the keyboard focus even if it is in some other window. It wants to temporarily set and 
then reset the keyboard focus when the user clicks in the scrolled region, but not when 
the user clicks in the scrollbar itself. Thus, it wants to prevent the window manager set 
ting the keyboard focus to any of its windows. This type of client sets XtNinput to 

FALSE. 

Note that even if the xtNinput resource is not set to TRUE, your application will still work 
under some window managers, including uwm and the version of twm that is standard in 
Release 4. This is because these window managers use the pointer-following keyboard focus 
model and ignore this hint. However, it is not wise to assume that all window managers will 
ignore this hint. Therefore, if your application expects keyboard input, and is not of the glob 
ally active type described above, you can use the code shown in Example 10-1 to set the xt 
Ninput resource. 



Interclient Communications 275 



Example 10-1. Setting the XtNinput resource of a Shell widget 

main(argc, argv) 
int argc; 
char *argv [ ] ; 



static Arg shell_args[] = { 

{XtNinput, (XtArgVal)TRUE), 



/* create the Shell widget */ 

topLevel = Xtlnitialize ("main", "Xmh", table, XtNumber (table) , 
&argc, argv) ; 



XtSetValues (topLevel, shell args, XtNumber (shell_args) ); 



Note that the XtNinput resource should always be hardcoded, since the application may 
fail if the user is allowed to change the expected style of keyboard focus. 

For a further discussion of the keyboard focus, see Section 13.3. 



10.1.5 Colormaps 



On most color systems, the display uses one or more hardware registers called colormaps to 
store the mapping between pixel values and actual colors, which are specified as relative 
intensities of red, green, and blue primaries (RGB values). 

X allows virtual colormaps to be created by applications. Some high-performance systems 
even allow all virtual colormaps to be installed in hardware colormaps and used at the same 
time, even to the level of one colormap per window. Far more commonly, though, there is 
only one hardware colormap, and virtual colormaps have to be copied into the hardware 
colormap one at a time as needed. Copying a virtual colormap into the hardware colormap is 
called installing the colormap, and the reverse process where the default colormap is 
installed is called uninstalling . The window manager is responsible for installing and unins- 
talling colormaps. 

If your application has standard color needs (decoration only), then you do not have to worry 
about the effects of colormaps being installed and uninstalled. Your application should use 
the standard xtRString to xtRPixel converter to translate color names into pixel val 
ues. If the colormap is full, or becomes full at any of the color allocations in the converter, 
the warning messages place the burden on the user to kill some applications in order to free 



276 X Toolkit Intrinsics Programming Manual 



some colormap cells. (If the converter cannot allocate the desired color, it prints a warning 
message, and the default for that resource is used. If the default is not xtDefault- 
Foreground or XtDef aultBackground, it also must be converted and this may also 
fail. If both allocations fail, the color will default to black. If this is not acceptable, then you 
will need to write your own type converter.) 

If your application absolutely requires accurate colors, a certain number of distinguishable 
colors, or dynamically changeable colors, you will need to write your own converter to allo 
cate colors. For example, if a color allocation for a known correct color name string fails, it 
means that all the colormap entries have already been allocated and no entry for that color is 
available. In this case, your converter might call the Xlib call XGopyColormapAndFree 
to copy the allocations your application has already made into a new colormap. Then the 
converter would allocate the color (and all subsequent colors) from the new colormap. 

See Chapter 7, Color, in Volume One, Xlib Programming Manual, for details of various color 
allocation techniques. 

The window manager is responsible for installing and uninstalling colormaps according to its 
own policy. Typically, the policy is to install the colormap of the application that has the 
keyboard focus or that contains the pointer. When an application has created a new colormap 
on a system that supports only one hardware colormap, and that colormap is installed, all 
applications that were using the other colormap will be displayed using the new colormap. 
Since the pixel values from the old colormap have not been allocated in the new colormap, 
all applications that use the old colormap will be displayed with false colors. This is known 
as "going technicolor." 

The window manager may also create standard colormaps to facilitate the sharing of colors 
between applications. A standard colormap is a colormap allocated with a publicly known 
arrangement of colors. The Xlib routine XGetStandardColormap allows an applica 
tion to determine whether the window manager has created a specific standard colormap, and 
it gets a structure describing the colormap. 



Icons 

The window manager always manages the icons for each application. Depending on the win 
dow manager, these icons may simply contain a text string called the icon name, or they may 
contain a pattern that identifies the application, called the icon pixmap. 

Figure 10-1 shows the icon, under the uwm window manager, for an application with a cus 
tom icon pixmap (xcalc) and for one without (xterm). 




977 

Interclient Communications 






DDDH 
DDDHB 

DDDBB 




Figure 10-1. An icon with and without an icon pixmap 

An application may supply an icon name by setting the XtNiconName resource; if it does 
not, the window manager will usually use the application name or the value of the xt- 
Nti tie resource. 

The application should supply the pattern for the icon, in the form of a single-plane pixmap, 
as the xtNiconPixmap resource. There are two basic ways to do this: one is by including 
bitmap data, and the other is by reading it in at run-time. The former is easy to do with an 
Xlib call; the code that needs to be added is shown in Example 10-2. The latter technique, 
because it involves building a filename and looking in a number of locations for the file, is 
better done with a converter defined by the Xmu library. This converter technique is more 
complicated because the converter has to be registered and called with the proper arguments. 
The example using a converter is provided in the example source code, but not shown here. 
See Chapter 9, Resource Mangement and Type Conversion, for more information. 

Example 10-2. Creating an icon pixmap, and setting XtNiconPixmap 



/* both R3 and R4 (part of Xt) */ 

tinclude <Xll/Shell .h> /* Athena Label Widget */ 

tinclude "icon. bit" 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Pixmap icon_pixmap; 

Arg arg; 



/* create topLevel here */ 

icon_pixmap = XCreateBitmapFromData (XtDisplay (topLevel) , 
RootWindowOf Screen (XtScreen (topLevel) ) , 
icon_bits, 
icon_width, icon_height ) ; 



278 



X Toolkit Intrinsics Programming Manual 



Example 10-2. Creating an icon pixmap, and setting XtNiconPixmap (continued) 

XtSetArg(arg, XtNiconPixmap, icon_pixmap) ; 
XtSetValues (topLevel, &arg, 1); 



/* realize widgets */ 

The included file, icon.bit, is in standard XI 1 bitmap file format. You can create such a file 
using the bitmap application. 

The window manager may have a preferred standard size for icons. If so, it will set a prop 
erty. The application can read this property with the Xlib call XGetlconSizes. To fully 
support a variety of window managers, an application should be capable of creating icon pix- 
maps of different sizes, depending on the values returned by XGetlconSizes. 

10.1.7 Window Manager Decorations 

Most window managers, with the exception of uwm t decorate windows on the screen.* 
These decorations typically include a title bar for the window with widgets for moving and 
resizing the window. Current decorating window managers include twm, awm, mwm, olwm, 
and gwm. 

The way these decorations are implemented can have an impact on Toolkit applications. The 
window manager places the decorations in a window slightly bigger than the application, and 
then reparents the application s top-level window into the decoration window. Reparenting 
gives the top-level window a new parent instead of the root window. The window manager 
actually creates the frame window as a child of the root window, then reparents the applica 
tion s top-level window into the frame, and then maps the frame window. 

Reparenting impacts the application mainly when you try to determine a global position (rel 
ative to the root window) from the xtNx and xtNy resources of the Shell widget This is 
usually done to place pop ups. Under a nonreparenting window manager such as uwm, these 
coordinates are indeed relative to the root window, because the parent of the shell is the root 
window. However, under a window manager that reparents transient shells, the coordinates 
are relative to the decoration window, not the root window. Therefore, these coordinates can 
not be used for placing pop ups within the application. The code shown in Section 3.3 that 
places a pop up uses xtTranslateCoords instead of relying on the position resources. 




*The uwm window manager will no longer be supported by the X Consortium as of Release 4. Then, virtually all 
window managers will be of the decorating, reparenting type. 



Interclient Communications 279 



10.2 Selections: Widget-To-Widget Communication 

Selections are a general mechanism for communicating information between two clients of 
the same server. The most familiar example of selections is selecting text from one xterm 
application and pasting it into another xterm application. This text can also be pasted into an 
xmh mail composition window, or into an xedit application. 

In Xt applications, selection is normally implemented within widgets. For example, the 
Athena Text widget is used by xmh and xedit , and it is this widget that supports cutting and 
pasting of text in these applications. The application code of xmh and xedit does not play a 
part in the communication of selection data. The fact that selection is implemented in wid 
gets also means that two widgets within the same application can communicate with each 
other through selections. For example, the Text widget is sometimes used to provide single- 
line input fields in an application. Since the Text widget supports selections, the user could 
select the text in one field and paste it into another field. This feature would be present with 
out any code in the application. If the same widget class supports both copying and pasting, 
selections can be used to move data in a single widget For example, selections allow you to 
copy text within an editor in xterm and paste the text in a new place (although some editors 
require keyboard commands to position the insertion point). 

The selection mechanism is not limited to text It requires only that the sender and recipient 
have knowledge of the format of the data being transferred. Therefore, selections can be 
used to transfer graphics between widgets that can understand a common format for com 
municating graphics. Unfortunately, a standard format for graphics has not yet been agreed 
upon. 

The selection mechanism uses properties for transferring data and uses the Selection- 
Clear, SelectionNotif y, and SelectionRequest event types to synchronize the 
communication. Essentially, a property is common storage. Properties are stored in the 
server, and are named pieces of data associated with a window on that particular server, that 
any client of that server can read or write. Because the various clients may not be running on 
the same host, all communication between applications and between applications and the 
window manager must take place through the server using properties.* 

The basic routines used to implement selections are part of Xlib. Xt provides an interface to 
the Xlib selection routines that makes selections easier to use in the context of widget code. 
Since there is a maximum size for the data stored in a single property, communication of 
large blocks of data using Xlib requires several partial transfers. Xt supplies routines that 
transparently perform the multiple partial transfers so that they appear to the application pro 
gram like a single transfer. The Toolkit selection routines also provide timeouts, so that one 
application won t wait forever for another to provide data. 



*It is not even possible, in general, to write your own networking routines in an application to communicate with oth 
er clients running on different hosts, because your client may be communicating with the server using TCP/IP and the 
other client may be using DECneL Both may be the same X application that you wrote, but compiled with a version 
of Xlib that uses a different protocol layer underneath the X protocol. When you communicate through the server us 
ing properties, the server takes care of the translation. 



280 X Toolkit Intrinsics Programming Manual 



First we ll give you an overview of how a selection transaction works, and then we ll discuss 
how to write the code to implement selections in a widget 

If you are writing a custom widget that contains data that could be pasted into other instances 
of the widget or other widgets, you should read on to see how to implement selections. 
Otherwise, the rest of this chapter is probably only of academic interest to you. 

How Selection Works 

Selections communicate between an owner widget and a requestor widget* The owner has 
the data and the requestor wants it The owner is the widget in which the user has selected 
something, and the requestor is the widget in which the user has clicked to paste that some 
thing. Many widgets need to act as both owner and requester at different times. The code to 
handle each of the two roles is separate. 

Here is a brief overview of the steps that take place during a single transfer of data from one 
widget to another. We ll assume we have two instances of the same widget class, which can 
operate either as the owner or the requestor. Initially, both widgets are in exactly the same 
state, neither having any text selected, and neither being the owner or requestor. We ll also 
assume that selections are implemented using actions tied to pointer buttons, as in existing 
widgets that use selections. 

The user selects an item in Widget A, and the widget highlights the item. An action, typi 
cally called in response to a <BtnlDown> translation, marks the start of a selection. A 
subsequent <BtnlMotion> event (that is, a motion event with button 1 held down) 
invokes another action to extend the highlighted selection. 

A <BtnlUp> event invokes a third action in Widget A that actually makes the selection. 
The action calls xtOwnSelection to claim ownership of the PRIMARY selection for 
Widget A. This means that Widget A claims the sole right to use the XA_PRIMARY prop 
erty for communication with other widgets, until some other widget claims ownership. 
(More about XA_PRIMARY below.) The call to XtOwnSelection also registers three 
procedures, to be called by Xt in response to selection events. The 
lose_ownershp_proc handles the case where Widget A loses the selection 
(because the user has made another selection elsewhere), the convert_proc converts 
the data in the selection to the target property type requested by Widget B (see below), 
and the optional trans fer_done_proc prepares for the next selection request, if 
necessary (this function is often NULL). 

The user pastes the item into Widget B, usually by clicking a pointer button. (By conven 
tion, a translation for <Btn2Down> invokes the action to do this.) 

The paste action in Widget B requests the value of the current selection by calling xt- 
GetSelectionValue; this specifies a target type, and a requestor_callback 
that will be invoked to actually paste the data when Widget A reports that the conversion 
has been successfully completed. 



*Note that since selections can be implemented in the application, as they are non-Xt applications, the words "appli 
cation" and "widget" are interchangeable in this section. 



Interclient Communications 



The XtGetSelectionValue call by Widget B also generates a Selection- 
Request event In response to this event, Xt invokes the convert_jproc registered 
by the call to XtOwnSe lection in Widget A. 

The convert_proc in Widget A converts the selected item into the appropriate data 
type for the target property specified by 5, if possible. The converted data is stored in the 
XA_PRIMARY property. 

Based on the return values from Widget A s conversion procedure, Xt sends a 
SelectionNotif y event to inform Widget B whether or not the data was success 
fully converted. 

The request or_callback registered in Widget B reads the data from the property 
and displays it, or if Widget A reported that the conversion could not be made, Widget B 
beeps or otherwise indicates that the kind of data selected in Widget A cannot be pasted 
in Widget B, or that the kind of data requested by B cannot be supplied by A. 

Xt notifies Widget A that the selection has been transferred, so that the widget s 
trans fer_done_proc can disown the selection if the selection is of a kind that can 
be transferred only once. 

Figure 10-2 shows this procedure in graphic form. 

The code to implement selections is divided logically into a number of functions within the 
widget The next sections show the code necessary to implement both the owner and the 
requestor roles. The code for each role is separate and cannot share any widget variables 
with the other role because the transaction may be between two different widget instances. 

As an example, we will add support for selections to the BiimapEdit widget described in 
Chapter 5 and Chapter 6. Little of the existing code in that widget needs to be changed. The 
examples show only the code added to implement selections, and describe where to add it 

We will start with the owner role, and then proceed to the requestor role, and then back to the 
owner role. 



282 X Toolkit Intrinsics Programming Manual 



user presses 
button 1 and 
makes selection 



convert _proc converts 
data and returns. Xt 
sets property 




XtOwnSelection 
registers 3 
procedures 



H user presses 
U button 2 to 
paste 
selection 


XtGetSelectionValue Me 
sends I 
SelectionRequest 
event to owner 




\ 



o j Xt sends 
SelectionNotify 
event 



ntrinsics 
routines 



XtGetSelectionValue () 



XtGetSelectionValue 
registers callback to 
do actual paste 



Xt invokes* 
requestor callback, 
which actually 
pastes the data 




widgetA. translations : \n\ 
<BtnlDown>: startHighlight ( ) \n\ 
<BtnlMotion>: extendHighlight ( ) \n\ 
<BtnlUp>: makeSelection ( ) 



widgetB. translations : \n\ 
<Btn2Down>: paste () 



Figure 10-2. The process of selection transfer 



Interclient Communications 



283 



10.2.2 Highlighting the Selected Data (Owner) 

The selection process begins when the user selects some text in Widget A. The widget code 
for the owner role must contain some code to identify the area or items selected and to high 
light the text (or whatever) being selected. This user-interface portion of the owner role is 
carried out by actions added to the widget Some event sequences that are not already in use 
must be mapped to these actions. In existing applications that support selections of text: 

A press of the first pointer button pins a starting point of the selection, dragging the first 
button extends and highlights the selection, and releasing the first button ends the selec 
tion. A subsequent press of the first button starts a new selection, unhighlighting the old 
one. 

A press of the second button pastes the selection. 

A button press or motion with the third button depressed repositions either end of the 
selected area. 

It is a good idea to stick with existing conventions for the user interface of highlighting a 
selection, so that your application will operate in a familiar way. But since BitmapEdit 
already uses all three pointer buttons, unmodified, to set, unset, and toggle bitmap cells, we 
cannot use unmodified button presses to control selections. But we can (and will) use these 
same buttons modified by Shift. 

A selection in BitmapEdit is any rectangular set of bitmap cells. Accordingly, BitmapEdit 
will use Shift<BtnlDown> to set the top-left corner of a selection rectangle, 
Shif t<BtnlMotion> to follow dragging, and Shif t<BtnlUp> to set the bottom right 
corner.* Each of these events will invoke a separate action routine, StartHighlight, 
ExtendHighlight, and MakeSelection, respectively. These translations are added 
to the widget s default translation table, and the actions are added to the actions table. 
Example 10-3 shows the action table, the translation table, and the three action routines. 



Example 10-3. BitmapEdit: actions that highlight selection 

static char defaultTranslations [ ] = 



Shif t<BtnlDown> : 
Shif t<BtnlMotion> : 
Shift <BtnlUp>: 
Shif t<Btn2Down> : 
Shift <BtnlDown> : 
"Shif t<Btn2Down> : 
~Shift<Btn3Down>: 
~Shift<BtnlMotion>: 
Shift <Btn2Motion> : 
Shif t<Btn3Motion> : 



StartHighlight () 
ExtendHighlight () 
MakeSelection () 
PasteSelection () 
DoCellO 
UndoCelK) 
ToggleCelK) 
DoCellO 
UndoCelK) 
ToggleCell ()"; 



\n\ 
\n\ 
\n\ 
\n\ 
\n\ 
\n\ 
\n\ 
\n\ 
\n\ 



static XtActionsRec actions!] = { 
{"DoCell", DoCell}, 
{"UndoCell", UndoCell}, 
{"ToggleCell", ToggleCell}, 



*For simplicity, we won t copy the third button semantics used in text selections. This could easily be added. 



284 



X Toolkit Intrinsics Programming Manual 



Example 10-3. BitmapEdit: actions that highlight selection (continued) 

("StartHighlight", StartHighlight}, 
{"ExtendHighlight", ExtendHighlight}, 
{ "MakeSelection", MakeSelection} , 
{ "PasteSelection", PasteSelection } , 



static void 

StartHighlight (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 

w->bitmapEdit .first_box = FALSE; 

w->bitmapEdit . select_start_x = (w->bitmapEdit .cur_x + 
event->x) / w->bitmapEdit .cell_size_in_pixels; 

w->bitmapEdit . select_start_y = (w->bitmapEdit .cur_y + 
event->y) / w->bitmapEdit .cell_size_in_pixels; 

/* clear old selection */ 
Redisplay (w, NULL); 

static void 

MakeSelection (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 

int temp; 

w->bitmapEdit . select_end_x = (w->bitmapEdit .cur_x + 

event->x) / w->bitmapEdit . cell_size_in_pixels, 

w >bitmapEdit . select_end_y = (w->bitmapEdit ,cur_y + 

event->y) / w->bitmapEdit . cell_size_in_pixels, 

if ( (w->bitmapEdit . select_end_x == 

w->bitmapEdit . select_start_x) && 
(w->bitmapEdit . select_end_y == 
w->bitmapEdit . select_start_y) ) { 

Redisplay (w, NULL); 

return; /* no selection */ 

/* swap start and end if end is greater than start */ 
if (w->bitmapEdit . select_end_x < 

w->bitmapEdit . select_start_x) { 

temp = w->bitmapEdit . select_end_x; 

w->bitmapEdit . select_end_x = 

w->bitmapEdit . select_start_x; 

w->bitmapEdit . select_end_x = 

w->bitmapEdit . select_start_x; 

w->bitmapEdit . select_start_x = temp; 

if (w->bitmapEdit . select_end_y < 

w->bitmapEdit . select_start_y) { 
temp = w->bitmapEdit . select_end_y; 
w->bitmapEdit . select_end_y = 




Interclient Communications 



285 



Example 10-3. B rtmapEdit: actions that highlight selection (continued) 

w->bitmapEdit . select_start_y; 
w->bitmapEdit . select_start_y = temp; 

} 

if (XtOwnSelection (w, XA_PRIMARY, event->time, convert_proc, 
lose_ownership_proc, 
transf er_done_proc) == FALSE) { 
XtWarning ("bitmapEdit : failed to become selection\ 

owner; make a new selection . \n") ; 
/* Clear old selection, because lose_ownership_proc 

* isn t registered. */ 
Redisplay (w, NULL); 



static void 

ExtendHighlight (w, event) 
BitmapEditWidget w; 
XMotionEvent *event; 
{ 

static int last_drawn_x, last_drawn_y; 

int event_cell_x, event_cell y; 

event_cell_x = w->bitmapEdit . cur_x + (event->x / 

w->bitmapEdit . cell_size_in_pixels) ; 
event_cell_y = w->bitmapEdit . cur_y + (event->y / 

w->bitmapEdit . cell_size_in_pixels) ; 

if ( (event_cell_x == last_drawn_x) && (event_cell_y == 

last_drawn_y ) ) 
return; 

if (w->bitmapEdit . first_box) { 

draw_box(w, last_drawn_x, last_drawn_y) ; /* undraws */ 

draw_box(w, event_cell_x, event_cell_y) ; 
} 
else { 

draw_box(w, event_cell_x, event_cell_y) ; 

w->bitmapEdit . first_box = TRUE;~ 
} 

last_drawn_x = event_cell_x; 
last_drawn_y = event_cell_y; 
i 

static void 
draw_box(w, x, y) 
BitmapEditWidget w; 
Position x, y; 
{ 

Position start_pos_x, start_pos_y; 

Dimension width, height; 

start_pos_x = w->bitmapEdit . cur_x + 

w->bitmapEdit . select_start_x; 
start_pos_y = w->bitmapEdit . cur_x + 

w->bitmapEdit . select_start_y; 

/* swap start and end if end is greater than start */ 
286 X Toolkit Intrinsics Programming Manual 



Example 10-3. BitmapEdit: actions that highlight selection (continued) 

if (x < start_pos_x) { 

width = start_pos_x - x; 

start_pos_x = x; 
} 
else { 

width = x - start_pos_x; 
} 

if (y < start_pos_y) { 

height = start_pos_y - y; 

start_pos_y = y; 
} 
else { 

height = y - start_pos_y; 
} 

XDrawRectangle (XtDisplay (w) , XtWindow (w) , 

w->bitmapEdit . xor_gc, (start_pos_x * 
w->bitmapEdit .cell_size_in_pixels) - 1, 
(start_pos_y * w->bitmapEdit .cell_size_in_pixels) - 1, 
(unsigned int) width * 

w->bitmapEdit . cell_size_in_pixels + 2, 
(unsigned int) height * 

w->bitmapEdit .cell_size_in_pixels + 2); 
} 

The actions shown in Example 10-3 reference some new instance part fields we have added 
to BitmapEditP .h to store the state of the selection. Four of these variables are the x and v; 
coordinates in cells of the top-left and bottom-right corners of the highlighted area: 
select_start_x, select_start_y, select_end_x, and select_end_y. 
These will be used throughout the owner code. (Because these fields are in units of bitmap 
cells, not pixels, their type is int rather than Position.) 

The Start Highlight action is quite simple. It sets the upper-left corner instance part 
fields based on the button press position in the triggering event. It also clears the highlight 
ing of the old selection, if one exists, and sets a flag to indicate that this is the beginning of a 
new selection. The f irstjbox flag is added as an instance part field because it will be 
needed in the ExtendHighlight action. 

ExtendHighlight is responsible for drawing a dynamic rubber-band box around the 
selected area, much as the window manager draws the outline of a window while it is being 
moved. This outline surrounds a rectangle of bitmap cells beginning from the cell selected in 
the StartHighlight action and ending at the cell the pointer is currently in. Extend 
Highlight is triggered by pointer motion events that occur while the first button is held 
down. It calculates which bitmap cell the pointer is in, and if the cell is not the same as the 
cell the pointer was in the last time ExtendHighlight was called, it erases the previous 
box and draws a new one. The most efficient way to draw such a box so that it can be erased 
easily is to use the exclusive OR logical function in the GC.* We ve added another GC field 
to the instance part structure to hold a GC set to this logical function, and added code to the 




*With exclusive OR, drawing once draws the box, and drawing it again erases the box. This works on both color and 
monochrome screens, but only if nothing is drawn between the drawing operations. See Chapter 7, Color, in Volume 
One, Xlib Programming Manual, for more information. 



Interclient Communications 287 



initialize method to create this GC. (See xbitmap in the example distribution for this 
modified widget instance structure.) 

The MakeSelection action is triggered when the button is released after dragging, indi 
cating that the selection is complete. This action sets the select_end_x and 
select_end_y instance part variables to reflect the bottom-right corner of the selection, 
and then swaps the top-left and bottom-right coordinates if the end coordinate is to the left or 
above the start coordinate. If the start and end coordinates are the same, then the action 
returns, since no selection was made. If a selection was made, MakeSelection calls xt- 
OwnSelection. 



10.2.3 Making the Selection with XtOwnSelection (Owner) 

Once the area is highlighted, Widget A calls XtOwnSelection to assert that it wants the 
right to set the value of a property that will be used to transfer information. 

XtOwnSelection is called with six arguments: 

Boolean XtOwnSelection (widget, selection, time, convert_proc, 

lose_ownershlp_proc f trans fer_done_proc) 
Widget widget; 
Atom selection; 
Time time; 

XtConvertSelectionProc convert_proc; 
Xt Lose Selection? roc lose_ownership_proc; 
Xt Select ionDoneP roc trans fer_done_proc; 

The selection argument specifies an Atom a number representing a property. Proper 
ties are arbitrarily named pieces of data stored on the server. To simplify communication 
with the server, a property is never referenced by name, but by a unique integer ID called an 
atom. Standard atoms are defined in <Xatom.h> using defined symbols beginning with XA_; 
nonstandard atoms can be obtained from the server by calling the Xlib function xt- 
InternAtom. 

Widgets that support one selection at a time pass the predefined XA_PRIMARY atom to Xt 
OwnSelection. The ICCCM also allows you to use the XA_SECONDARY and 
XA_CLIPBOARD atoms. XA_SECONDARY would be used by widgets implementing behavior 
involving more than one selection (for example, allowing the user to make two selections, 
and to exchange the data they contain). No current clients implement this behavior. The 
XA_CL IP BOARD atom should be used by a widget that allows the user to delete a selection. 
We ll talk more about the properties referenced by the XA_SECONDARY and XA_CLIPBOARD 
atoms in Section 10.2.9.3. 

The purpose of the XtOwnSelection call is to make sure that only one widget has the 
right to set the XA_PRIMARY selection property at a time, and to assert that this widget is pre 
pared to honor requests for this data. Notice that when you select text with xterm, that text is 
highlighted only until you select a different area in a different window. 



288 X Toolkit Intrinsics Programming Manual 



The next three arguments to xtOwnSelection specify procedures that will carry out 
essential parts of the selection operation: 

The convert_proc is responsible for converting the selected data into the representa 
tion requested by the requestor in its call to xtGetSelectionValue; this function 
is called by Xt when a Select ionRequest event arrives. This happens as a result of 
the requestor calling XtGetSelectionValue. The convert^proc is of type 
XtConvert Select ionProc. 

The lose_o*rnership_proc clears the highlighted area when this widget has lost 
the selection (because some other widget has taken it); this routine is called by Xt when a 
SelectionClear event arrives. The lose_ownership_jproc is of type xt- 
LoseSelectionProc. 

The trans fer_done_jproc is called by Xt when the requestor has successfully 
retrieved the converted value. If this selection is intended to be erased after being 
transferred once, this function should free any storage allocated in the transfer. If, 
instead, the owner remains ready for pasting the same selection into other widgets, this 
function pointer should be NULL. (For example, xterm does not clear its selection after 
pasting once.) The t ransfer_done_proc is of type Xt Select ionDoneP roc. 

The XtOwnSelection call also takes a time argument this should be the time from 
the event that completed the highlighting, not the constant CurrentTime. If XtOwn 
Selection returns FALSE, it means that because of network conditions another client has 
called XtOwnSelection with a more recent time argument 

XtOwnSelection returns TRUE or FALSE to indicate whether Widget A has been granted 
ownership. If TRUE, and if this widget was not already the owner, then the old owner (if any) 
will receive a SelectionClear event and will clear its highlighted area. The process 
may end here if the user never pastes the selected data anywhere. If the user selects a differ 
ent piece of data, the selection owner will receive a SelectionClear itself before ever 
having converted the data for a requestor. 

Otherwise the owner code waits to hear from the requestor that it is ready to paste the selec 
tion. 



Requesting the Selection (Requestor) 

When the user pastes the selection into Widget 5, Widget B becomes the requestor and the 
second part of the process begins. First of all, Widget B needs a translation that maps a cer 
tain key or button event to an action that pastes data. This action calls XtGet 
SelectionValue. 

XtGetSelectionValue is called with six arguments: 




Intercllent Communications 



void XtGetSelectionValue ( widget, selection, target, callback, 

cllent_data, time) 
Widget widget; 
Atom selection; 
Atom target; 

XtSelectionCallbackProc callback; 
caddr_t cllent_data; 
Time time; 

The selection argument is an atom specifying which property is being used to transfer 
the selection. This will typically be XA_PRIMARY, though in theory two widgets (or two 
instances of the same widget) could agree to transfer some particular data using other proper 
ties. 

The target argument is another atom, this one specifying a target representation type in 
which the requestor wants the information. We ll talk more about the possible values for this 
atom in a moment. 

The callback argument is a pointer to a callback procedure that actually pastes the data. 
Xt will call this procedure when the owner has converted the data. The XtGet 
SelectionValue call registers the callback with Xt, and sends a Selection- 
Request event to the owner. 

When the selection owner has successfully converted the data, the owner sends back a 
SelectionNotify event to Xt. Xt then calls the requestor s callback procedure. The 
callback procedure must handle the pasting of the data into the widget s data structures, and 
it must handle the case where the data could not be converted into the requested representa 
tion. We ll discuss the responsibilities of this procedure in more detail once we ve seen the 
owner s conversion procedure. 

The client_data argument of XGetSelectionValue is normally used to pass the 
event that triggered the pasting into the requestor callback. The callback will use the coordi 
nates at which the event occurred as the location at which to paste the data. 

As in the call to XtOwnSelection, the time argument should be the time from the event 
that initiated the pasting, not the constant Cur rent Time. 

1 0.2.4.1 Possible Target Type Atoms 

The target argument to XtGetSelectionValue is an atom that the requestor uses to 
tell the owner what kind of information it is looking for from the selection.* This is not nec 
essarily a conversion of the actual selection data. For example, it might be a timestamp on 
the data, or some characteristic of it, such as its size or font 

To take full advantage of the Xt selection mechanism, you need to understand what atoms 
can be used as selection targets. However, apart from some standard, predefined atoms, the 
atom for a property is not known by a client until it queries the server for the atom using an 
xinternAtom call. This call specifies the string name of the property, and returns the 
atom. 



* Ai described earlier, atoms (rather than strings) are always used in network transmissions to identify properties. 



290 X Toolkit Intrinsics Programming Manual 



Some atoms needed by almost all applications are predefined in the header file 
<XlllXatom.h>. These atoms are symbolic constants that can be used without an 
xinternAtom call. The constants always start with the prefix XA_. See <X1 1 IXatom.h> 
for the complete list of predefined atoms. 

Note that many of the predefined atoms have uses in X other than as target types, and not all 
are appropriate as selection targets. A few of those that might obviously be useful as targets 
include: 

XA_STRING 

XA_INTEGER 

XA_BITMAP 

At present, the Athena widgets and the clients in the MIT core X distribution use only 
XA_STRING as a target. However, one can imagine uses for other targets as well. For 
example, XA_FONT might be used as a target to indicate that the requestor doesn t want the 
text of a selection, but wants only to know its font XA_TIMESTAMP might be used to indi 
cate that the requestor wants a timestamp for the data. 

Once the xtGetSelectionValue request is made, a SelectionRequest event is 
generated, which Xt uses to invoke the owner widget s convert_proc. The 
convert^proc will need to branch according to the target type passed in by the requestor 
through Xt, and convert the data accordingly before transferring the selection to the 
requestor. 

For selection of multiple data types to work correctly between any two arbitrarily chosen 
widgets, there must be conventions about which targets will be supported. As a step in the 
direction of interwidget selection compatibility, the ICCCM specifies a required target type of 
XAJTARGETS, to which the owner is supposed to respond by returning a list of the target 
types into which it is capable of converting data. We ll talk about how to work with this tar 
get in Section 10.2.9. 

In a custom widget such as BitmapEdit, which has a custom data type not represented by a 
predefined atom, it is possible to obtain a custom atom using XinternAtom, and use that 
as the target. Because the XinternAtom call requires a round trip to the server, the best 
place to do this is in the widget s initialize method.* The returned atom can be stored 
in a field added to the widget s instance part. BitmapEdit s target type, "CELL_ARRAY," is 
unique to BitmapEdit. The atom is stored in an instance part field called target so that it 
is available in convert_proc and in the requestor role code. Example 10-4 shows the 
code added to the initialize method to get an atom for the string "CELL_ARRAY." 

Example 10-4. BitmapEdit: getting the atom fora widget-specific target type 

/* ARGSUSED */ 

static void 

Initialize (request, new) 




"Since Xlib functions causing round-trip requests can impact performance, they should be called only once if pos 
sible, and where possible, during the set-up phase of the application as opposed to the event-loop phase. If 
XinternAtom were called every time the user made a selection, it would slow the application. In addition, since 
atoms are server resources that are not freed until the server shuts down, it is important to use predefined atoms 
whenever possible. 



Interclient Communications 291 



Example 10-4. BitmapEdit: getting the atom fora widget-specific target type (continued) 
BitmapEditWidget request, new; 



new->bitmapEdit .target_atom = XInternAtom(XtDisplay (new) , 
"CELL_ARRAY, " FALSE); 

The target type property name used by BitmapEdit is "CELL.ARRAY." 

The third argument to xinternAtom is a Boolean that indicates what to do if the atom 
doesn t already exist. If this argument is TRUE, XinternAtom will return None. This 
argument should always be FALSE if you want to create a new atom. 

Note that for repeated calls to xtinternAtom with the same string as an argument, even 
from different widgets, the returned atom will be the same. There will be only one atom 
created for any unique string interned on a given server. (Case is important: "Cell_Array" 
would return a different atom than "CELL_ARRAY".) 

This XinternAtom call occurs in every instance of the BitmapEdit widget, since there is 
no way for the widget instance to know that other instances exist or whether they have 
already interned an atom. Both the owner and requestor widgets, in separate applications, 
will get the same atom in return. 

10.2.4.2 The Paste Action from BitmapEdit 

To initiate the requestor role, you need to assign an event sequence to trigger the pasting, and 
to write an action that calls XtGet Select ionValue, and a callback function that inserts 
the returned data. 

Traditionally the action to paste data is triggered by a press of the second pointer button. 
BitmapEdit will use the shifted second button since it uses the unshifted button for other pur 
poses. Example 10-5 shows the action mapped to Shif t<Btn2Down>. 

Example 10-5. BitmapEdit: action to paste a selection 

static void 

PasteSelection (w, event) 
BitmapEditWidget w; 
XButtonEvent *event; 
{ 

XtGetSelectionValue(w, XA_PRIMARY, w->bitmapEdit . target_atom r 

requestor_callback, event, 

event->time) ; 
} 

This action can be dropped verbatim into your widget, replacing only the name of the 
instance fields you are using to store the target atom. 



292 X Toolkit Intrinsics Programming Manual 



Converting the Selection (Owner) 

The real challenge in handling selections is writing the convert^proc, which converts 
data to the format specified by the requestor and prepares it for transfer. 

As mentioned above, the widget s convert^proc is called by Xt when the requestor calls 
XtGetSelectionValue. The procedure is passed the selection atom and the target 
atom, and is expected to return in its arguments the type, value, size, and format of the 
converted selection data. 

To support the possibility of having to convert the data to any one of several targets, the code 
branches according to the value of the target passed in, and does its conversions accordingly. 
In the version of BitmapEdit s convert_proc shown here, only one target type is 
handled, but provision is made for future expansion. 

Once the conversion is made, the procedure sets the value_retuz-n argument passed in to 
a pointer to a block of memory, and length_return to the size of the block. This block 
of memory will be set into a property by Xt and passed to the requestor s callback in the 
same form as a pointer to a block of memory and a length. This puts constraints on the for 
mats that can be used for the data. 

For text selections, the data is usually a simple character string. The convert_j>roc sim 
ply needs to set *value_return to a pointer to the string, and length_return to the 
length of the string. For BitmapEdit, however, the required data is a string (of bitmap cell 
states) plus width and height values. Since C provides easy ways to put numeric values into 
strings and to get them out again at the other end, we ve chosen to handle this data by 
converting the numbers to characters and tacking them on to the beginning of the string. 

If your selection is composed of a number of numeric values, you can create a structure con 
taining the values and then pass a pointer to the structure. However, the structure cannot 
contain pointers, because the data pointed to by these pointers will not be set into the selec 
tion property. For example, BitmapEdit cannot pass a pointer to a structure containing a 
string pointer field and width and height fields, because the block of memory pointed to by 
the string pointer will not be copied. 

In this case, the type_return can simply be the target atom that was passed in, indicating 
that the data is of the requested type. 

The f ormat_return is the size in bytes of each element in the array. Since we are pass 
ing a compound string, this value is 8. If we were passing a structure, length_return 
would be 1 and *f ormat_return would be 8 times the size of the structure in bytes. 

Example 10-6 shows BitmapEdit s convert_proc. 

Example 10-6. BitmapEdit: converting the selection value 

static Boolean 

convert_proc (w, selection, target, type_return, value_return, 

length_return, format_return) 
BitmapEditWidget w; 
Atom *selection; 
Atom *target; 
Atom *type_return; 



Interclient Communications 



Example 1 0-6. BitmapEdit: converting the selection value (continued) 

caddr_t *value_return; 
unsigned long *length_return; 
int *f ormat_return; 
{ 

int x, y; 

int width, height; 

if (*target == w->bitmapEdit . target_atom) { 
char *data; 

width = w->bitmapEdit . select_end_x - 

w->bitmapEdit . select_start_x; 
height = w->bitmapEdit . select_end_y - 

w->bitmapEdit . select_start_y ; 

/* 8 chars is enough for 2 3-digit numbers and 2 delimiters */ 
*length__return * ((width * height) + 8) * sizeof (char) ; 

data = XtMalloc (*length_return) ; 
sprintf (data, "%d@%d~", width, height); 

for (x = 0; x < width; x++) { 

for (y = 0; y < height; y++) { 

data [8 + x + (y * width)] = 

w->bitmapEdit .cell [ (x + 
w->bitmapEdit . select_start_x) + 
( (y + w->bitmapEdit . select_start_y) * 
w->bitmapEdit .pixmap_width_in_cells) ] ; 

} 
i 

*value_return = data; 

*type_return = w->bitmapEdit . target_atom; 

*format_return = 8; 
return (TRUE) ; 



This code determines the width and height of the selected rectangle from the instance part 
fields, and then allocates enough memory to fit a character array big enough to fit the width 
and height values, delimiters, and a width by height character array. Then it copies the cur 
rent contents of the selected area into the allocated character array. Finally, it sets 
*value_return to point to the compound string, and sets *length_return to the 
length of this string. *f ormat_return is the size in bits of each element in the array, 
which in this case is 8 bits. 



294 X Toolkit Intrinsics Programming Manual 



10.2.6 Finally Pasting the Selection (Requestor) 

When the owner s convert_proc returns, Xt sends a SelectionNotif y event to the 
requestor. The Xt code on the requestor side then invokes the callback routine the requestor 
registered with the call to xtGetSelectionValue. 

The requestor_callback function is passed all the same arguments that the owner 
received in the convert_proc, plus the values that the owner returned through the argu 
ment of convert_proc. In the BitmapEdit widget, it sets instance part fields to paste the 
data. 

Example 10-7 shows the requestor callback function from BitmapEdit 
Example 10-7. BitmapEdit: pasting selection in requestor_callback function 

/* ARGSUSED */ 

static void 

requestor_callback (w, event, selection, type, value, length, format) 

BitmapEditWidget w; 

XButtonEvent *event; /* client_data, to pass press position */ 

Atom *selection; 

Atom *type; 

caddr_t value; 

unsigned long *length; 

int * format; 

{ 

if ((*type = 07* XT_CONVERT_FAIL */) I I (*length ==0)) { 
XBelKXtDisplay(w) , 100); 

fprintf (stderr, "bitmapEdit : no selection or selection\ 
timed out; try again\n"); 

} 
else { 

int width, height; 

int x, y; 

int dst_offset_x, dst_of f set_y; 

char *ptr; 

/* figure pointer position in cells */ 
dst_offset_x = 

(w->bitmapEdit .cur_x + event->x) / 
w->bitmapEdit .cell_size_in_pixels; 
dst_offset_y = 

(w->bitmapEdit .cur_y + event->y) / 

w->bitmapEdit .cell_size_in_pixels; 

. 

/* extract width and height from string */ 

ptr = value; 

width = atoi (ptr) ; 

ptr = index (ptr, @ ); 

ptr++; 

height = atoi (ptr) ; 

/* set ptr to beginning of char array. */ 
ptr = & value [8] ; 

/* copy char array into widget cell array, 

* checking ranges as necessary, and draw 

* cells that change into pixmap. */ 



oat: 

Interclient Communications 




Example 10-7. BitmapEdit: pasting selection in requestor_callback function (continued) 

>-:!::: 

for (x = 0; x < width; x++) { 

for (y = 0; y < height; y++) { 

/* range checking */ 

if ( ( (dst_of f set_x + x) > 

w->bitmapEdit .pixmap_width_in_cells) 
II ( (dst_of f set_x + x) < 0)) 
break; 
if ( ( (dst_offset_y -f y) > 

w->bitmapEdit .pixmap_height_in_cells) 
II ( (dst_of fset_y + y) < 0) ) 
break; 

/* setting cell array */ 

w->bitmapEdit .cell [ (dst_of f set_x + x) + 
( (dst_offset_y + y) * ~ 
w->bitmapEdit .pixmap_width_in_cells) ] 
= ptr[x + (y * width)]; 

/* updating pixmap */ 

if (w->bitmapEdit .cell [ (dst_of f set_x + x) + 
( (dst_offset_y + y) * 

w->bitmapEdit .pixmap_width_in_cells) ] 
== DRAWN) 

DrawCell (w, dst_of f set_x + x, dst_of f set_y + y, 

w->bitmapEdit . draw_gc) ; 
else 

DrawCell (w, dst_of f set_x + "x, dst_of f set_y + y, 
w->bitmapEdit .undraw_gc) ; 



/* the requestor must free the data passed by 

* Xt after using it. */ 
XtFree (value) ; 

/* copy updated pixmap to window */ 
Redisplay (w, NULL) ; 



The requestor_callback first determines whether the conversion was a success by 
checking the target type and data length. If it was not, it beeps and possibly prints a message. 
This can happen if no selection has been made, or if there is some delay that causes the selec 
tion to have timed out before the owner could convert the data. 

If the conversion was a success, the requestor_callback pastes the data. In Bitmap- 
Edit s case, the requestor must first convert the data into a more useful form. This means 
extracting the width and height values, and then setting the widget s cell array based on the 
data in the character array passed in. Note that the code should check to make sure that the 
data can be pasted in the desired position. BitmapEdit must make sure that no attempt is 
made to set a cell array member outside of the bitmap. The routine then updates the screen 
display of the widget. 



296 X Toolkit Intrinsics Programming Manual 



The final responsibility of the request or_callback is to free the memory passed in by 
Xt. 



If the Selection is Lost (Owner) 

If the owner loses the selection, either because the selection timed out or because the user 
made a different selection, the lose_ownership_proc that was registered with its call 
to XtOwnSelection will be invoked. Typically, this function simply clears any high 
lighting or other visual feedback about the selection, and resets to their initial state any inter 
nal variables used in handling selections. 

Example 10-8 shows the lose_ownership_proc from the BitmapEdit widget 
Example 10-8. BitmapEdit: the bse_ownership_proc 

/* ARGSUSED */ 

static void 

lose_ownership_proc (w, selection) 

BitmapEditWidget w; 

Atom *selection; 

{ 

/* clear old selection */ 

w->bitmapEdit . f irst_box = FALSE; 

w->bitmapEdit . select_start_x = 0; 

w->bitmapEdit . select_start_y = 0; 

w->bitmapEdit . select_end_x =0; 

w->bitmapEdit . select_end_y = 0; 

Redisplay (w, NULL); 



When the Selection Transfer is Complete (Owner) 

The transfer_done_j>roc, registered in the call to XtOwnSelection, is called 
when the transfer is complete. It s job is to do any processing necessary to get ready for the 
next selection request In many cases no processing is necessary and this function can be 
NULL in the call to XtOwnSelection. However, this function might clear variables or 
free memory. Some transfers are intended to be made only once, to make sure that there is no 
duplication of information. In these cases, the transfer_done_proc would do a lot 
more, including erasing the visual selection, calling xtDisownSelection (and perhaps 
even erasing the data that was selected). 




Interclient Communications 29? 



10.2.9 ICCCM Compliance 

For any two widgets to be able to transparently transfer different types of data, there must be 
agreement about the possible target types and their contents. The ICCCM suggests a list of 
possible target types, as shown in Table 10-2. If you can, use one of these target types since 
this will increase the chances that your widget will be able to communicate with widgets 
written by other people. 



Table 10-2. Target Types Suggested in ICCCM 



Atom 



TARGETS 

MULTIPLE 

TIMESTAMP 

STRING 

TEXT 

LIST_LENGTH 

PKMAP 

DRAWABLE 

BITMAP 

FOREGROUND 

BACKGROUND 

COLORMAP 

ODIF 

OWNER_OS 

FILE.NAME 

HOSTJSTAME 

CHARACTER_POSmON 

LINE_NUMBER 

COLUMN_NUMBER 

LENGTH 

USER 

PROCEDURE 

MODULE 

PROCESS 

TASK 

CLASS 

NAME 

CUENT.WINDOW 

DELETE 

INSERT_SELECnON 

INSERT PROPERTY 



Type 



ATOM 

ATOM_PAIR 

INTEGER 

STRING 

TEXT 

INTEGER 

DRAWABLE 

DRAWABLE 

BITMAP 

PIXEL 

PIXEL 

COLORMAP 

TEXT 

TEXT 

TEXT 

TEXT 

SPAN 

SPAN 

SPAN 

INTEGER 

TEXT 

TEXT 

TEXT 

INTEGER, TEXT 

INTEGER, TEXT 

TEXT 

TEXT 

WINDOW 

NULL 

NULL 

NULL 



Meaning 



List of valid target atoms 

Look in the ConvertSelection property 

Timestamp used to acquire selection 

ISO Latin 1 (+TAB+NEWLINE) text 

Text in owner s encoding 

Number of disjoint parts of selection 

Pixmap ID 

Drawable ID 

Bitmap ID 

Pixel value 

Pixel value 

Colormap ID 

ISO Office Document Interchange Format 

Operating system of owner 

Full path name of a file 

See WM_CLIENT_MACHINE 

Stan and end of selection in bytes 

Stan and end line numbers 

Stan and end column numbers 

Number of bytes in selection 

Name of user running owner 

Name of selected procedure 

Name of selected module 

Process ID of owner 

Task ID of owner 

Class of owner see WM_CLASS 

Name of owner see WM_NAME 

Top-level window of owner 

TRUE if owner deleted selection 

Insert specified selection 

Insert specified property 



More entries are expected to be added. 



298 



X Toolkit Intrinsics Programming Manual 



Because not every widget will support every possible target type, the ICCCM specifies a tar 
get type of XA_TARGETS, to which the owner is required to respond by returning a list of the 
target types into which it is capable of converting data. 

Normally, a requestor would first call xtGet Select ionValue for XAJTARGETS, and 
then, in the callback, determine which target it wants to request from the list, and then call 
xtGetSelectionValue again for the desired target with a separate callback to process 
the actual data. This is really two separate selection transfers. 

In Release 3, though, XA_TARGETS itself is not yet implemented as a predefined atom. To 
use it, you must use the Xmu atom caching mechanism described in Section 10.2.9.1. 

Fortunately, there is existing template code that you can copy to handle XA_TARGETS and 
some other standard target types that are required by the ICCCM. 

This template code uses the Xmu routine XmuConvertStandardSelection. It also 
uses an Xmu atom-caching facility that eliminates the need for xinternAtom calls for 
each of the ICCCM standard target atoms.* 

Xmu Atom Caching 

Xmu s caching facility uses symbols similar to those defined in <XlllXatom.h>, only in this 
case, they are macros that take an argument and call XmulnternAtom, For example, the 
macro for XAJTARGETS is defined as follows in <XlllXmu.h>: 

fdefine XAJTARGETS (d) XmulnternAtom (d, _XA_TARGETS) 

where d refers to a pointer to a Display structure. (This can be returned by the xt- 
Di splay macro.) The XmulnternAtom function first tries to get the atom for the string 
"XAJTARGETS" from Xmu s internal cache. If Xmu doesn t yet have a value for the atom, it 
calls XinternAtom to make a server request Because this facility makes only one query 
to the server, you can access the atoms in this way every time a selection is made without sig 
nificant penalty. This allows you to place the XA_TARGETS ( ) macro in your selection 
code instead of adding an instance part variable and setting itintheinitialize method. 

You might use this macro as follows in a convert_proc branch dedicated to handling the 
TARGETS target type: 

if (*target == XA_TARGETS (XtDisplay (w) ) ) { ... 

The Xmu atom caching mechanism must be initialized before you can make calls of the form 
just shown. Example 10-9 shows the code that should be placed in the widget s 
initialize method to initialize this mechanism. 



"Since the adoption of the ICCCM as an X Consortium standard occurred fairly recently, the list of atoms supported 
by the Xmu atom caching mechanism may change radically. For example, in Release 3, neither XAJTARGETS nor 
XA_CLIPBOARD is defined as a predefined atom, even though they are required by the ICCCM. See <Xll/Xmu.h> 
under Release 3 or <Xll/XmuJ Atoms. h> under Release 4 for the list of predefined atoms on your system. 



Interclient Communications 299 



Example 10-9. BitmapEdit: initializing Xmu s atom caching m&chanism in the initialize method 

(void) XmuInternAtom( XtDisplay (new) , XmuMakeAtom( n NULL") ); 



10.2.9.2 Converting the Standard Selections 

The Xmu routine XmuConvertStandardSelection can be used to respond to a 
TARGETS selection request, as well as to other standard targets denned by Xmu. 

Example 10-10 shows the portion of the convert_proc for BitmapEdit that handles the 
standard targets. 

This code is adapted from the standard client xclipboard, and can be copied almost directly 
into your widget 

Example 10-10. BitmapEdit: converting standard targets in the convert_proc 

static Boolean 

convert_proc (w, selection, target, type_return, value_return, 

length_return, format_return) 
!p BitmapEditWidget w; 
Atom *selection; 
Atom * target; 
Atom *type_return; 
caddr_t *value_return; 
unsigned long *length_return; 
int *format_return; 

int x, y; 

int width, height; 

/* handle TARGETS target */ 
if (*target == XAJTARGETS (XtDisplay (w) )) { 
Atom* targetP; 
Atom* std_targets; 
unsigned long std_length; 

XmuConvertStandardSelection (w, CurrentTime, selection, 
target, type_return, 
(caddr_t*) &std_targets, 
&std_length, format_return) ; 

*value_return = XtMalloc (sizeof (Atom) * (std_length + 1)); 
targetP = * (Atom**) value_return; 
*length_return = std_length + 1; 
*targetP++ = w->bitmapEdit .target_atom; 
bcopy ( (char*) std_targets, (char*) targetP, 

sizeof (Atom) *std_length) ; 
XtFree ( (char*) std_targets) ; 
*type_return = XA_ATOM; 
*format_return = sizeof (Atom) * 8; 
ret urn (TRUE) ; 



/* Xt already handles MULTIPLE, no branch needed */ 

/* Handle expected selection target */ 

else if (*target == w->bitmapEdit . target_atom) { 

/* code shown and described earlier in text */ 



300 



X Toolkit Intrinsics Programming Manual 



Example 10-10. BitmapEdit: converting standard targets in the convert_proc (continued) 



else { 

/* Handle other standard targets defined by Xmu */ 
if (XmuConvertStandardSelection(w, CurrentTime, 

selection, tarrget, type_return, 
value_return, length_return, 
forma t_return) ) 
return TRUE; 
else { 

fprintf (stderr, "bitmapEdit : requestor is requesting", 

"unsupported selection target type.Xn") 
return (FALSE) ; 



Overall, this code handles the TARGETS atom in the first branch, the expected selection target 
in the second, and any remaining standard atoms and any unknown atoms as two cases in the 
third branch. For ICCCM-compliant code, you can copy this entire function into your widget 
and then write just the second branch. Note that branches that successfully provide the 
requested data return TRUE, and ones that don t return FALSE.* 

In the first branch you will also need to change the reference to the instance part field that 
stores the target atom used for selections, bitmapEdit . target_atom. If your widget 
uses a predefined atom or one supported by the Xmu facility, you would reference that atom 
here instead of the instance part field. If you called xinternAtom in initialize and 
stored the result in an instance part field, you specify that here. 

10.2.9.3 The Clipboard Selection 

According to the ICCCM, if a widget or application allows the user to delete a selection, the 
selection owner code should place the deleted data on the CLIPBOARD selection.! The wid 
get should be prepared to respond to a request for the contents of the CLIPBOARD, much as 
it does for the PRIMARY selection. The only client that requests data in this way will be 
xclipboord. 

Except when a widget asserts ownership of the CLIPBOARD with XtOwnSelection in 
order to place newly deleted data on it, the xdipboard client is the owner of this property. 
When it starts up, xdipboard asserts ownership of the CLIPBOARD selection. If it loses the 
selection (which will happen whenever a widget or client has newly deleted the contents of a 



*The ICCCM also specifies that functions implementing selections must be able to respond to a MULTIPLE target val 
ue, which is used to handle selections too large to fit into a single property. However, the necessary handling is done 
by the Intrinsics. Your procedures do not need to worry about responding to the MULTIPLE target value; a selection 
request with this target type will be transparently transformed into a series of smaller transfers. 
fAs mentioned earlier, XA_CLIPBOARD is not a predefined atom, and must be handled via the Xmu atom caching 
mechanism or equivalent code. 



Interclient Communications 301 



selection), it obtains the contents of the selection from the new owner, then reasserts its own 
ownership of the selection. 

Clients wishing to restore deleted data should request the contents of the CLIPBOARD, 
using the same techniques as we ve shown for the PRIMARY selection, xclipboard will 
respond to these requests, returning the deleted data. 

The use of xclipboard allows the value of a selection to survive the termination of the origi 
nal selection owner. 



10.2.10 Miscellaneous Selection Routines 

If the user deletes the information selected, the owner should call XtDisownSelection. 
If the trans fer_done_jproc is used because the selection is intended to be made only 
once, it should call XtDisownSelection, as well as erasing the highlighting of the visi 
ble selection. 

xtSetSelectionTimeout sets the time within which widgets must respond to one 
another. This is initially set by the XtNselectionTimeout resource, and defaults to 5 
seconds. This prevents hanging when the user pastes but the current owner is slow or hung. 
xtGetSelectionTimeout reads the current selection timeout value. Widgets should 
not normally require these two calls, since the selection timeout should remain under the 
user s control. 

If the requestor can request more than one target type, such as TARGETS and its normal selec 
tion target, it normally does so using separate actions. (Both actions can be invoked by the 
same triggering event, if desired.) Each action specifies a different target type and a different 
requestor callback. That way, each requestor callback handles only one type of target. 

Beware: there is a danger in this approach. There is a chance that the selection owner might 
change between the repeated XtGetSelectionValue calls. XtGetSelection- 
vaiues (plural) can be used instead if the requestor would like to receive the data in more 
than one representation. The requestor s single callback function would then be called once 
for each representation. (The owner s convert_proc would also be called once per rep 
resentation.) 



302 X Toolkit Intrinsics Programming Manual 



11 



Geometry Management 



This chapter discusses how composite and constraint widgets manage the 
layout of widgets, and how to write your own simple composite and constraint 
widgets. 



In This Chapter: 

How Composite Management Works 306 

Initial Geometry Negotiation 308 

User Resizes the Application 31 1 

Widget Desires a Size Change 31 1 

Application Resizes a Widget 312 

Writing a Composite Widget 312 

Basic Core Methods in Composite Widgets 315 

Laying Out Child Widgets 317 

The changejnanaged Method 319 

XtQueryGeometry and the query_geometry Method 320 

XtMakeGeometryRequest and the geometryjnanager Method 320 

The set_values_almost Method 322 

The insert_child and delete_child Methods 323 

How Constraint Management Works 325 

Writing a Constraint Widget 325 

The Core Resource List 325 

The Constraint Resource List 326 

Class Structure Initialization 327 

The Constraint initialize Method 329 

The class_part_init Method 331 

The geometryjnanager Method 332 

The resize Method .. .. 336 



The Core and Constraint set_values Methods 338 

The changejnanaged Method 338 

The query_geometry Method 339 

Delaying Geometry Recalculation 340 

Compound Widgets 340 

Stacking Order 341 



11 

Geometry Management 



Composite and constraint widgets lay out the widgets in your application according to certain 
rules. You cannot hardcode the position of widgets in an application because X applications 
can be resized and they must reposition their widgets to take advantage of the available 
space. Because of the window manager, even the initial size of the application may not be 
the application s preferred size. 

Chapter 3, More Widget Programming Techniques, demonstrated how you can use existing 
composite and constraint widgets in the application. You can control widget layout rules 
with resources. However, you may find that no existing composite or constraint widget can 
be configured with resources to have the layout rules you need. In this case, you will need to 
write your own composite or constraint widget, or modify an existing one. However, before 
embarking on writing one of these widgets, you should realize that composite and constraint 
widgets are complex. First investigate the alternatives! Perhaps you can find a composite or 
constraint widget from another widget set that has the layout characteristics you need. If you 
determine that you have no alternative but to write your own composite or constraint widget, 
you should keep it as simple as possible. It is much easier to write a special-purpose widget 
that handles a limited layout situation than it is to write a general-purpose composite or con 
straint widget like Box or Form. And even Box and Form are simple as composite and con 
straint widgets go! 

A composite widget is defined as any widget that is a subclass of the Xt-defmed class Com 
posite. A constraint widget is any widget that is a subclass of the Xt defined class Con 
straint Constraint is a subclass of Composite. As you may recall, a composite widget is the 
simplest kind of geometry-managing widget; it handles all its children equally, or handles 
each child in a fixed way. For example, the Box widget handles all of its children equally. 
As an example of a special-purpose composite widget, Section 11.2 describes a composite 
widget called ScrollBox that manages two scrollbars and a main window. This widget 
requires that it have exactly three children added in a particular order. 

A constraint widget has all the characteristics of composite widgets, but maintains configur 
able data about each child so that it can cater to the needs of each child. By setting the con 
straint resources of a child of a constraint widget, you configure the constraint widget s lay 
out policy for that child. Constraint widgets are inherently more powerful than composite 
widgets, but also more complicated to write. A constraint widget requires all the code of a 
composite widget, plus code to handle the constraints of each child. Because of this com 
plexity, you should hesitate even further before attempting to write a constraint widget. As 



Geometry Management 305 




an example of the code for a constraint widget, this section describes the Athena Form 
widget 

Composite and constraint widgets can be used within widgets as well as within applications. 
For example, you may recall that the xbitmap application was implemented using the 
BitmapEdit widget and adding scrollbars from the application. We could rewrite the Bitmap- 
Edit widget to provide its own scrollbars, controllable through resources. This widget would 
create a composite widget and three children; BitmapEdit and two Scroll widgets. This kind 
of compound widget is actually made up of several widgets, but to the application writer it 
should act like a single widget The advantage of this rewrite would be that the application 
code would become simpler, and the bitmap editor with scrollbars could be easily used in 
other applications. The fourth major section of this chapter describes how to write a com 
pound widget 

It is a good idea to define exactly what is meant by the geometry of a widget. The geometry 
of a widget is its position, its size, and its border width. These are the Core fields x, y, 
width, height, and border_width. Border width is included because window posi 
tions are measured from the origin of the parent (the top-left corner inside the border of the 
parent) to the top-left corner outside the border of the child. Therefore, changing the border 
width of a widget by 1 pixel moves the origin of that widget 1 pixel along both the x and y 
axes relative to its parent. This concept is shown in Figure 11-1. 

Geometry management may also control the stacking order of a group of children (that is, 
which children appear to be on top). However, control of the stacking order is more manual 
than control of geometry, because it isn t completely built into Xt. 



11.1 How Composite Management Works 

Like simple widgets, the characteristics of a composite widgets are defined by their methods. 
The key methods in a composite widget are the Core methods resize and 
query_geometry and the Composite methods geometry_manager and 
change_managed. We will discuss these methods first, and then move on to the other 
methods defined by Composite, insert_child and delete_child, which are infre 
quently used. 

We ll begin with a summary of what these four most important methods do. In short, they 
handle interactions with the three generations of widgets involved in direct geometry interac 
tions with a composite widget; the parent of the composite widget the composite widget 
itself, and the children of the composite widget 

The resize method moves and resizes the child widgets as necessary to fit within the 
composite widget s new size. 

The query_geometry method supplies a preferred geometry to a widget s parent 
when the parent calls xtQueryGeometry. The parent makes this call in the process 
of determining a new layout for its children. 

The geometry_manager method handles resize requests from the child widgets. 
Usually, the only kind of child that will make a resize request to the parent is another 



306 X Toolkit Intrinsics Programming Manual 



parent window 
origin (0, 0) ~ 



child origin - 



(x,y) 

position of 
child within 
parent 
measured to 
this point 



parent - I 

border_width 
not involved in 
child geometry 



X increasing 



- parent window 



increasing 



border width 



height 



width 



y 




Figure 11-1. Role of border width in widget geometry 

composite or constraint widget However, some simple widgets do request resizing. For 
example, when a Label widget s string is changed through resources, the Label widget 
increases its own size (this is allowed only in the set_values method). Xt then calls 
the parent s geometry_manager method, which must decide whether this new size is 
acceptable and then make any changes. When a child widget asks for more space and the 
composite widget doesn t have enough, the composite widget s geometry_manager 
may ask its own parent for more space by calling XtMakeGeometryRequest. 

The change_managed method changes the layout of the children when a child is 
managed or unmanaged. This occurs initially when xtRealizeWidget is called 
(after children are created with XtCreateManagedWidget) or when xtManage- 
Child or xtManageChildren is called to add an already-realized widget to a com 
posite parent s managed set (A widget can be unmanaged later to remove it from the 
screen without destroying it, and managed again at any time. Each time a child is man 
aged or unmanaged, or destroyed, the change_managed method is called.) 

The resize and query_geometry methods were already introduced in Chapter 6, 
Basic Widget Methods, as they apply in simple widgets. In composite widgets, they have the 
same job, but it is more complicated because they now have children to worry about. We will 
discuss these methods again in this chapter as they appear in composite widgets. 



Geometry Management 



307 



To write any of these four methods, you need to look at all the ways that geometry changes 
can occur, so that you know all the situations in which the methods will be called. The first 
situation is the negotiation that takes place to determine the initial size of each widget when 
an application starts up. Other situations include when the user resizes the entire application, 
when a widget requests a size change from the application, and when a widget is resized by 
the application. As you can see, there are many cases. It helps to be systematic about under 
standing and programming for these cases. The next four sections describe each of these 
cases one at a time. 

The complexity of the geometry negotiations in the following description may be intimidat 
ing. A truly general-purpose composite widget is a large, complex piece of software. You 
should leave this programming to the widget writers that write commercial widget sets, and 
concentrate on things that are more important in your application. The purpose of this 
description is to let you understand how complete composite widgets work, not to suggest 
that you should try to write one. However, it is possible to write small, special-purpose com 
posite widgets that solve particular layout problems. Composite widgets are simpler when 
they are more authoritarian when they don t do as much to try to satisfy the preferences of 
their children. Section 11.2 describes ScrollBox, a simple composite widget designed solely 
to manage a main widget and two scrollbars. Writing this kind of widget is manageable 
because the widget manages a fixed number of children, and has simple layout rules. 

11.1.1 Initial Geometry Negotiation 

At least one geometry negotiation takes place in any application, even if the application is 
never resized. This occurs when an application starts up. 

Figure 11-2 shows the process of initial geometry negotiation in schematic form. 

The call to xtRealizeWidget initiates a two-step process. When xtRealizeWidget 
is called on the top-level widget, most or all of the widgets have been created but windows 
have not been created for them. XtRealizeWidget initiates a geometry negotiation that 
ripples through the widget hierarchy (as is described below). The widgets realize meth 
ods (which create windows for the widgets) are not called until this process is complete. 

XtRealizeWidget first calls the change_managed method of every composite 
widget in the application, beginning with the lowest widgets in the hierarchy (called a post- 
order traversal). Each change_managed method determines an initial size for each child 
and calls xtMoveWidget and/or xtResizeWidget for the child. All the 
change_managed methods are called until the one in the Shell widget (Remember that 
the Shell widget is a composite widget that has only one child.) The child is also a composite 
widget (except in single-widget applications such as xhello). When the Shell widget is 
reached, the Shell widget size is set to the size of its child and the process stops unless the 
user has specified an initial geometry for the entire application through the resource database 
or command line. 

A change_managed method can (but is not required to) determine each of its children s 
preferred geometry by calling xtQueryGeometry for each child. This may result in the 
resize method of the child being called. Instead of calling XtQueryGeometry, the 
change_managed method may use the child s Core width and height fields. 



308 X Toolkit Intrinsics Programming Manual 




change_managed method called from bottom up 




Figure 1 1-2. Initial geometry negotiation, assuming sufficient shell space 

The change_managed method does not determine the composite widget s own size. That 
job is for the parent of the composite widget, which is another composite widget 

If the user-specified, top-level widget geometry is different from the geometry of the Shell 
widget s child after all the change_managed methods are called, then the Shell widget 
resizes its child to the user-specified size. This makes Xt call the resize method of the 
child composite, and this resize method reconsiders the layout of its children. This pro 
cess proceeds down the chain of widgets to the bottom. At each stage the resize method 
can (but need not) call xtQueryGeometry for each child to get each child s opinion of 
the intended geometry for that child. 

Figure 11-3 shows the continued process of initial geometry negotiation if the user has speci 
fied the top-level geometry through resources rather than accepting the application s built-in 
defaults. 

Note that this process and the methods involved are more complicated if the 
change_managed or resize methods call XtQueryGeometry. XtQuery 
Geometry calls a child widget s query_geometry method, as described in Section 6.6. 
When they do call XtQueryGeometry, the change_managed or resize methods 
need to determine a suggestion for the child s geometry, make the XtQueryGeometry 
call, and then do different things depending upon which of the three different answers it 
receives from the child. The xtGeometryAlmost answer includes a suggested compro 
mise. The change_managed or resize method will decide on a new size based on the 
compromise, and may or may not make another XtQueryGeometry call to make this 



Geometry Management 



309 




If user specifies shell geometry, 



resize 



methods called from top down 



Figure 1 1-3. Initial geometry negotiation, if resizing is necessary 

suggestion to the child. The code to perform all of this is extensive because the suggestions 
and answers are in the form of structures with several fields. Only the VPaned (Paned in 
Release 4) and Viewport classes in the Athena set call xtQueryGeometry, and they do so 
only in minimal ways. VPaned takes the height of a pane from the height returned by the 
child query, but only if the child returns XtGeometryAlmost. Since Viewport manages 
only one child (in addition to the scrollbar widgets it creates), it queries that child for its 
geometry in its own query_geometry method (called when queried by its parent), and in 
its resize method. 

Notice that this process can result in the resize, change_managed, and possibly the 
query_geometry methods of every widget being called, but the geometry_manager 
method does not play a part. 

Once this process is complete, xtRealizeWidget calls the realize methods of all the 
widgets and actually creates windows for them. Up to this point, all the methods were simply 
changing the widget size and position parameters in Xt structures, not the sizes of actual win 
dows. XtRealizeWidget also maps all managed widgets. 



310 



X Toolkit Intrinsics Programming Manual 



11 .1 .2 User Resizes the Application 

When xtRealizeWidget returns, most applications call xtMainLoop. Internally, this 
calls the Xlib call XNextEvent which sends the batch of queued window creation and win 
dow map requests to the server. Most window managers intercept the mapping request for 
the top-level window and draw a rubber-band outline of the application on the screen, ready 
for the user to place or resize the application. (Each window manager has a different user 
interface for positioning and sizing the application when the rubber-band outline appears.) If 
the user simply places the application, no new geometry negotiation takes place. But if the 
user resizes the application, a new round of geometry negotiation takes place, identical to the 
process described above where the user specified a top-level widget geometry. 

In other words, the process that occurs when the user supplies a top-level geometry is the 
same when the user resizes the application with the window manager as it is when the user 
specifies top-level widget geometry with resources or the command line. This process was 
illustrated in Figure 11-2 and Figure 1 1-3. 

This process uses all the methods except geometry_manager. 

1 1 .1 .3 Widget Desires a Size Change 

When an application sets a widget resource that affects what is displayed in the widget, it 
may be logical for the widget to ask its parent for a new size. This would occur in the 
set_values method of the widget The widget sets its desired geometry into its Core 
geometry fields (width, height, x, y, and border_width). Xt finishes calling all the 
set_values methods (because they chain), and then calls xtMakeGeome try- 
Request to ask the parent widget for a geometry change. Note that the set_yalues and 
initialize methods are the only place where widgets are allowed to set their own size 
directly. (In set_values they can do so only because of an xtSetValues call to 
change a resource that affects geometry.) 

Figure 11-4 shows what happens when a widget requests a size change. 

Of course, composite widgets often want a size change because their children have asked to 
be resized. The composite widget has no knowledge of what caused the child s size change. 
Therefore, composite widgets call XtMakeGeometryRequest themselves to see if their 
parent will allow them to change size. Composite widgets should request such a change; 
otherwise their parent may have unused space or have other children that need more space. 
However, handling the variety of responses to the request is not trivial. 

For both simple and composite widgets, Xt calls the geometry_manager method of the 
parent widget when XtMakeGeometryRequest is called, and the method is responsible 
for deciding whether to except, reject, or compromise on the requested geometry. The 
geometry_manager method may have to ask its parent to decide whether it can accept 
its child s proposal. If so, it makes another XtMakeGeometryRequest call. This can 
go on to arbitrary depth, and the final answer will trickle back down to the parent of the origi 
nal requestor. The XtMakeGeometryRequest call itself will change the child s 
geometry if the answer is yes. If the answer is no, the child gets this information and may try 



Geometry Management 




another geometry. If the answer is a compromise, then the child will get the compromise 
information returned in its call to XtMakeGeometryRequest and make another request 
to be able to proceed. More on this interaction in Section 1 1.2.5. 

This process uses only the geometry_manager methods of each widget. However, this 
method may call xtQueryGeometry to determine the needs of each of its children before 
replying to the XtMakeGeometryRequest request When the process is finsished, the 
resize method is called for any widgets that have been resized. However, the 
change_managed method is never involved. 

11 .1 .4 Application Resizes a Widget 

An application may change the size of a widget by setting the xtNx, xtNy, xtNwidth, 
xtNheight, or xtNborderWidth resources directly (as opposed to setting a resource 
which indirectly affects the size, as covered in the last section). If that widget has no chil 
dren, the widget code does nothing, but Xt queries the parent with an XtMakeGeometry 
Request. The complete negotiation process as described for xtRealizeWidget is 
repeated, except that the current top-level Shell size is used as a user-specified size (because 
ultimately it is). 

Although the widget code did nothing, the set_values method sets the new values speci 
fied through resources into the Core fields. If the XtMakeGeometryRequest request is 
denied by the parent, Xt sets these Core fields back to their original values. If the parent sug 
gests a compromise, the set_values_almost method, which is described below, is 
called. 

If the widget whose size is changed is a widget with children, the negotiation process is the 
same, except that when it is complete the children of the widget need to be laid out, and if the 
children have children they need to be laid out too, and so on. 



1 1 .2 Writing a Composite Widget 

The process of writing a composite widget is the same as writing a simple widget You copy 
the three files of some existing composite widget, perhaps Composite itself, make global 
name changes to make the files a skeleton for a distinct class, and then write new methods. 

As mentioned earlier, writing a general-purpose composite widget is not a trivial task and 
should be done only when other options fail. Because composite widgets have no user inter 
face, you may be able to find a composite widget with the proper characteristics from another 
widget set There are several public domain widget sets to look in. Note, however, that com 
mercial widget set vendors may design in a private protocol between their composite widgets 
and their children, which make the composite widgets unable to correctly manage widgets 
from other sets. And if you are writing a commercial product, you may have to pay a binary 
license fee to the commercial widget set vendor for each copy of your product Especially 
for large software houses, it is a good idea to have at least one programmer adept at writing 
composite widgets and the query_geometry methods of simple widgets. 



312 X Toolkit Intrinsics Programming Manual 



3] Application sets a resource that changes 
requirements of widget D. 




Xt calls resize method of widget D. 
(If B had suggested a compromise, Xt 

would call the set_values_almost 

method of D) 



[2] Widget D s set_values 
method sets its core width 
and height to its desired 
size. 



Xt determines if widget D has 
proposed a new size. Xt calls 

XtMakeGeometryRequest 

to ask B (D s parent) about 
D s proposed new size. 



B S geometry_manager 

method accepts, rejects, 
or suggests compromise 
size. B is composite and 
may ask parent A. 
Assume B has room and 
accepts D s proposal. 



Requests trickle up until widget is found that: 

has room to accomodate the change without 
resizing itself. This widget s 

geometry_manager accepts the Child proposal. 



or 



never asks its parent for a size change. 



(Requests that reach the shell widget will be 
denied because most window managers currently 
ignore shell size change requests) 



Window Hierarchy 




Figure 11-4. A widget requesting a size change 



313 



Small scale composite widgets that handle a small set of circumstances are not difficult to 
write, because you can make a number of simplifying assumptions. As an example, this sec 
tion describes a very simple composite widget called ScrollBox, which is designed to manage 
a BitmapEdit widget (or any other main widget) and two Athena Scroll widgets. It handles 
only these three widgets, and they must be added in a particular order. Because we know the 
geometry preferences of these three widgets (the bigger the better, but no size in particular), 
we can dispense with querying them about their preferred geometry. We also know that none 
of our children will request to be resized. Therefore, we do not need a 
geometry_manager method. 

A ScrollBox widget is shown managing BitmapEdit and two scrollbars in Figure 11-5.* 

The Athena Viewport widget does scrollbar management in a more general way than does 
ScrollBox. It is a subclass of Form that takes any main window as a child and creates 
scrollbars. It shows only a small portion of the main window, and uses the scrollbars to 
determine which portion of the main window is shown. But Viewport doesn t work well with 
BitmapEdit because BitmapEdit has a built-in ability to display in a smaller window that 
conflicts with Viewport s efforts. Besides, Viewport is several times larger and more compli 
cated than ScrollBox, because it includes the scrollbar callback functions and because it hon 
ors a child s geometry preferences. ScrollBox is a modest widget that manages the geometry 
of scrollbars, leaving their connection with the main window up to the application. This 
demonstrates the essential elements of a composite widget without too much complication.! 

The ScrollBox widget code, along with a version of xbitmap that uses it, is available in the 
example source in the ch09 directory. It lays out its children by adjusting the width and 
height of the three children so that they fill the ScrollBox widget, while keeping the width of 
the Scroll widgets constant. The width of the Scroll widgets is set through their resources, 
and never modified by ScrollBox. 

The first few sections below describe the methods that are used in ScrollBox and that are 
required in all composite widgets. First, we discuss the Core initialize, realize, 
set_values, resize, and query_geometry methods as they are used in composite 
widgets. Then, we discuss how the ScrollBox widget implements layout calculations in a 
common routine called by the set_values, resize, and change_managed values. 
This is followed by further discussion of the change_managed and query_geometry 
methods. Then, we go on to discuss the methods not used by ScrollBox, but that would be 
used in more complicated composite widgets, in particular geometry_manager. Finally, 
we briefly discuss the methods available in composite widgets but rarely needed: 
set_values_almost, insert_child, and delete_child. 



*ScrollBox widens the borders of its children, for an unknown reason. It might as well be admitted that there is prob 
ably a bug in it somewhere! 

fit is worth noting that the Box widget fails miserably in managing scrollbars, while Form is adequate but has the an 
noying characteristic that it resizes the width of the scrollbars as well as their length, sometimes resulting in bloated 
or m in iscule scrollbars. 



314 X Toolkit Intrinsics Programming Manual 





Figure 1 1-5. A ScrollBox widget at two different sizes 

11.2.1 Basic Core Methods in Composite Widgets 

Both composite and constraint widgets are subclasses of Core. Therefore, they have all the 
Core methods described in Chapters 5 and 6. However, since composite and constraint widg 
ets usually have no input and output semantics, the expose method is set to NULL and the 
widget has no default translation table or actions. As a result, all the event-oriented fields in 
the Core class structure become irrelevant to composite and constraint widgets. 

But composite and constraint widgets do use the Core initialize, realize, and 
set__values methods. These methods have the same roles as for simple widgets. The 
initialize method initializes instance part variables and checks initial resource values. 
The realize method sets window attribute values and then creates a window for the 
widget The set_values method updates any instance part fields that depend on 



Geometry Management 



315 



resources. Since composite and constraint widgets don t need GCs, initialize and 
set_values don t contain code to create and change GCs as they would in simple widg 
ets. 

These three methods for ScrollBox are absolutely minimal, and call a common routine called 
DoLayout when any actual sizing or positioning of widgets is required. The initial 
ize method simply sets the widget s default width and height, the realize method is 
inherited, and the set_values method changes the layout of children when either of 
ScrollBox s two resources is changed. These resources control the vertical and horizontal 
distance in pixels that will be left between the Scroll widgets and the main widget, and 
between each of these widgets and the borders of ScrollBox. Example 11-1 shows the 
set_values method of ScrollBox. 

Example 11-1. ScrollBox: the set_values method 

/* ARGSUSED */ 

static Boolean SetValues (current , request, new) 

ScrollBoxWidget current, request, new; 

{ 

/* need to redo layout if h_space or v_space change */ 
if ( (new->scrollBox.h_space != current->scrollBox.h_space) I I 
(new->scrollBox. v_space != 

current->scrollBox. v_space) ) 
DoLayout (new) ; 

/* nothing to redisplay, always returns FALSE */ 
return FALSE; 
} 

Two more Core methods are used in composite widgets: resize and query_geometry. 
The resize method changes the layout of its children, and is shown in Example 11-2. 

Example 11-2. ScrollBox: the resize method 

static void Resize (w) 
ScrollBoxWidget w; 
{ 

DoLayout (w) ; 
i 

The query_geometry method answers the parent s inquiry about a size change for this 
composite widget, and is shown in Example 11-3. 

Example 11 -3. ScrollBox: the query_geometry method 

/* ARGSUSED */ 

static XtGeometryResult QueryGeometry (widget, request, reply_return) 

ScrollBoxWidget widget; 

XtWidgetGeometry *request, *reply_return; 

{ 

XtGeometryResult result; 

request->request_mode &= CWWidth I CWHeight; 

if (request->request_mode == 0) 

/*parent won t change w or h, so nothing to re-compute*/ 
return Xt Geometry Yes; 



316 X Toolkit Intrinsics Programming Manual 



Example 11 -3. ScrollBox: the queiy_geometry method (continued) 

/* if proposed size is large enough, accept it. 
* Otherwise, suggest our arbitrary initial size. */ 

if (request->request_mode & CWHeight) 

if (request->height < INITIAL_HEIGHT) { 

result = XtGeometryAlmost; 

reply_return->height = INITIAL_HEIGHT; 

reply_return->request_mode &= CWHeight; 
} 
else 

result = XtGeometryYes; 

if (request->request_mode & CWWidth) 

if (request->width < INITIAL_WIDTH) { 
result = XtGeometryAlmost; 
reply_return->width = INITIAL_WIDTH; 
reply_return->request_mode &= CWWidth; 
} 

return (result) ; 
} 

Although the query_geometry method has the same role in all widgets, composite and 
simple, a composite widget s size preference depends on its children. Normally this means 
the query_geometry method will query its children and try different layouts until it 
arrives at the geometry, or some approximation of it, suggested by its parent . This calcula 
tion is complicated because the widget may have any kind of child and their responses to 
geometry suggestions are unpredictable. ScrollBox ignores this complexity because it knows 
exactly what kinds of children it will have and what their characteristics are. Therefore, its 
query_geometry method is basically the same as the query_geometry method of a 
simple widget. 

To be more precise, what this query_geometry method does is accept any size suggested 
by the parent which is larger than the minimum useful size of the application. When the sug 
gested size is too small, the query_geometry method uses the minimum useful size as a 
compromise. Note, however, that this is really hardcoding the characteristics of the child into 
our composite widget. It would be better to add resources to control the minimum useful 
size. 



11.2.2 Laying Out Child Widgets 

Composite widgets need to calculate a layout and manipulate their child widgets from 
set_values, from resize, and from change_managed. Therefore, in most compos 
ite widgets this common code is placed in a single routine called DoLayout. Example 11-4 
shows the DoLayout routine from ScrollBox. 




Geometry Management 317 



Example 11-4. ScrollBox: private routine to lay out child widgets 

/* ARGSUSED */ 
static DoLayout (sbw) 
ScrollBoxWidget sbw; 

Widget main, vscroll, hscroll; 

Widget child; 

Dimension mw, mh; /* main window */ 

Dimension vh; /* vertical scrollbar length (height) */ 

Dimension hw; /* horizontal scrollbar length (width) */ 

Position vx; 

Position hy; 

int i; 

if (sbw->composite .num_children != 3) 

fprintf (stderr, "scrollBox: must manage exactly \ 
three widgets . \n") ; 



for (i = 0; i < sbw->composite .num_children; 
child = sbw->composite .children [i] ; 
if ( IXtlsManaged (child) ) 

fprintf (stderr, "scrollBox: all three widgets \ 

must be managed. \n") ; 
} 

/* 

* Child one is the main window, two is the vertical 

* scrollbar, and three is the horizontal scrollbar. 
*/ 

main = sbw->composite .children [0] ; 
vscroll = sbw->composite .children [ 1] ; 
hscroll = sbw->composite .children [2] ; 

/* 

* Size all three widgets so that space is fully utilized. 
*/ 

mw = sbw->core .width - (2 * sbw->scrollBox.h_space) - 

vscroll->core .width - (2 * vscroll->core .border_width) - 
(2 * main->core .border_width) ; 

mh = sbw >core . height (2 * sbw->scrollBox. v_space) - 

hscroll->core .height - (2 * hscroll->core .border_width) - 
(2 * main->core .border_width) ; 

vx = main->core.x + mw + sbw->scrollBox.h_space + 

main->core .border_width + vscroll->core .border_width; 

hy = main->core.y + mh + sbw->scrollBox. v_space + 

main->core .border_width + hscroll->core .border_width; 

vh = mh; /* scrollbars are always same length as main window */ 
hw = mw; 

XtResizeWidget (main, mw, mh) ; 

XtResizeWidget (vscroll, vscroll->core .width, vh) ; 
XtMoveWidget (vscroll, vx, vscroll->core .y) ; 

XtResizeWidget (hscroll, hw, hscroll->core .height) ; 
XtMoveWidget (hscroll, hscroll->core .x, hy) ; 



318 X Toolkit Intrinsics Programming Manual 



In general, DoLayout moves and resizes the child widgets according to its layout policy. 
This routine may query the children with XtQueryGeometry before making decisions, 
but it is not required to. In this case, there is no need to because ScrollBox handles only two 
types of widgets with no size preferences. 

DoLayout is passed only one argument, ScrollBox s own widget ID (a pointer to its widget 
instance structure). But the composite children field in ScrollBox s instance structure is 
an array of the IDs of all the children, and num_children is the number of children.* 

When each child is added to a composite widget, its ID is added to the children field of 
the composite part of the instance structure, and the num_children field is incremented. 
Therefore, the code to lay out the children is usually a loop that treats each child one at a 
time. This often takes two passes, since the routine needs to know which children are 
managed before it can determine their final geometries. All children, even unmanaged ones, 
are listed in the children and num_children fields. 

This particular DoLayout procedure makes sure that there are exactly three children and 
that they are all managed. Then, it calculates the positions and sizes for all the children so 
that they will fill all the available space in ScrollBox s own window. Finally, it calls xt- 
ResizeWidget and xtMoveWidget, which check to see if there was any change before 
making Xlib calls to move and resize the windows. 

11.2.3 The changejnanaged Method 

In every composite widget, the change_managed method is called once (and only once, 
even when there are multiple children) during the xtRealizeWidget process to deter 
mine an application s initial layout. change_managed is also called when an application 
later unmanages a managed widget or manages an unmanaged widget (as long as the xt- 
NmappedWhenManaged resource has its default value). Therefore, change_managed 
also calls DoLayout. 

An application unmanages a widget to remove the widget from visibility without destroying 
it, and at the same time to tell the composite widget to change the layout of the remaining 
widgets to fill the gap. This is done by calling XtUnmanageChild or xtUnmanage- 
Children. The application can then make the composite widget redisplay the widget by 
calling XtManageChild or xtManageChildren. This response depends on the Core 
xtNmappedwhenManaged resource having its default value, TRUE. When set to FALSE, 
the management state has no effect on mapping, and the application must call xtMap- 
Widget and xtUnmapWidget instead. Usually an application does this so that a widget 
will become invisible without triggering a re-layout to fill in the space it has vacated. There 
fore, change_managed need not check the XtNmapWhenManaged resource of each 
child. 




"Incidentally, the children and num_children fields are resources. However, they are for reading only from 
outside of the widget code; the application should never set them with XtSetValues. 



Geometry Management 319 



You have now seen all of the code of ScrollBox! To summarize, a very basic composite 
widget such as ScrollBox has a standard initialize method, resize and 
change_managed methods that just call DoLayout, and a set_values method that 
calls DoLayout when any resource that affects layout is changed. The DoLayout rou 
tine actually lays out the children. The widget s query_geometry method is basically 
just like a simple widget s query_geometry. Now we ll move on to describe what may 
be added to this skeleton to make more fully-featured composite widgets. 

11.2.4 XtQueryGeometry and the query_geometry Method 

We have mentioned that XtQueryGeometry just calls a child s query_geometry 
method, but not the details of how this works. The query_geometry method for simple 
widgets is described in Chapter 6, Basic Widget Methods. The role of this method in compo 
site widgets is the same, but the details of its job are different. You may recall that this 
method is passed pointers to two xtwidget Geometry structures, one which specifies the 
parent s proposed geometry, and the other which is used by the child to return a compromise 
geometry. These two structures are allocated by the method that calls XtQuery 
Geometry, and passed as pointers to that call. The XtGeometryResult enum 
returned by the query_geometry method is passed right through as the returned value of 
XtQueryGeometry. 

Composite and constraint widgets play the role of both parent and child. When you write a 
composite widget, you may call XtQueryGeometry in several places to get the child s 
response to your proposed size. You will also need to write a query_geometry method 
so that your widget can responds to its parent s XtQueryGeometry request. 

A query_geometry method in a composite widget should base its response on the size 
preferences of its children. It should calculate a new layout based on the proposed geometry 
passed in, and then query its children to get their opinions of their new geometry. If any of 
the children is a composite widget, they may query their children, and so on. Therefore, 
these requests tend to trickle down to the lowest widget in the hierarchy. ScrollBox took the 
biggest shortcuts in its query_geometry method. Not only didn t it query its children, 
but it hardcoded its response based on the characteristics of the kind of main window it 
expected. This would be the first place to begin improving ScrollBox. 

Note, however, that a composite widget is allowed to be authoritarian and not ask its children 
whether they like the sizes they are about to be given. However, this kind of composite 
widget will not be suitable as a parent of a widget that really needs certain size preferences. 

11.2.5 XtMakeGeometryRequest and the geometry_manager Method 

XtMakeGeometryRequest calls are made for two reasons. First, when a composite 
widget honors its children s size preferences, it may find that its current size is inadequate to 
lay out its children. In this case, it should ask its parent to be resized by calling XtMake 
GeometryRequest. Second, Xt calls XtMakeGeometryRequest for a widget when 
the application has changed a resource that affects geometry. 



320 X Toolkit Intrinsics Programming Manual 



As mentioned above, xtMakeGeometryRequest calls the parent s 
geometry_manager method. The parent s geometry_manager has the job of decid 
ing whether the size proposed by the child is acceptable. A subclass of Composite must 
either define a geometry_manager method, or set this field in the class structure to 
NULL, because there is no default method to inherit. The xtlnheritGeometry- 
Manager symbol can be used only in subclasses of a class that defines a 
geometry_manager method. 

Any composite widget that wants to allow its children to suggest resizing will require a 
geometry_manager method of its own. 

The way the arguments and returned values are passed between XtMakeGeometry 
Request and the parent s geometry_manager method is almost exactly parallel to the 
way XtQueryGeometry calls the child s query_geometry method. Both calls take 
pointers to two structures of the same types where one is used for a returned compromise. 
Both take no more arguments other than the widget ID. Both return an enum value of type 
XtGeometryResult. The returned value of the geometry_manager method is, gen 
erally speaking, passed through as the returned value of XtMakeGeometryRequest. 
Review Section 6.6 so that these structures, their fields and values, and the returned values 
are fresh in your mind. 

One difference between the way the query_geometry and geometry_manager 
methods are invoked is that the geometry_manager method can return a fourth enum 
value, XtGeometryDone (in addition to Xt Geometry Yes, XtGeometryNo, and Xt- 
GeometryAlmost). Table 11-1 summarizes the return codes of the 
geometry_manager method. 

Table 11-1. Return Codes of geometry_manager Method 




Code 



XtGeometryNo 
XtGeometryAlmost 
Xt Geometry Yes 



XtGeometryDone 



Description 



Requested change is denied 

A compromise is suggested 

Requested change is accepted, let xtMakeGeometryRe 

quest make change 

Requested change is accepted, I have made change 



XtGeometryDone means that geometry_manager approves of the change and has 
actually made the change. XtMakeGeometryRequest never returns XtGeometry 
Done though; it returns XtGeometryYes when the geometry_manager returns Xt- 
GeometryYes or XtGeometryDone. When the geometry_manager returns Xt 
GeometryYes, the XtMakeGeometryRequest call itself makes the size change. All 
these shenanigans simply allow the parent to make the size change by calling its normal lay 
out code or to let XtMakeGeometryRequest do it, depending on which is most conve 
nient 

The second difference is that XtMakeGeometryRequest and the 
geometry_manager method interpret the XtGeometryNo returned value differently. 
For XtMakeGeometryRequest and geometry_manager, it has its intuitive 



Geometry Management 



meaning that the requested change is denied. For query_geometry and xt Query- 
Geometry, the symbol should really be XtGeometryNoChange. Since this symbol 
doesn t exist, xtGeometryNo has to do double duty, meaning in this case that the pro 
posed size and current size are the same. 

The final difference is an additional mask for the request_mode field of the Xt- 
widget Geometry structure that contains the proposed change. In XtMakeGeometry- 
Request requests, the mask xtCWQueryOnly can be ORed with the masks that identify 
which fields in the proposed geometry the child considers important. This indicates that the 
proposed change should not be made, but that the geometry_manager method should fill 
in the return structure with the changes it would have made. This flag is used whenever a 
widget is making an XtMakeGeometryRequest from its geometry_manager 
method: these requests are intermediate (triggered by requests from children). The compos 
ite widget does not actually want to be resized until it has made a suggestion for its own size 
to its parent, received an answer from the parent, recalculated the layout of its children, and 
queried its children, if necessary, to see that the new size is adequate for everybody. 

This also makes it obvious that the geometry_manager method you write for your com 
posite widget must be prepared to handle the XtCWQueryOnly mask. It should calculate a 
layout but not actually move or resize any widgets. 

ScrollBox does not need a geomet ry_manager method because it knows that its children 
will never make geometry requests. However, any composite widget that accepts all kinds of 
children requires a geometry__manager method. In Section 11.4.6 below, the 
geometry_manager method of the Form widget is shown and described. 

Similar to XtMakeGeometryRequest, but less general, is XtMakeResizeRequest. 
Instead of passing two structures, XtMakeResizeRequest passes two width and height 
pairs. Otherwise, the results of this call are the same. 



11.2.6 The set_values_al most Method 

As mentioned above, a child widget may request a geometry change for one of three reasons: 

The application just called Xt Set Values and set a geometry field. In this case, Xt 
makes the geometry request to the parent to allow the parent to overrule or modify the 
change. 

The application just called xt Set Values and set a resource that affects geometry, like 
the string displayed in a Label widget The set_values method of the child changes 
the geometry fields in the widget directly. Then Xt makes a geometry request to the par 
ent, to allow the parent to overrule or modify the change. 

The child may decide it needs more or less room because of some kind of user input, or 
because its own children need more or less room. In this case, it calls XtMake 
GeometryRequest itself, and handles the various returned values itself. If the widget 
wants to use set_values_almost to make compromise suggestions (since it is 
designed for that purpose and may be there anyway), the widget will have to call the 
method itself. 



322 X Toolkit Intrinsics Programming Manual 



In the first two cases, Xt calls xtMakeGeometryRequest, while in the third case, the 
child must call the function itself. If the returned value is Xt Geometry Yes, the Xt 
MakeGeometryRequest call itself (or Xt) has resized the child. 

When XtMakeGeometryRequest is called by Xt, and its returned value is xt- 
GeometryAlmost or XtGeometryNo, Xt calls the set_values_almost method 
of the widget whose geometry is changing.* The job of set_values_almost is to pro 
pose a different geometry to the parent Once set_values_almost proposes a new 
geometry, Xt calls the parent s geometry_manager method again, and the cycle repeats 
until the geometry_manager returns XtGeometryYes or XtGeometryDone. Fig 
ure 11-6 illustrates this process. 

Most widgets inherit this method from the Core widget by specifying xtlnheritSet- 
Va lues Almost in the Core class part initialization. This inherited method always 
approves the suggestion made by the parent geometry_manager method. If your widget 
really depends on being certain sizes, however, you will need to write a set_val- 
ues_almost method. You should never specify a NULL set_values_almost 
method. If you do, Xt will print a warning message when set_values_almost would 
have been called, and continue as if it had been called and returned XtGeometryYes 
approving the change. 

The set_values_almost method is passed pointers to two Xtwidget Geometry 
structures: request and reply. The request structure contains the child s original 
request and reply includes the geometry_manager method s compromise geometry if 
geometry_manager returned XtGeometryAlmost. To accept the compromise, the 
procedure must copy the contents of the reply geometry into the request geometry; to attempt 
an alternate geometry, the procedure may modify any part of the request argument; to termi 
nate the geometry negotiation and retain the original geometry, the procedure must set 
request->request_mode to zero. 

If geometry_manager returned XtGeometryNo, it will not have generated a compro 
mise. In this case, the set_values_almost method may suggest a new geometry, but it 
is probably not worth it since the method has no information upon which to base its changes 
to its previous suggestion. The set_values_almost method at this point should usually 
just set request ->request_mode to zero to terminate the geometry negotiation. 

1.2.7 The insert_child and delete_child Methods 

The Composite class has an instance part structure that contains an array of all the widget s 
children (even those not currently managed), the current number of children, and the total 
number of child slots available. The insert_child method inserts the ID of a child into 
this array. It is called when the child is created by a call to xtCreatewidget or xt- 
CreateManagedWidget. Most widgets inherit the insert_child method from the 
Composite class by specifying the symbolic constant xt Inherit insertChild in the 



*Several facts described here differ from the R3 Xt specification document (the initial X consortium standard). No 
known implementation of Xt ever followed those specifications. This section describes the R3 and R4 implementa 
tion, which works as described in the R4 specification. 



Geometry Management 323 



J] Xt calls parent 

geometry_manager 

again. 




; 2_ Parent s geometry_manager 

analyses child suggestion and 
returns value and possibly a 
compromise. Must make sure 
this is not an infinite loop. 
XtGeometryYes means 

compromise accepted. 



If returned value is 

XtGeometryNo Or 
XtGeomet ryAlmost , 

Xt calls child s 

set_values_almost 

method. 



Child s set_values_almost 

method proposes a new 
geometry based on information 
passed in, or gives up. If new 
geometry back to [j] . 



Figure 1 1-6. Geometry negotiation by the set_values_almost method 

class structure initialization. A class would replace the default insert_child method to 
control the position of each child added, or to limit the number or classes of widgets that can 
be added. 

A composite widget can control the position of each child added by calling a function whose 
pointer is stored in the instance part field insert _pos it ion. The function should return 
the number of widgets before the widget The xtNinsertPosition resource sets this 
function pointer. The default insert_position function returns the current number of 
children. Of course, because this resource s value is a function pointer, it can be specified in 
the application only at run time, never through the resource files or command line. 

The delete_child method removes the ID of a child from the child array and is called 
when the application calls xtDestroyWidget. This method is almost always inherited 
from Composite by specifying the symbolic constant xtlnheritDeleteChild in the 
class structure initialization. 



324 



X Toolkit Intrinsics Programming Manual 



11 .3 How Constraint Management Works 

The first thing to realize about constraint widgets is that everything said about composite 
widgets is still true. Because Constraint is a subclass of Composite, all the methods 
described above are still present and have the same tasks. However, constraint widgets also 
maintain a structure full of data attached to each child, set through resources. Every time it 
lays out the children, the constraint widget reads this data to determine how to handle that 
child. Of course, it still may query each children to get its opinion of a new size. The con 
straint information adds another level of complexity to the situation. 

Like composite widgets, constraint widgets can be drastically simplified by reducing flexibil 
ity and features. The Athena Form widget, for example, never queries its children for their 
geometry input, and never asks its parent for a size change. Furthermore, its constraints for 
each child are quite limited. This makes Form quite short and simple, but also means that it 
doesn t always do the right thing. 



1 1 .4 Writing a Constraint Widget 

The following sections describe the portions of the Athena Form widget that relate to 
geometry management. This will give you a birds-eye view of constraints in action. 

11.4.1 The Core Resource List 

The Form widget has only one resource of its own, xtNdef aultDistance, as shown in 
Example 11-5. This resource is used only as the default for two of the Constraint resources, 
XtNhorizDistance and XtNvertDistance. XtNdef aultDistance is used to 
set the instance field def ault_spacing, which is used in only one place in the widget, in 
the Constraint initialize method described in Section 11.4.4. 

Example 1 1-5. Form: the Core resource list 

#define Offset (field) XtOf f set (FormWidget, form. field) 
static XtResource resources [] = { 

XtNdef aultDistance, 

XtCThickness, 

XtRInt, 

sizeof (int) , 

Offset (default_spacing) , 

XtRImmediate, 

(caddr_t) 4 

} 

}; 
tundef Offset 




Geometry Management 325 



11.4.2 The Constraint Resource List 

The Form widget has three groups of constraint resources. xtNhorizDistance, xt- 
Nf romHoriz, XtNvertDistance, and XtNfromVert together control the initial 
position of a child. XtNtop, XtNlef t, XtNbottom, and XtNright govern reposition 
ing of the child when Form is resized. The xtNresizable resource controls whether the 
geometry_manager of this widget will honor requests to change the geometry of this 
child. Note that XtNresizable does not control whether this constraint widget can resize 
a child only whether or not it will do so because of a request from the child.* 

For more details about how these constraint resources work, read about them on the reference 
page for the Form widget in Volume Five, X Toolkit Intrinsics Reference Manual. 

Constraint resources are also called simply constraints, particularly because they are stored 
in a Core instance field called constraints. Example 11-6 shows Form s constraint 
resource list. 

Example 11 -6. Form: constraint resource list 
static XtEdgeType defEdge = XtRubber; 

#define Of f set (field) XtOf f set (FormConstraints, form. field) 
static XtResource f ormConstraintResources [ ] = { 

II < 

XtNhorizDistance, 

11 XtCThickness, 

XtRInt, 

sizeof (int ) , 

Offset (dx) , 
I| XtRImmediate, 

(caddr_t) DEFAULTVALUE 

II ) , 

II {XtNf romHoriz, XtCWidget, XtRWidget, sizeof (Widget) , 

Offset (horizjbase) , XtRWidget, (caddr_t) NULL} , 
{XtNvertDistance, XtCThickness, XtRInt, sizeof (int), 

Offset (dy), XtRImmediate, (caddr_t) DEFAULTVALUE }, 
{XtNfromVert, XtCWidget, XtRWidget, sizeof (Widget ), 
Offset (vertjbase) , XtRWidget, (caddr_t ) NULL} , 

{XtNtop, XtCEdge, XtREdgeType, sizeof (XtEdgeType) , 

Off set (top), XtREdgeType, (caddr_t) SdefEdge } , 
{XtNbottom, XtCEdge, XtREdgeType, sizeof (XtEdgeType) , 

Of f set (bottom) , XtREdgeType, (caddr_t) SdefEdge } , 
{XtNleft, XtCEdge, XtREdgeType, sizeof (XtEdgeType) , 

Offset (left) , XtREdgeType, (caddr_t ) SdefEdge } , 
{XtNright, XtCEdge, XtREdgeType, sizeof (XtEdgeType) , 

Offset (right) , XtREdgeType, (caddr_t ) sdefEdge } , 

{XtNresizable, XtCBoolean, XtRBoolean, sizeof (Boolean) , 

Of fset (allow_resize) , XtRImmediate, (caddr_t)0}, 
}; 
tundef Offset 



*The fact that Form does not provide individual control over the resizability of each child is a major weakness. 



326 X Toolkit Intrinsics Programming Manual 



The corresponding data structure that this resource list references, FormConstraints, is 
defined in the private include file for the widget Its definition is shown in Example 1 1-7. 

Example 11 -7. Form: constraint data structure 

typedef struct _FormConstraintsPart { 

II /* 

* Constraint Resources. 

III */ 

XtEdgeType top, bottom, /* where to drag edge on resize */ 

left, right; 

int dx; /* desired horiz offset */ 

int dy; /* desired vertical offset */ 

Widget horiz_base; /* measure dx from here if non-null */ 

Widget vert_base; /* measure dy from here if non-null */ 

Boolean allow_resize; /* TRUE if child may request resize */ 

/* 

* Private constraint variables. 

* These store the dimensions of the child prior to layout. 
Ill */ 

int virtual_width, virtual_height; 

III /* 

* Size of this child as it would be if we did not impose the 

* constraint that its width and height must be greater than zero (0) 
*/ 

LayoutState layout_state; /* temporary layout state */ 
} FormConstraintsPart; 

typedef struct _FormConstraintsRec { 

FormConstraintsPart form; 
} FormConstraintsRec, *FormConstraints; 

The constraints part structure should be considered an instance part structure. This structure 
has public fields set through resources and private fields that hold state data, just like an 
instance part structure. Note also that the FormConstraints structure is built the same 
way as instance structures, by combining part structures for each class into a complete con 
straint structure. This allows subclasses of Form to create their own constraint part structure 
and add it after the Form constraint part. 

When a widget is created as a child of a constraint widget, the constraint instance structure 
(FormConstraintsRec, in this case) is placed in the constraints field of the Core 
instance structure. Xt makes the constraint resources stored there sellable, like resources 
defined by the child even though they are actually defined and used by the parent. 

11.4.3 Class Structure Initialization 

The Form class is a subclass of Constraint. Therefore, its class structure contains class parts 
for Core, Composite, Constraint, and Form. Example 11-8 shows the class structure initiali 
zation of Form. Several methods referenced here have not been discussed so far in this book. 
They are the Core methods class_initialize and class_jpart_init, and the 



Geometry Management 327 




Constraint methods initialize and set_values. These and all the geometry man 
agement-related methods of Form will be discussed in Section 11.4.6. 

Example 11 -8. Form: class structure initialization 
FormClassRec formClassRec = { 



{ /* Core class fields 
/* superclass 
/* class_name 
/* widget_size 
/* class_initialize 
/* class_part_init 
/* class_inited 
/* initialize 
/* initialize_hook 
/* realize 
/* actions 
/* num_actions 
/* resources 
/* num_resources 
/* xrm_class 
/* compress motion 



*/ 
*/ 
*/ 
*/ 

*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 



/* compress_exposure */ 
/* compress_enterleave*/ 
/* visible interest 



destroy 

resize 

expose 



/* set_values 

/* set_values_hook 

/* set values almost 



*/ 

*/ 
*/ 
*/ 

*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
*/ 
/* display_accelerator*/ 



get_values_hook 
accept_focus 
version 

callback_private 
tm table 



/* query_geometry 



/* extension 



/ 



(Widget Class) sconstraintClassRec, 

"Form", 

sizeof (FormRec) , 

Class Initialize, 

ClassP art Initialize, 

FALSE, 

Initialize, 

NULL, 

Xt Inner itRealize, 

NULL, 

0, 

resources, 

XtNumber (resources) , 

NULLQUARK, 

TRUE, 

TRUE, 

TRUE, 

FALSE, 

NULL, 

Resize, 

Xt Inner itExpose, 

SetValues, 

NULL, 

Xt Inner it SetValuesAlmost, 

NULL, 

NULL, 

XtVersion, 

NULL, 

NULL, 

Pref erredGeometry, 

XtlnheritDisplayAccelerator, 

NULL 



{ /* Composite class fields 



/* geometry_manager 

/* change_managed 

/* insert_child 

/* delete_child 

/* extension 



*/ 

*/ 
*/ 
*/ 
*/ 



GeometryManager, 

ChangeManaged, 

XtlnheritlnsertChild, 

XtlnheritDeleteChild, 

NULL 



{ /* Constraint class fields */ 



/* subresourses 

/* subresource_count 

/* constraint_size 

/* initialize 



destroy 

set_values 

extension 



*/ formConstraintResources, 

*/ XtNumber (formConstraintResources) , 

*/ sizeof (FormConstraintsRec) , 

*/ Constraintlnitialize, 

*/ NULL, 

*/ ConstraintSetValues, 

*/ NULL 



{ /* Form class fields */ 



328 



X Toolkit Intrinsics Programming Manual 



Example 11 -8. Form: class structure initialization (continued) 
/* layout */ Layout 

WidgetClass formWidgetClass = (WidgetClass) sformClassRec; 

Note that the Form class is the first widget we have shown that defines a class part field a 
method of its own, called layout. Since this method is not known to Xt, Xt will never call 
it The widget must invoke this method itself at the appropriate times (you will see this invo 
cation in the methods below). This code is made into a method instead of just a private func 
tion only to make it possible for subclasses of this widget to inherit or replace the method. 
Having such a method requires that the widget have a class_part_init method to 
handle the inheritance if a subclass specifies the layout method with the symbolic constant 
Xt Inherit Layout (also defined in this class s private header file). 

Section 11.2.1 described which Core and Composite methods are required for composite 
widgets, and how to initialize the other Core and Composite fields for a composite widget. 
The same is true for constraint widgets. 

However, the Constraint part is probably new to you. The ConstraintClassPart 
structure contains seven fields. The first three fields are where the constraint resource list, the 
number of resources, and the size of the constraint instance structure are entered. This 
resource list and instance structure were described in the last section. These fields are analo 
gous to the resources, num_resources, and widget_size fields in the Core class 
part. 

The three next fields, initialize, destroy, and set_values are methods defined 
by the Constraint class. These methods have the same field names as methods of Core, but 
are fields of a different structure, and contain pointers to different functions that you may 
need to write. To differentiate Constraint methods from the Core methods, we will precede 
the names of Constraint fields with the word "Constraint" and the names of Core fields with 
the word "Core" throughout this chapter. 

Two of the three Constraint methods will be described where they fit in below. We ll 
describe one of them, Constraint destroy, now, because it is not used in Form and is less 
likely to be needed in the constraint widgets you may write. The Constraint destroy 
method is called when a child is destroyed, just before the Core destroy method of the 
child. It is responsible for freeing any memory allocated by the constraint widget that was 
used to manage that child. However, like the Core destroy method, it does not need to 
free memory allocated by Xt, such as the constraint data structure for the child. 



The Constraint initialize Method 

The Constraint initialize method is called when a widget is created, soon after the Core 
initialize method. It has the same two responsibilities as the Core initialize method, 
and one additional responsibility. It must: 

Validate the ranges of resource settings, since they may be user-supplied. 



Geometry Management 329 




Compute the value of any private constraint instance part fields that depend on constraint 
resource values (public constraint instance part fields). 

Set child Core geometry fields to match the constraint resources. For example, if a con 
straint for the maximum height of a widget is set and the initial value set by the child is 
larger, the Constraint initialize method resets the height field in the Core instance 
structure. 

However, like the Core initialize method, the Constraint initialize method is 
responsible only for constraint resources and for Core geometry resources. It need not handle 
any resources of superclasses (other than the Core geometry resources). 

The Form widget performs only one of the tasks listed above, initializing constraint 
resources. In Form s case, the Constraint initialize method (shown in Example 11-9) 
simply sets the initial values of the XtNvertDistance and XtNhorizDistance con 
straint resources to the current value of the xtNdef aultDistance Form resource, unless 
the user has specified a value for either constraint resource. This is done only so that the 
application can set the Form resource once and have it apply to every child that does not 
override the value. 

Form doesn t validate the values of any user-supplied resource values, as it should. For 
example, the user may supply a negative value for the XtNhorizDistance or Xt 
NvertDistance resources. This would certainly make the layout look bad, but it could 
also cause the Form widget to go into an infinite loop on geometry negotiations. In general, 
all initialize methods in Core and Constraint should check for ranges of reasonable 
values of resources where this makes sense (doing this in set_values is also a good idea 
to give the programmer good warning messages). This eliminates a source of potential bugs. 

Example 11 -9. Form: the Constraint initialize method 

/* ARGSUSED */ 

static void Constraintlnitialize (request, new) 

Widget request, new; 
{ 

FormConstraints form = (FormConstraints) new->core .constraints; 

FormWidget fw = (FormWidget) new->core .parent; 

if (form->form.dx DEFAULTVALUE) 

form->form.dx = fw->form.default_spacing; 

if (form->form.dy == I>EFAULTVALUE ) 

form->form.dy = fw->form.default_spacing; 

} 

Note that the Constraint instance part structure (FormConstraints) and the Form widget 
instance structure (FormWidget) are accessed by casting two different fields of the child s 
instance structure passed in. 

The Constraint initialize method and the child s Core initialize are passed the 
same two copies of the child s instance structure: request, and new. The request 
widget is the widget as originally requested. The new widget starts with the values in the 
request, but it has already been updated by calling all superclass initialize methods. 



330 X Toolkit Intrinsics Programming Manual 



The class_part_init Method 

The class_part_init method should be present in a class that defines new methods in 
its class part structure. These new methods will never be called by Xt since Xt has no knowl 
edge of when to call them. They can only be invoked directly from the widget code. The 
purpose of making them methods instead of just functions is to allow subclasses to inherit or 
replace the functions. The class_jpart_init method actually resolves this inheritance 
by setting each method field to the pointer provided by this class (the subclass is inheriting 
the method) or to the pointer provided by the subclass (the subclass is replacing the method). 
Example 11-10 shows a class_part_init method for a class that defines only one new 
method in its class part structure. This method is the Form widget s layout code. 

Example 11-10. The class_part_init method of Form. 

static void ClassPartlnitialize (class) 

WidgetClass class; 
{ 

register FormWidgetClass c = (FormWidgetClass) class; 

if (c->form_class. layout == XtlnheritLayout) 

c->form_class. layout = Layout; 
} 

The XtlnheritLayout symbol is defined in the private include file for any class that 
defines new class part methods (one for each new method). Its value is always _xt- 
Inherit. 

Form itself sets the layout field to a pointer to its Layout function. When its 
class_part_init method is called when the first instance of Form is created, it does 
nothing because the layout field is not XtlnheritLayout. When a subclass is defined 
that sets the layout field to a function, the same thing happens: Form s 
class_part_init method is called because it is chained downward (the 
class_part_init methods of all superclasses are called), and it still does nothing 
because the layout field is not XtlnheritLayout. Thus, the subclass has replaced 
Form s method. But if the subclass sets the layout field to XtlnheritLayout, Form s 
class_part_init method sets the field to its own Layout function. The subclass has 
inherited Form s method. 

Usually, only the class that defines a particular new method resolves the inheritance by 
checking for the value of that field in its class_part_init method. However, if a sub 
class also checks for the value if for example a subclass of Form checked for Xtlnherit 
Layout the downward chaining means that the subclass class_part_init method 
would take precedence. 



Geometry Management 331 



11.4.6 The geometry_manager Method 

geometry_manager methods handle requests from the children to be resized. Therefore, 
they typically use the proposed geometry passed in from the child to calculate a new experi 
mental layout, and actually move and resize the children if the new layout is acceptable. 
However, when the request is just a query, the method should be able to return the same 
values without actually moving or resizing anything. 

The Form geometry_manager method is shown in Example 11-11. Form uses the 
allow_resize field (the XtNresizable resource) to determine whether to even con 
sider the resize request Then, if the request specifies a width and height, Form will accept 
the change by returning xtGeometryYes. The XtMakeGeometryRequest call that 
invoked the geometry_manager will actually make the geometry change before return 
ing to the child s code. If the request specifies any other geometry change (border width, 
position, or stacking order), Form will deny the request Finally, if the request was not a 
query, Form actually does the new layout. Note that Form returns xtGeomet ryDone if it 
has made the geometry changes, and returns XtGeometryYes when it agrees with the 
changes but has not made them (due to a query). 

Note that the allowed structure in this routine could be replaced by individual width and 
height variables. Also note that the reply structure is never filled. This is used only 
when the geometry_manager method wants to suggest a compromise. 

II Example 11-11. Form: the geometry_manager method 

/* ARGSUSED */ 

static XtGeometryResult GeometryManager (w, request, reply) 

Widget w; 

XtWidgetGeometry *request; 

XtWidgetGeometry *reply; /* RETURN */ 
{ 

FormConstraints form = (FormConstraints) w->core. constraints; 

XtWidgetGeometry allowed; 

if ( (request->request_mode & ~ (XtCWQueryOnly | 
CWWidth | CWHeight)) || 
! form->form. allow_resize) 
return XtGeometryNo; 

if (request->request_mode & CWWidth) 

allowed. width = request->width; 
else 

allowed. width = w->core .width; 

if (request->request_mode & CWHeight) 

allowed. height = request->height; 
else 

allowed. height = w->core .height; 

if (allowed. width == w->core .width && allowed. height == 

w->core . height ) 
return XtGeometryNo; 

if ( ! (request->request_mode & XtCWQueryOnly)) { 
/* reset virtual width and height. */ 
form->form. virtual width = w->core .width = allowed .width; 



332 X Toolkit Intrinsics Programming Manual 



Example 11 -11. Form: the geometry_manager method (continued) 

form->form. virtual_height = w->core .height = allowed. height; 
Ref igureLocations ( (FormWidget ) w->core .parent ); 
} 

return XtGeometryYes; 
} 

The Ref igureLocations called from the geometry_manager method is a private 
function analogous to the DoLayout routine used in ScrollBox, except that Ref igure 
Locations calls Form s layout method that contains the actual layout code so that the 
method can be inherited or replaced by subclasses. The layout method calculates a layout 
and moves and resizes the children. Ref igureLocations is also called from the 
change_managed method, as described in Section 11.4.9. Example 11-12 shows the 
Ref igureLocations function and Form s layout method, which it calls. (The if 
statement that branches depending on the value of the no_re figure field allows an appli 
cation to turn relayout on and off, as described in Section 1 1.4.1 1.) 

Example 11-12. Form: private functions: RefigureLocations and the layout method 

static void Ref igureLocations (w) 

FormWidget w; 
{ 

/* no_refigure supports the relayout recalculation 

delay described later in this chapter */ 
if (w->f orm. no_ref igure) { 

w->form.needs_relayout = TRUE; 
} 
else { 

(* ( (FormWidgetClass) w->core . widget_class) ->f orm_class . layout) 

( w, w->core .width, w->core .height ); 
w->form. needs_relayout = FALSE; 



/* ARGSUSED */ 

static Boolean Layout (fw, width, height) 

FormWidget fw; 

Dimension width, height; 
{ 

int num_children = fw->composite .num_children; 

WidgetList children = fw->composite .children; 

Widget *childP; 

Position maxx, maxy; 

static void LayoutChild ( ) ; 

Boolean ret_val; 

for (childP = children; childP - children < num_children; 
childP + -f) { 

FormConstraints form = (FormConstraints) 

(*childP) ->core. constraints; 

form->form.layout_state = LayoutPending; 
} 

maxx = maxy = 1; 
/* 

* Layout children one at a time, and determine 

* necessary size for self 



Geometry Management 



Example 11-12. Form: private functions: RefigureLocations and the layout method (con 
tinued) 

*/ 

for (childP = children; child? - children 

< num_children; childP++) { 
/* 

* Layout child then find position of bottom right 

* outside corner of child 
*/ 

if (XtIsManaged(*childP) ) { 
Position x, y; 
LayoutChild (*childP) ; 
x = (*childP)->core.x + (*childP) ->core .width 

+ ( (*childP)->core.border_width 1); 
y = (*childP)->core.y + (*childP) ->core .height 

+ ( (*childP) ->core.border_width 1); 
if (maxx < x) maxx = x; 
if (maxy < y) maxy = y; 



fw->form.preferred_width = (maxx += fw->f orm. default_spacing) ; 
fw->form.pref erred_height = (maxy += fw->form. default_spacing) ; 

/ Now ask parent to resize us. If it says Almost, accept the 
compromise. If Almost and parent chose smaller size, or No 
and we were smaller than necessary, children will be clipped, 
not laid out again. 
/ 
if (fw->form.resize_in_layout 

&& (maxx != fw->core .width II maxy != fw->core .height) ) { 
XtGeometryResult result; 
result = XtMakeResizeRequest ( fw, (Dimension) maxx, 

(Dimension) maxy, (Dimension*) Smaxx, (Dimension*) Smaxy ) 
if (result == XtGeometryAlmost) 

result = XtMakeResizeRequest ( fw, (Dimension) maxx, 

(Dimension) maxy, NULL, NULL ); 
fw->form.old_width = fw->core .width; 
fw->form.old_height = fw->core .height ; 
ret_val = (result == XtGeometryYes) ; 
} else ret_val = FALSE; 

return ret_val; 
} 

The layout method treats one child at a time, as usual. It first initializes the 
layout_state private constraint instance field of each child to LayoutPending; the 
LayoutChild routine will start from this value. Next, it calls LayoutChild for each 
child, and at the same time keeps a running total of the sizes of the children so that when the 
loop is finished it knows how big to be to fit all the children. Finally, it requests of its parent 
that it be just big enough to fit its children. If the parent denies the request, the code makes 
no attempt to make another request. If the parent offers a compromise, it is accepted. In 
either case, the Form widget may be too big or too small to fit its children. If it is too small, 
some of its children will be clipped. 



334 X Toolkit Intrinsics Programming Manual 



The LayoutChild routine is shown in Example 1 1-13. What it does is simple, although it 
is a little hard to follow because it is called recursively. It moves the child according to the 
XtNf romHoriz and XtNf romVert constraint resources.* These resources specify that 
a child be placed to the right of or below another, particular child. 

Example 11-13. Form: the LayoutChild private function 

static void LayoutChild (w) 
Widget w; 

FormConstraints form = (FormConstraints) w->core .constraints; 
Position x, y; 
Widget ref; 

switch (f orm->form. layout_state) { 

case LayoutPending: 

form->form.layout_state = LayoutlnProgress; 
break; 

case LayoutDone : 
return; 

case LayoutlnProgress: 

String subs [2] ; 

Cardinal num_subs = 2; 

subs[0] = w->core .name; 

subs[l] = w->core .parent->core .name; 

XtAppWarningMsg(XtWidgetToApplicationContext (w) , 

"constraintLoop", "xawFormLayout", "XawToolkitError", 
"constraint loop detected while laying out child %s f in \ 

FormWidget %s ", 

subs, &num_subs) ; 

return; 

x = form->f orm.dx; 
y = f orm->form.dy; 
if ((ref = form->form.horiz_base) != (Widget) NULL) { 

LayoutChild (ref) ; 

x += ref->core.x + ref->core .width + (ref->core .border_width 
1); 

if ((ref = form->form.vert_base) != (Widget)NULL) { 
LayoutChild (ref ) ; 

y += ref->core.y + ref->core .height + (ref->core.border_width 
1); 

XtMoveWidget ( w, x, y ) ; 

form->form. layout_state = LayoutDone; 

If neither XtNf romHoriz nor XtNf romVert are set for the child, it is simply placed the 
default distance from the top-left corner of the Form. When one child is set, the next child 

*Form resizes children only when it is resized never during normal layout 



Geometry Management 335 



must be placed relative to that child. However, the other child may be later in the list and not 
properly positioned yet. Therefore, the code calls LayoutChild to lay out the child that 
this child is positioned relative to. 

The layout_state field catches circular settings for the XtNf romHoriz and Xt- 
Nf romvert resources. For example, if widget A is specified to the right of widget B, and 
widget B is specified to the right of widget A, there is no solution. LayoutChild would be 
caught in an infinite loop of calling itself. When first called from the layout method, the 
layout_state is LayoutPending. This is changed to Layout InProgress in the 
switch statement. If the function is called again for the same child, this state will cause the 
warning message to be printed and the function to exit The Form widget does not exit it 
just gives up processing the invalid constraint resource setting and prints a warning message. 



11.4.7 The resize Method 

The resize method calculates a layout to fit in the new dimensions of Form and moves and 
resizes the children accordingly. Form s resize method is shown in Example 11-14. It 
consists of a loop that treats each managed child one at a time. The position and dimensions 
of each child are calculated with the help of the private function Transf ormCoord (also 
shown in Example 11-14) and the child is moved and resized. Transf ormCoord handles 
one parameter at a time, and uses a position, the size before resizing, the size after resizing, 
and the constraints settings to arrive at the appropriate value for the parameter. The old 
width and height of the Form widget are initialized in the Core initialize method and 
updated at the end of the resize method. 

II Example 11 -14. Form: the resize method 

static void Resize (w) 

Widget w; 
{ 

FormWidget fw = (FormWidget ) w; 

WidgetList children = fw->composite . children; 

int num_children = f w->composite .num_children; 

Widget *childP; 

Position x, y; 

Dimension width, height; 

for (childP = children; child? - children < num_children; 

childP++) { 
FormConstraints form = (FormConstraints) 

(*childP) ->core .constraints; 
if ( !XtIsManaged(*childP) ) continue; 
x = Transf ormCoord ( ( *childP) ->core .x, fw->form.old_width, 

fw->core .width, form->form. left ); 

y - Transf ormCoord ( ( *childP) ->core .y, fw->form.old_height, 
fw->core. height, form->f orm. top ); 

form->form.virtual_width = 

Transf ormCoord ( (Position) ( (*childP) ->core.x 

+ form->form. virtual_width 

+ 2 * (*childP) ->core.border_width) , 

f w->f orm . old_width, f w->core . width, 

form->f orm. right ) 



336 X Toolkit Intrinsics Programming Manual 



Example 11 -14. Form: the resize method (continued) 

- (x + 2 * (*childP)->core.border_width) ; 

form->form. virtual_height = 

TransformCoord ( (Position) ( (*childP) ->core .y 

+ form->form. virtual_height 

+ 2 * (*childP)->core.border_width) , 

f w->f orm . old_height , f w->core . height , 

form->form. bottom ) 

( y + 2 * (*childP)->core.border_width) ; 

width = (Dimension) 

(form->form. virtual_width < 1) ? 1 : 

form->form.virtual_width; 
height = (Dimension) 

(form->form.virtual_height <!)?!: 
f orm->f orm . virtual_height ; 

XtMoveWidget ( (*childP), x, y ); 
XtResizeWidget ( (*childP), width, height, 

(*childP) ->core .border_width ); 
} 

fw->form. old_width = fw->core .width; 
fw->form.old_height = fw->core .height ; 

} 

static Position TransformCoord (loc, old, new, type) 
register Position loc; 
Dimension old, new; 
XtEdgeType type; 
{ 

if (type == XtRubber) { 
if ( ( (int) old) > 0) 

loc = (loc * new) / old; 
} 

else if (type == XtChainBottom I I type == XtChainRight) 
loc += (Position) new - (Position) old; 

/* 

* I don t see any problem with returning values 

* less than zero. 
*/ 

return (loc) ; 
} 

This resize method stores the new size of the children in the virtual_width and 
virtual_height constraint part fields, and uses their previous values to arrive at the 
new size. This is done because Form s XtNtop, XtNbottom, xtNlef t, and xtNright 
constraints specify the geometry of the child based on its previous geometry. 

Notice that the for loop in this particular resize method loops through the children 
directly, using pointer arithmetic. This is equivalent to using a loop that increments an inte 
ger and then uses the integer to index the children array. For example, the first five lines 
of the loop could also be expressed as: 




Geometry Management 337 



int i; 

for (i = 0; i < num_children; 

FormConstraints form = (FormConstraints) 
(children [i] ) ->core. constraints; 
if ( IXtlsManaged (*childP) ) continue; 
x = Transf ormCoord ( (children [i] ) ->core . x, 

fw->form.old width, fw->core .width, form->form. left ); 



11.4.8 The Core and Constraint set_values Methods 

When the application calls xt Set Values to set the resources of a child of a constraint 
widget, Xt calls the child s Core set_values method and then the parent s Constraint 
set_values method. Both methods are passed the same arguments. Constraint 
set_values validates the ranges of constraint resource settings and computes the value of 
any private constraint instance part fields that depend on constraint resource values. It 
should also set child Core geometry fields to match the changes in constraint resources. For 
example, if a constraint for the maximum height of a widget is changed to a value smaller 
than the widget s current height, then the Constraint set_values procedure should reset 
the height field in the widget 

Both Core and Constraint set_values must return TRUE or FALSE to indicate whether 
redisplay of the widget is necessary. For composite and constraint widgets, this value is 
usually meaningless because there is nothing to redisplay. But these might be useful if, for 
some reason, you write a composite widget that does have display semantics. 

Form defines both the Core and Constraint set_values methods as empty functions that 
return FALSE. An easier way to do this is to specify NULL for them in the class structure ini 
tialization. 



11.4.9 The change_managed Method 

The change_managed method is responsible for making the initial layout of an applica 
tion and changing the layout when any child changes management state. Form s 
change_managed method (shown in Example 11-15) calls Ref igureLocations to 
actually do a layout (RefigureLocations is a private routine equivalent to Do- 
Layout in ScrollBox, which was described in Section 11.4.6.) Form s 
change_managed method also stores the previous size of the children in the 
virtual_width and virtual_height constraint part fields, for use in the resize 
method as described in Section 11.4.7. 

Example 11 -15. Form: the change_managed method 

static void ChangeManaged (w) 

Widget w; 
{ 

FormWidget fw = (FormWidget ) w; 

FormConstraints form; 

WidgetList children, childP; 



338 X Toolkit Intrinsics Programming Manual 



Example 11-15. Form: the change_managed method (continued) 

int num_children = fw->composite .num_children; 
Widget child; 

/* 

* Reset virtual width and height for all children. 
*/ 

for (children = childP = fw->composite. children; 

childP - children < num_children; childP++) { 
child = *childP; 
if (XtlsManaged (child) ) { 

form = (FormConstraints) child->core. constraints; 

if ( child->core. width != 1) 

form->form. virtual_width = (int) child->core .width; 
if ( child->core. height != 1) 

form->form. virtual_height = (int) child->core .height ; 

Ref igureLocations ( (FormWidget ) w ); 

} 



11.4.10 The query_geometry Method 

Form s query_geometry method (shown in Example 11-16) is the minimal version 
almost identical to the one described for simple widgets in Chapter 6, Basic Widget Methods. 
The preferred_width and preferred_height instance variables are set in the 
Form class Layout method to the size that just fits the current layout. 

Example 11 -16. Form: the query_geometry method 

static XtGeometryResult Pref erredGeometry ( widget, request, reply ) 

Widget widget; 

XtWidgetGeometry *request, *reply; 
{ 

FormWidget w = (FormWidget) widget ; 

reply->width = w->form.pref erred_width; 
reply->height = w->form.preferred_height; 
reply->request_mode = CWWidth I CWHeight; 
if ( request->request_mode & (CWWidth I CWHeight) == 
reply->request_mode & CWWidth | CWHeight 
&& request->width == reply->width 
&& request->height -= reply->height) 
return XtGeometryYes; 
else if (reply->width == w->core .width && reply->height == 

w->core .height) 
return XtGeometryNo; 
else 

return XtGeometryAlmost ; 



Geometry Management 339 



1 1 .4.1 1 Delaying Geometry Recalculation 

During an application s initial layout, the change_managed method of a composite 
widget is called only once even though many children may have been managed. However, 
after that, change_managed is called once for every child that changes management 
state. Many composite or constraint widgets, especially ones that have complicated layout 
code, provide a public function (such as the one shown in Example 11-17) that the applica 
tion can call to turn off layout recalculation until a group of windows is managed or 
unmanaged, and then call again to trigger recalculation once the whole group of children has 
been managed or unmanaged. 

To implement this delay, you need an instance variable to hold a Boolean value indicating 
whether to delay or not (no_ref igure, in this case). You set and unset this variable in 
this public routine and you test it in change_managed.* 

Example 11-17. Form: the public function for delay ing calls to change_managed 

void XawFormDoLayout (w, doit) 

Widget w; 

Boolean doit; /* FALSE, don t recalculate; TRUE, do */ 

{ 

register FormWidget fw = (FormWidget) w; 

fw->form.no_ref igure = Idoit; 

if ( XtlsRealized (w) && fw->form.needs_re layout ) 
Ref igureLocations ( fw ); 



11.5 Compound Widgets 

A compound widget is a combination of widgets that are put together to make a higher-level, 
user-interface object. For example, Xaw makes the Dialog widget by combining the Label 
and Text or Command widgets in a widget that is actually a trivial subclass of the Form 
widget Dialog creates the Label, Text, and Form widgets in its initialize method, and 
sets constraint resources to position them. Dialog provides its own resource list to allow an 
application to configure some characteristics of its children. The application can manipulate 
the children only through these resources, because it cannot access the widget IDs of the 
subwidgets of Dialog without breaking the rules of data hiding. Thus, compound widgets 
provide programming convenience, but they make it more difficult to take advantage of all 
the configurable aspects of the subwidgets. 

The main widget of the compound widget may be a subclass of Core, Composite, or Con 
straint If it is a subclass of Core, the widget manages the positions and sizes of its children 
manually whenever it is resized. The success of this strategy is dependent on the children 
never trying to resize themselves, and on the application never trying to resize the children 



*XawFormDoLayout is called XtFormDoLayout in Release 3. 



340 X Toolkit Intrinsics Programming Manual 



directly.* The latter will not be a problem unless the application breaks the data-hiding rules 
by manipulating the child directly. The Text widget is an example of this kind of widget It 
creates and manages its own scrollbar. 

Compound widgets normally define only a few methods and inherit the rest. Compound 
widgets based on Core will move and resize their children manually in their resize 
method. If the widget is a subclass of Composite or Constraint, the normal geometry man 
agement facilities manage the position and size of the children. If it is a subclass of Con 
straint, the main widget sets the constraints of the children to control the geometry manage 
ment process by providing a Constraint initialize method. 

A compound widget always needs a destroy method that destroys the children it created. 
Compound widgets also need a set_yalues method to manage their resources. 



11.6 Stacking Order 

We promised earlier to say a bit more about how composite or constraint widgets can control 
the stacking order of their children. We noted that this must be done manually, because Xt 
doesn t provide much support for it 

There is no Core resource for stacking order, and therefore it can t be set with xtSet- 
Values unless you define the resources in your own widget class. Xt provides no call to 
restack windows; you must use the Xlib functions XConf igurewindow, XRestack- 
Windows, XRaiseWindow, or XLowerWindow. When a widget suggests a stacking 
order for itself through its query_geometry method, Xt takes care of making the 
required Xlib call if the parent agrees with the change. However, stacking requests of unreal 
ized widgets have no effect (so stacking order won t be set this way in the initial geometry 
negotiation). Therefore, the most robust method to handle stacking order is for your compos 
ite widget to make the appropriate Xlib calls directly to change the stacking order of its chil 
dren. XRestackwindows is probably the best call to use. Since restacking the windows 
doesn t change their requirements for screen space, it shouldn t effect either the parent or the 
children adversely. The appropriate place to call XRestackwindows depends on when 
you want to change the stacking order. (Note that the stacking change won t become visible 
until the next time Xt is waiting for an event.) 




*When a child of a simple widget calls XtMakeGeometryRequest because it wants to change its size, Xt- 
MakeGeometryRequest always makes the requested changes and returns XtGeometryYes. Therefore, a 
simple widget parent really has no control over its child if the child wants to resize itself. A simple widget cannot 
even tell that the child has resized itself. 



Geometry Management 341 



12 



Menus, Gadgets, 
and Cascaded Pop Ups 



This chapter describes how menus work, and several ways to create menu 
widgets. One of these ways involves the use of windowless widgets, or gad 
gets. This chapter also describes how to use more advanced features of the 
Xt pop-up mechanism, including modal cascades, to implement cascading 
pop-up menus. 

In This Chapter: 

Menu Styles and Implementation 347 

How Menus are Popped Up 348 

Menu Panes 349 

Several Ways to Create and Use Menus 351 

A Spring-Loaded Menu: Pointer Grabbing 351 

A Drop-Down Menu 359 

Cascaded Menus 362 

Using the R4 SimpleMenu Widget 367 

About Dialog Boxes 371 

Gadgets 372 

Inside a Gadget 375 

Private Header File 376 

The Gadget Source File 377 

The Public Header File 378 

The Gadget Parent 378 



12 

Menus, Gadgets, 
and Cascaded Pop Ups 



In Chapter 2, we show a simple example that pops up a dialog box. This chapter is much 
more thorough in describing the Xt facilities for managing pop ups, and focuses on pop-up 
menus. 

Although the menus provided by various widget sets vary greatly in the way they look and in 
the way they are used in the application, the underlying Xt facilities for managing them are 
the same. This chapter presents a series of examples based on R3 and R4 Athena widgets 
that implement menus in different ways. While some of the techniques shown may be hidden 
within the menu widgets provided in commercial widget sets, it will help you understand 
menus better to see the underlying techniques fully exposed and explored. 

This chapter also discusses cascaded pop ups pop ups that call other pop ups and the 
event management necessary to have pop ups that shut out other input elsewhere in the appli 
cation and system. 

Finally, this chapter discusses windowless widgets called gadgets, which have been designed 
to reduce window system overhead. Their most important use is to implement the panes in 
menu widgets. Gadgets were originally developed by Digital as a part of DECWindows, and 
have been carried over into the version of Xt shipped with Motif. They are supported by the 
MIT Intrinsics beginning in Release 4 (R4). As an example of a widget that manages gad 
gets, we will show the R4 SimpleMenu widget and its gadget children. 

In this chapter, we are using the term menu broadly, to refer to any user-interface element 
that lists many options and allows the user to select one or more. A menu might consist of a 
list of commands, only one of which can be selected at a time, a list of nonexclusive Boolean 
settings that can be turned on or off, or a list of exclusive choices (such as the colors or pat 
terns for a paint palette). A menu that invokes commands will start in the same state each 
time, while the other two types may have different contents in any particular invocation, 
showing the settings invoked the previous time or all previous times, or a modified list of 
choices. 

Menus are one of the most important user-interface elements in window-based applications. 
They offer the same feature as Command buttons a way for the user to invoke application 
functions or set parameters but in a more organized and more easily accessible fashion 
when there are more than a few buttons. 



Menus, Gadgets, and Cascaded Pop Ups 345 



Figure 12-1 compares a menu to a box full of buttons. 



IView 


Next || 


View Previous 


Delete 


| Move | 


|Copy 


Unmark 


1 View 


In 


New 


II Reply | 


| Forward | 


|Use 


As 


Composition 



























MAIN MENU 



View Next 



View Previou 



Delete 



Move 



Copy 



Unmark 



View In New 



Reply 



Forward 



Use As Compo: 



Figure 12-1. Command widgets in a button box, and the same commands as a menu 

The menu takes up less space because only its title is visible until it is called up.* As a result, 
you can have more menus than you could have permanent button boxes. Commands can be 
presented in smaller, more closely related groups. The user will spend less time searching for 
the desired command. 

The commands in the menu are also easier to read because they are arranged one per row. 
The commands in the menu may even be easier to invoke because it is more natural to drag 
the mouse up and down than from side to side. And last but not least, menus avoid the worst 
problem with button boxes: when the application is resized, button boxes may place each 
command widget in a different position, making it more difficult for the user to find com 
mands, t 

Many of the applications in the core distribution from MIT use button boxes instead of 
menus because there was no menu widget in the Athena widget set until Release 4. Those 
applications that do use menus have implemented them directly with Xlib. All commercial 
widget sets supply one or more menu widgets. 

If you have only the Release 3 Athena widgets, you can simulate a rudimentary menu widget 
using a Box widget that contains Label and Command widgets (as will be demonstrated), and 
convert the application to the R4 menu widgets when you install R4. The R4 menu widgets 



* Under some widget sets and window managers, menus don t even display a title they simply pop up at the pointer 
position in response to a particular pointer button/keypress combination. This is the behavior of the menus provided 
by xterm and uwm. However, this is not very desirable behavior from a user-interface point of view, since it gives the 
user no visual feedback that a menu is available or how to invoke it The user needs the manual something graphi 
cal user interfaces are designed to avoid. 

tTo be fair, there is something to be said for the fact that all the available commands are always visible in an applica 
tion that uses button boxes. You can invoke a button in a box with just a button click, while in a menu it requires a 
press, a drag, and a release. When there are only a small number of commands, putting the command widgets in a 
box is probably better than using a menu. 



346 



X Toolkit Intrinsics Programming Manual 



will not work under R3, because they depend on changes to Xt made in R4 (but most R3 code 
should work under R4). 



12.1 Menu Styles and Implementation 

The conventions for the appearance and user interface of menus (look and feel) in widget sets 
probably varies more than any other aspect of the user interface. 

There are several different styles of menus. As we ve pointed out earlier, a button box is 
itself a style of menu. However, in this chapter, we will be focusing on pop-up 
menus menus that are not visible until the user presses a pointer button or a key-button 
combination. 

There are several different styles of pop-up menu. Probably the most familiar is the pull 
down menu popularized by the Apple Macintosh. A pull-down menu has a label permanently 
visible in the application, usually on a menu bar at the top. When the pointer is clicked on 
the label, and then dragged downwards, the menu is pulled down like a window shade, and 
remains displayed as long as the pointer button is depressed. The currently selected item (as 
indicated by the pointer position within the menu) is highlighted, and is executed when the 
pointer button is released. 

The variation adopted by both Motif and OPEN LOOK (possibly to avoid legal entanglements 
with Apple) is the drop-down menu. The pointer need not be dragged down to display the 
menu. Instead, it appears to drop down as soon as the button is depressed in the menu title. 
(Actually, it doesn t drop down at all, but simply pops up below the menu title.) The distinc 
tion between pull-down and drop-down menus is a subtle one, since with a drop-down menu 
the pointer must subsequently be dragged down the menu in order to make a selection. 

In some cases, selecting an item on the menu or moving off the right side of certain menu 
panes causes a second menu to appear next to the first (usually to the right). This is referred 
to as a cascading pop up. 

Finally, there is the pure spring-loaded pop-up menu used by many of the standard X clients, 
which displays no menu label, and simply pops up at the pointer position, given the appropri 
ate key or button press. 

For example, the menus in xterm pop up when you hold the Control key and press the first or 
second button while the pointer is anywhere in the xterm window. 

One can also imagine many other possible menu styles. For example, an effective user 
interface could be constructed using only pop-up button boxes, emulating the single-line 
menu popularized by Lotus for its character-based 123 spreadsheet. Any given button might 
either execute an action, or pop up a lower-level menu, which would overlay (and thus 
appear to replace) the first menu. 

In this chapter, though, we will focus on the two styles of menu you are most likely to 
encounter in X applications: the drop-down menu and the pure spring-loaded pop up. 
(Though a drop-down menu is technically also a spring-loaded pop up, throughout the rest of 
this chapter, we will use the latter term to refer to an unlabeled, position-independent pop-up 
menu such as that used by xterm.) 



Menus, Gadgets, and Cascaded Pop Ups 347 



The difference between spring-loaded and drop-down menus is primarily in the method of 
placing the menu before popping it up; one menu widget class can usually work in either 
style. 

To be precise, the Xt specification makes the distinction between modeless pop ups, modal 
pop ups, and spring-loaded pop ups. 

Modeless pop ups are windows that, once popped up, are subject to window manager control, 
and for all intents and purposes act like regular applications in themselves. A help window 
that stayed up, and could be moved and resized like a regular window once popped up is an 
example of this type of pop up. It is referred to as "modeless" because it doesn t put the 
application into a special mode, in which only input to the pop up is allowed. 

A modal pop up may or may not be visible to the window manager, and disables user-event 
processing by the application, except in the pop up itself. A dialog box that requires the user 
to enter data or click on a button is an example of a modal pop up. Typically, input may still 
be possible to other applications. 

A spring-loaded pop up, as defined by Xt, is invisible to the window manager, and disables 
user input to all windows, except to the pop up itself. The most important thing about spring- 
loaded pop ups is that they are invoked with a key or pointer button press, whereas another 
type of pop up might be invoked as a routine part of application processing, or just because 
the pointer entered a particular window. 

However, due to a lack of appropriate terminology, throughout this chapter we use the term 
"spring-loaded pop up" to refer to menus that pop up at the pointer position when a button is 
pressed, as opposed to drop-down or pull-down menus. 

1 2.1 .1 How Menus are Popped Up 

How you create menus in an application differs according to the class of menu widget and 
whether it will be drop-down or spring-loaded. Commercial widget sets are designed to 
make it quite easy to create menus that fit into their user-interface conventions. As usual, the 
examples in this chapter use the Athena widgets to implement various types of menus. 
Although the procedure for creating menus under the widget set you plan to use may be dif 
ferent, many of the underlying issues are the same. 

In Section 3.3, a dialog pop up was created by first creating a pop-up shell, and then creating 
the widget to be popped up as a child of the pop-up shell. This procedure is used for some 
menu widgets, but most menu widgets are themselves subclasses of Shell, and therefore no 
separate shell needs to be created. You just create an instance of the menu widget itself, 
using XtCreatePopupShell instead of XtCreateManagedWidget. 

To have a spring-loaded pop up, your application usually adds an action that places the 
widget in the application main window. (Xt has a standard action for popping up a widget, 
but by default it places the widget at the top-left corner of the screen. As a result, you must 
use it in conjunction with an action of your own, which moves the invisible shell widget to 
the desired location before it is actually popped up.) The application-defaults file should 
supply a translation to specify what event sequence will call up that menu. 



348 X Toolkit Intrinsics Programming Manual 



In some cases, a menu widget itself may add actions and translations to the parent so that the 
widget can be popped up in spring-loaded fashion without any application code. In others, 
the widget will add the actions but leave the user or the application writer to define the trans 
lation that will invoke the action. 

To use a menu in drop-down fashion, you create a Command widget and use its callback to 
pop up the menu, or better still, use a widget specially made to invoke a drop-down menu, 
and tell it the name of the shell to be popped up (which as just mentioned may be the menu 
widget itself). 

Menus differ widely on their conventions for when to pop down. Most menus pop down after 
a choice is made. In this case, the callback invoked to tell the application about the menu 
choice would pop down the widget, or perhaps the menu widget itself would pop itself down 
before calling the chosen item s callback. Some menus pop down whenever the button that 
popped them up is released (for example, xterm), even if the pointer is outside the menu 
when the button is released. Some pop down whenever the pointer moves out of the menu 
(for example, uwm)* OPEN LOOK menus provide a pushpin metaphor that allows the user to 
keep a pop-up menu on the screen, where it will be handy for repeated use. 



12.1.2 Menu Panes 



The style of the items, or panes, in the menus also varies widely. Panes are usually imple 
mented using one or more subwidgets, or in the case of Motif and the Athena SimpleMenu 
widget, with gadgets, which are windowless objects that can be drawn and managed sepa 
rately within a widget There may be several different widgets or gadgets that implement 
menu panes with different input and output semantics. 

If the panes are widgets, they are created with xtCreateManagedWidget, or in some 
menu widgets, by specifying resources of the menu widget, which will then create its own 
panes; how gadgets are created is discussed later in this chapter. 

Figure 12-2 shows menus developed using OSF s Motif and AT&T s OPEN LOOK Toolkit, 
which you can compare and contrast with each other and with the R4 Athena SimpleMenu 
widget shown in Figure 12-1. 



*Most people find it annoying to have menus that pop down when the pointer moves out of them. It is too easy to ac 
cidentally move outside the menu and have to start all over. All the menus in this chapter pop down the menu when 
the choice is made, or when the button is released outside the menu. 



Menus, Gadgets, and Cascaded Pop Ups 349 



v) (options v) (help (F I ) 




J^, 


mre 


j 


j 



File Edit 



View 



Options 



Help (Fi) 



New . 
Open 



A N 
A O 



Save ...... A S 

Save As .... A A 

Exit . . A E 



Figure 12-2. Menus from the OPEN LOOK and Motif widget sets 

The Athena SimpleMenu widget has rectangular panes that display an identifying string, and 
an optional bitmap before and/or after the string. For example, the bitmap can be used to 
place a checkmark to the left of the label (indicating that an option has been selected and is 
in effect), or an arrow to the right, indicating that selecting this pane will produce a cascad 
ing submenu. When an item is selected, it is displayed in inverse video. 

Motif menu panes are rectangular. The currently-selected pane is highlighted with a simu 
lated 3-D shadow. Panes may contain either a string or a bitmap. 

OPEN LOOK menus come with several types of panes, depending on the type of menu item. 
Commands, whether available from menus, or in other control areas, are represented by 
oblong buttons with rounded ends. (Buttons that generate menus (or submenus) follow their 
label with an arrowhead pointing in the direction where the submenu will appear.) Exclusive 
options are shown as adjacent rectangles, with the one currently chosen highlighted by a dark 
border. Nonexclusive options are displayed in rectangles with a small separation between 
each one. Panes may contain a string or a bitmap, or both. 

However, what all menu widgets have in common is that the application programmer can set 
the label of each pane and the function it invokes. Exactly how to do this varies according to 
the widget set you use. 



350 



X Toolkit Intrinsics Programming Manual 



See Appendix A, OPEN LOOK and Motif, for more information on how Motif and OPEN 
LOOK implement menus. 



12.2 Several Ways to Create and Use Menus 



You already know how to create a pop-up shell, create a Box as its child, fill it with Com 
mand widgets, label the Command widgets, and register a callback function for each one. By 
doing this you can create a basic menu. Its performance is rather sluggish, but it looks and 
works like a menu and is the best you can do with the R3 Athena widgets without writing a 
menu widget of your own. If you are using the R3 Athena widgets, you can use this tech 
nique until you have access to the R4 Athena SimpleMenu widget or one of the commercial 
widget sets. 

This section describes how to use the menu made from a box full of buttons in two different 
menu styles: spring-loaded and drop-down. The purpose of this exercise is to expose some 
of the issues involved in event-management of pop ups. Some of these issues may be hidden 
in the widgets or facilities provided by some commercial widget sets, but seeing how to do 
the event management explicitly should help you to understand and use pop ups more effec 
tively. 

The challenge of creating a pop up with Box and Command buttons is to make it pop up and 
down at the right times, and to control its event handling to fit the menu style. We will also 
experiment with creating a cascaded menu, in which one menu pane in a main menu invokes 
a submenu. 

Finally, this section describes how to create a menu using the R4 SimpleMenu widget and its 
gadget children. 

12.2.1 A Spring-Loaded Menu: Pointer Grabbing 

A spring-loaded menu should pop up when a button press occurs in a particular widget; 
usually the application s main window. The menu should stay visible as long as the user 
holds down that button, and disappear when the button is released. If the button is released in 
a menu pane, the function registered for that pane should be invoked. If the button is 
released outside the menu, no function should be invoked but the menu should still be 
popped down. 

The only tricky part of implementing a spring-loaded menu is getting the menu to pop down 
when the button is released outside the menu. Since this occurs outside the menu and possi 
bly outside the application, the X server will not send the button release event to the applica 
tion unless a grab is in effect. Normally, user events are sent to the window that contains the 
pointer. But after an application makes a grab, the X server sends all events of particular 
types to the window that made the grab, even if the pointer is no longer in the window. 

The X server defines several types of grab: keyboard grabs, pointer grabs, and server grabs. 
Keyboard and pointer grabs control only input from the indicated device, while server grabs 
make the server act on requests from one application exclusively. (Server grabs are mainly 



Menus, Gadgets, and Cascaded Pop Ups 351 



used by window managers.) Pointer grabs are used for controlling events in pop ups when a 
pointer button pops up the pop up, and keyboard grabs are used when a key press pops up the 
pop up. We will discuss pointer grabs since keyboard grabs are analogous (and keyboard- 
triggered pop ups are less common). 

There are two types of pointer grabs, passive grabs and active grabs. An active grab is 
invoked directly with the Xlib function XGrabPo inter. This function tells the server that 
you want the grab to begin right away, and to continue until specifically released with 
XUngrabPointer. Active grabs are not normally used for pop ups.* 

A passive grab tells the server that you want a grab to begin when a certain key or button 
combination is pressed in a certain window (the combination that is to pop up the pop up). 
The grab continues until the button in the combination is released. This is perfect for menus 
because we need the grab only until the button is released. (Also, as you ll see in the section 
on drop-down menus, you can register several passive grabs for the same key-button combi 
nation as long as each grab is initiated by a press in a different window. This allows you to 
have as many drop-down menus as you want. Since spring-loaded pop ups are generally 
invoked by a press in the same window the application main window you will need to 
use a different key-button combination for each different menu.) 

Xt provides three ways of popping widgets up and down: 

There are three built-in callback functions: xtCallbackNone, xtCallback- 
Exclusive, and XtCallbackNonexclusive. Each of these functions pops up a 
widget with a different type of grab, as indicated by its name. XtCallbackNone 
makes no grab at all. The difference between an exclusive grab, as caused by xt- 
CallbackExclusive, and a nonexclusive grab, as caused by XtCallback 
Nonexclusive, has to do with the handling of cascading widgets. In brief, an exclu 
sive grab constrains input to the widget actually making the grab (the latest widget in the 
cascade), while a nonexclusive grab allows input to any widget in the cascade. We ll talk 
more about this in Section 12.2.3, when we talk about pop-up cascades. 

XtCallbackPopdown is the corresponding built-in callback function to pop down a 
widget. 

There are two built-in actions, MenuPopup and MenuPopdown, that pop up or pop 
down a widget You can use these actions in translation tables in the application-defaults 
file or application code. MenuPopup always asserts an exclusive grab. 

There are two functions, xtPopup and XtPopdown, that you can call directly in your 
application code to pop up or pop down a widget. Xt Popup has a grab_kind argu 
ment that lets you specify whether to assert an exclusive or nonexclusive grab, or no grab. 

Each of these ways is appropriate for different situations, and they are often used in combina 
tion. Each will be described in the sections below. 



*One reason that XGrabPo inter is rarely used for pop ups is that it requires that the window that will receive the 
grabbed events be visible. This is often not the case. In a menu, for example, the window that you want to grab the 
events is hidden by the menu panes even when the menu is popped up. Another reason is that you need to call 
XUngrabPointer to release the grab when finished. Passive grabs match the task better. 



352 X Toolkit Intrinsics Programming Manual 



Passive grabs can be invoked directly using the Xlib functions XGrabButton and 
XGrabKey. However, Xt takes care of making the appropriate passive grab if you use the 
MenuPopup action to pop up your shell widget. As we will see, the other two ways to pop 
up a widget do not make any grab, which makes them inappropriate for popping up main 
menus. However, they are still useful for some types of dialog boxes and for cascading sub 
menus, if the main menu has used MenuPopup to assert an exclusive grab. We ll return to 
this subject in Section 12.2.3.* 

A pop-up menu grabs the pointer to force the user to make a menu choice before leaving the 
menu, or to pop down the menu if no choice is made. However, this grab is necessary for 
another reason as well. The X server automatically grabs the pointer beginning at a button 
press and ending at the release of the same button. Since the initial button press pops up the 
menu, the next button release would also arrive at the same widget the application main 
window even if the pointer were already in the menu. Furthermore, the application main 
window would get all EnterNotify and LeaveNotify events, so the Command wid 
gets in the menu wouldn t get any of them. When the menu is popped up with MenuPopup 
action, this cancels the automatic grab. (Of course, pointer grabs redirect only the events 
caused directly by the pointer; ButtonPress, ButtonRelease, EnterNotify, 
LeaveNotify, and MotionNotify. All other events (most notably Expose events) 
occur and are delivered normally.) 

With that background, let s take a look at an application that provides a spring-loaded menu. 
The xmenul application s permanent appearance is a variation of xbox\ it displays a large 
Label widget that we are using to simulate an application s main window and a Command 
widget for quitting. Pressing any button in the Label widget calls up the menu, which oper 
ates as described at the beginning of this section, xmenul is shown in Figure 12-3. As usual, 
we suggest you compile and run this example now. 



*XtPopup, XtCallbackExclusive, and XtCallbackNonexclusive in fact make no grab at all. As 
we will see, this is needed to make them useful for submenus, and they are also useful for dialog boxes. In R4, a new 
function called XtPopupSpringLoaded has been added as a version of XtPopup that does make a passive 
grab. Since all R4 changes are backwards compatible with R3, the XtCallback* callback functions have not 
been changed and will still not be useful for menus (although they will still be useful for some dialog boxes). With 
XtPopupSpringLoaded you can also write callback functions that are the equivalent of XtCallback*, ex 
cept that they will pop up a menu with a passive grab. 



Menus, Gadgets, and Cascaded Pop Ups 353 



This is a Pretend Main LJlndr"--* P*~ 



MAIN MENU 



View Next 



View Previous 



Delete 



Move 



Copy 



Unmark 



View In New 



Reply 



Forward 



Use fts Comp 



Figure 12-3. xmenul: application with spring-loaded pop-up menu 

The relevant code in xmenul consists of an action routine to place the pop up, code to add the 
action, a callback routine to handle when a menu item has been chosen, and code to create 
the Box populated with Command widgets that will act as the menu. Example 12-1 shows 
the complete code. 

Example 12-1. xmenul: complete code 

I * 

* xmenul. c - simple spring-loaded menu 
*/ 

/* 

* So that we can use fprintf: 

*/ 

tinclude <stdio.h> 

/* 

* Standard Toolkit include files: 
*/ 

tinclude <Xll/Intrinsic.h> 
tinclude <Xll/StringDef s .h> 

tinclude <Xll/Shell .h> 

/* 

* Public include files for widgets used in this file. 
*/ 

tifdef X11R3 

tinclude <X11 /Command. h> 
tinclude <Xll/Box.h> 
tinclude <Xll/Label .h> 
telse /* R4 or later */ 



354 



X Toolkit Intrinsics Programming Manual 



Example 12-1. xmenul: complete code (continued) 

#include <Xll/Xaw/Command.h> 
#include <Xll/Xaw/Box.h> 
finclude <Xll/Xaw/Label .h> 
#endif /* X11R3 */ 

The popup shell ID is global because both dialog and pshell 
are needed in the dialogDone callback, and both can t be 
passed in without creating a structure. 
i 

Widget pshell; 

void PlaceMenu (w, event) 
Widget w; 
XButtonEvent *event; 

Arg args [ 5 ] ; 

int i; 

/* should make sure coordinates let menu fit on screen */ 

/* 

* move submenu shell slightly to left and above button 

* position 
*/ 

i = 0; 

XtSetArg(args [i] , XtNx, event->x_root - 10); 
XtSetArg(args[i] , XtNy, event->y_root - 10); 
XtSetValues (pshell, args, i) ; 



/* 

* guit button callback function 

*/ 

void Quit (w, client_data, call_data) 
Widget w; 

caddr_t client_data, call_data; 
{ 

exit (0) ; 



/* 

* menu pane button callback function 

*/ 

void PaneChosen (w, pane_number, call_data) 
Widget w; 

int pane_number; /* client_data */ 
caddr_t call_data; 

printf ("Pane %d chosen. \n", pane_number) ; 
XtPopdown (pshell) ; 



main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget topLevel, box, label, guit, menubox, 



Menus, Gadgets, and Cascaded Pop Dps 



355 



Example 12-1. xmenul: complete code (continued) 

menulabel, menupane [ 10] ; 
int i; 
String buf [50] ; 

static XtActionsRec trial_actions [ ] = { 
{"placeMenu", PlaceMenu}, 

}; 

topLevel = Xtlnitialize ( 

argv[0], /* application name */ 

"XMenul", /* application class name */ 

NULL, /* application resources (not used) 

0, /* application resource count */ 

&argc, /* command line argument count */ 

argv) ; /* command-line string */ 

box = XtCreateManagedWidget ( 

"box", /* widget name */ 

boxWidgetClass, /* widget class */ 

topLevel, /* parent widget*/ 

NULL, /* argument list*/ 

/* arglist size */ 

label = XtCreateManagedWidget ( 

"label", /* widget name */ 

labelWidgetClass, /* widget class */ 
box, /* parent widget*/ 

NULL, /* argument list*/ 

/* arglist size */ 

quit = XtCreateManagedWidget ( 

"quit", /* widget name */ 

commandWidgetClass, /* widget class */ 
box, /* parent widget*/ 

NULL, /* argument list*/ 

/* arglist size */ 

pshell = XtCreatePopupShell ( 
"pshell", 

transient ShellWidget Class, 
topLevel, 
NULL, 

); 

menubox = XtCreateManagedWidget ( 

"menubox", /* widget name */ 

boxWidgetClass, /* widget class */ 
pshell, /* parent widget*/ 

NULL, /* argument list*/ 

/* arglist size */ 



menulabel = XtCreateManagedWidget ( 

"menulabel", /* widget name */ 
labelWidgetClass, /* widget class */ 



356 X Toolkit Intrinsics Programming Manual 



Example 12-1. xmenul: complete code (continued) 

menubox, /* parent widget*/ 

NULL, /* argument list*/ 

/* arglist size */ 

for (i = 0; i < 10; i++) { 

sprintf(buf, "menupane%d", i) ; 

menupane[i] = XtCreateManagedWidget (buf , /* widget name */ 
commandWidgetClass, menubox, NULL, 0) ; 

XtAddCallback (menupane[i] , XtNcallback, PaneChosen, i) ; 

XtAddActions (trial_actions, XtNumber (trial_actions) ) ; 
XtAddCallback (quit, XtNcallback, Quit, 0); 
XtRealizeWidget (topLevel) ; 
XtMainLoop ( ) ; 

The PlacePopup action just places the pop up slightly to the left and above the position 
where the pointer button that popped it up was clicked, using the coordinates reported in the 
button event. The offset of ten pixels from the pointer position simply helps to make sure 
that the pointer is inside the menu.* Remember that the window created by a pop-up shell 
widget is a child of the root window and therefore is placed relative to the root window. The 
ButtonPress event pointer coordinates relative to the root window are used. 

The PaneChosen callback function is a stub function used in this example as the notify 
callback for all the menu panes. In this example, it simply prints the name of the chosen pane 
to stdout and then pops down the menu using XtPopdown. In a real application, a different 
callback function would probably be registered for each pane. 

Instead of calling XtPopdown in each of these separate callback functions, you could write 
a single additional callback function that calls xtPopdown, and then add it to the callback 
list for the Command widget that makes up each menu pane. 

As usual, the pop up is created by first creating a pop-up shell, then a Box widget as its child, 
and then a series of Label and Command widgets as children of Box. The pop-up shell is 
itself invisible. As with all menus, what you actually see is the array of children. 

Note that this program does not include any code that would pop up the menu. We ve done 
that from the application-defaults file shown in Example 12-2. The translations for the Label 
widget invoke Xt s built-in MenuPopup action. 



*It is important to provide a consistent user interface, so you should use the same offset in all menus. Menus in com 
mercial widget sets such as the OPEN LOOK widgets have carefully designed and documented policies about pop-up 
window placement. This allows the user s "pointer reflexes" to be trained, so that using menus becomes as automatic 
and easy as possible. 



Menus, Gadgets, and Cascaded Pop Ups 357 



Example 12-2. XMenul: the application-defaults file 

i 

! Appearance Resources 

i 

*quit. label: Quit 

*label . label : This is a Pretend Main Window; Press in here. 

*menulabel. label: FILE MENU 

i 

! make all entries in menu same width (adjust value for longest entry) 
i 

*menulabel .width: 80 
*menubox . Command. width: 80 
*menupaneO . label : Create 
*menupanel . label : Open 
*menupane2 . label : Delete 
*menupane3 . label : Rename 

*menupane4 . label : Copy 
i 

! make Box leave no space around Command widgets in menu 
i 

*pshell .Box .hSpace : 
*pshell .Box . vSpace : 
i 

! Translation Resources 

i 

*menubox . Command . translations : \ 

<EnterWindow>: highlight () \n\ 

<LeaveWindow> : reset () \n\ 

<BtnUp>: set() notify () unset () 

* label .translations : \ 

<BtnDown>: placeMenu() MenuPopup (pshell) 
* pshell . translations : \ 

<BtnUp> : MenuPopdown (pshell) 

There are a number of settings designed to give the Box widget a characteristic menu appear 
ance: all of the Command widgets are forced to have the same size (rather than the size of 
their label), and the Box widget is forced to leave no space between the command widgets. 

However, it is the new translations that are the critical part of this application-defaults file. 
The Label widget must be given translations so that a button press will pop up the widget. 
The supplied translation maps a button press into a call to the application action Place- 
Popup and then to Xt s predefined MenuPopup action. The argument to MenuPopup in 
the translation is the instance name of the pop-up shell. Xt converts this string name into the 
widget ID of the pop-up shell before it can pop up the widget 

We are replacing rather than overriding this widget s translations because it is a Label widget 
and has no default translations. 

The menu panes are Command widgets, but we need to adjust their event response so that 
they will be triggered on a button release with no corresponding press (since the press that 
popped up the menu occurred in the application main window). We are replacing their trans 
lations to get rid of the translation for ButtonPress (which would still be present if we 



358 X Toolkit Intrinsics Programming Manual 



used the # augment directive, and we would have to create an action that did nothing in 
order to replace it with tfoverride). The translation for ButtonRelease (BtnUp in 
the translation table) calls all the actions that usually occur in Command widgets with both 
press and release. 

Perhaps least obvious is the translation we have added to pop down the menu when the 
pointer button is released outside the menu. As mentioned earlier, Xt makes a passive pointer 
grab on the pop-up shell (pshell) in the MenuPopup action. When the pointer is inside 
the menu, the Command widgets intercept these grabbed events, because they are descen 
dants of pshell and they have a translation for ButtonRelease events. This invokes 
the actions in the selected Command widget. But when the pointer is outside the menu, the 
grabbed events are sent directly to the widget that was specified in the grab call, namely 
pshell. Therefore, the translation to pop down the menu on button release must be added 
to pshell. (Again, this translation table is simply replaced because the pop-up shell nor 
mally has no translations.) 



A Drop-Down Menu 

What are the desired characteristics of a drop-down menu? There is a Command widget or 
the like permanently visible in the application, with a label indicating some common charac 
teristic of the items in the menu. When a button is pressed in this widget, the menu should 
pop up on or just below the button. Dragging the pointer down through the menu with the 
button still held should highlight the entry that is pointed to. Releasing the button in an entry 
should invoke or set that entry, and pop down the menu. Moving out of the menu should not 
change this behavior, except that if the button is released anywhere outside of a menu pane, 
the menu should pop down without executing any entry. 

If you compile and run xmenu2 you can try out this style of menu. The appearance of this 
application is shown in Figure 12-4. 




Figure 12-4. xmenu2: a drop-down menu 



Menus, Gadgets, and Cascaded Pop Ups 



Invoking a menu as a drop-down is a simple enhancement of the spring-loaded invocation 
method just shown. We can do everything exactly the same as in the spring-loaded example, 
except that a drop-down menu should appear just below the pressme widget, not at the 
pointer position. Therefore, all we need to change is the placement code. However, since the 
coordinates in the event are not necessary for placing the pop ups, we can use a callback 
function instead of an action to place the pop up. (In general, it is better to use an existing 
callback than to add an action to do the same thing.) 

Pop-up shell widgets have XtNpopupCallback and xtNpopdownCallback callback 
resources; the functions on these callback lists are called whenever the pop up is popped up 
or down using any of the Xt mechanisms. 

In the last example we created an action called PlaceMenu, to move the pop-up shell 
before it was actually popped up. We included it in a translation along with the standard 
action MenuPopup, which was actually used to pop up the widget. xmenu2 also uses the 
standard action MenuPopup to pop up the widget, but it uses the XtNpopupCallback 
resource to invoke the code to place it. This saves having to reference the placement action 
in the translation table. This is preferable, since the placement code should almost always be 
hardcoded rather than user-configurable. Another advantage of the pop-up and pop-down 
callbacks is that you may arrange for a pop up to be popped up or down in more than one 
way, and it may be convenient to have certain code called automatically in all cases. 

(You can also use the XtNpopupCallback resource to specify a callback function to cre 
ate a pop-up widget the first time it is popped up, instead of at application startup. The one 
problem is that the functions on the callback list are invoked every time the widget is popped 
up. To make sure that it creates the pop up only once (the first time), the callback function 
should remove itself from the callback list by calling XtRemoveCallback.) 

There is not enough difference between xmenul and xmenu2 to merit showing the complete 
code. All we have done is changed the PlaceMenu function from an action into a callback 
and changed its placement logic to place the pop-up relative to the invoking Command 
widget We have then modified the application-defaults file accordingly. 

Example 12-3 shows the PlaceMenu routine (now a callback, not an action) and the code 
to register it as a callback. 

Example 12-3. xmenu2: code to place drop-down menu 

void PlaceMenu (w, topLevel, call_data) 

Widget w; 

Widget topLevel; /* client_data */ 

caddr_t call_data; 

{ 

Position x, y; 

Arg arg [2] ; 

int i; 

int val; 

/* 

* Translate coordinates of invoking Command widget 

* into root window coordinates. 
*/ 

XtTranslateCoords (pressme, /* Widget */ 
(Position) 0, /* x */ 



360 X Toolkit Intrinsics Programming Manual 






Example 12-3. xmenu2: code to place drop-down menu (continued) 

(Position) 0, /* y */ 

&x, &y) ; /* coords on root window */ 

/* 

* Move pop-up shell so that it completely covers invoking 

* button, assuming border width of 1 (menu not visible yet) 
*/ 

i = 0; 

XtSetArg(arg[i] , XtNx, x - 1); 
XtSetArg(arg[i] , XtNy, y - 1); 
XtSetValues (pshell, arg, i) ; 
} 

main (argc, argv) 
int argc; 
char **argv; 



XtAddCallback (pshell, XtNpopupCallback, PlaceMenu, topLevel) 



Xt calls the functions on the XtNpopupCallback list before it pops up the widget. This 
means that PlaceMenu is called before the MenuPopup action, placing the widget before 
it is popped up. 

Note that the xtTranslateCoords routine determines the root window coordinates at 
the origin of the pressme widget. Because of the reparenting done by most window man 
agers, this information cannot be obtained by using xtGetValues to read the XtNx and 
XtNy resources.* 

Example 12-4 shows the translation portion of the application-defaults file. 

Example 12-4. XMenu2: translation portion of the application-defaults file 

i 

! Translation resources 
i 

*pressme . translations : \ 

<EnterWindow>: highlight () \n\ 

<LeaveWindow> : reset () \n\ 

<BtnDown>: set() MenuPopup (pshell) reset () 

l 

*pshell .translations : \ 

<BtnUp>: MenuPopdown (pshell) 



*Incidentally, XTranslateCoordinates, the Xlib equivalent of XtTranslateCoords, gets the same in 
formation and a little more by querying the server. XtTranslatCoords does not have to make a server request 
because Xt stores this data locally. Each time a window in this application is moved, Xt receives this information as 
an event and updates its knowledge of the position of each window. This is an important optimization, because 
server queries are subject to network delays and tend to slow applications. 






Menus, Gadgets, and Cascaded Pop Ups 361 



Example 12-4. XMenu2: translation portion of the application-defaults file (continued) 

*menubox . Command . translations : \ 

<EnterWindow>: set() \n\ 

<LeaveWindow> : unset () \n\ 

<BtnUp>: notify () unset () 

These translations are different from those forxmenul only in that pressme is a Command 
widget, which already has its own translation table, rather than a widget without existing 
translations. We have modified the translations of pressme to be suitable for this use. 
Note that the translation no longer calls PlaceMenu as an action because it is now a call 
back. 

The translations for the menu pane Command widgets are also somewhat different from 
xmenul, but only for cosmetic reasons. This iteration of the xmenu example uses the set 
and unset actions instead of highlight and reset or unhighlight to make the 
Command widgets highlight their entire box instead of just an area near the border. 
(Although this modification makes the menu look more like a typical menu, it also seems to 
make it slower.) 

To create several menus you simply need to replicate the code shown here, changing the vari 
able names for each menu. The passive grabs invoked by Xt for each menu do not interfere 
with each other even if they specify the same key/button combination, because they specify 
different windows in which the key/button combination will begin the grab. 

12.2.3 Cascaded Menus 

A cascaded menu is a menu in which one or more panes do not invoke functions but instead 
bring up additional menus. 

The techniques used to bring up cascaded menus can also be used to have dialog boxes bring 
up other dialog boxes. However, cascaded menus are more challenging because they rely on 
the passive pointer grab to receive the ButtonRelease event that occurs outside the 
menu and application. 

You can implement a cascaded menu the same way for both spring-loaded and drop-down 
menus, simply by adding to the code we ve already written to implement a single menu. 
We ll show you xmenuS, the spring-loaded version, since it is slightly shorter. (xmenu4 is the 
equivalent drop-down version.) Both are included in the example source code. In this 
example, only one menu pane will be used to invoke a submenu. However, this technique 
can be generalized to have additional panes bring up additional submenus. 

First, let s describe exactly how we expect the cascaded menu to work. Figure 12-5 shows 
both menus popped up. (Compile the program and try it.) 

The main menu works as described above. However, one of the panes the one that brings 
up the submenu has an arrow pointing to the right after its label. This pane does not high 
light itself when the pointer moves inside (telling the user that this pane is different). 
Instead, when the user moves the pointer out through the right edge of the pane, the submenu 
pops up. The submenu operates just like the main menu. When the button is released inside 



362 X Toolkit Intrinsics Programming Manual 



[Quit | 


This is a Pre 




bw; Press in here. 




MAIN MENU 






View Next 




View Previous 


Delete 


Move 


Unmark 


SUB MENU 


Copy To ==> 


Xnews folder 


View In New 


Xt folder 


Reply 


XI ib folder 


Forward 


Xconsortium folder 


1 IP Q* Pnmo 



Drafts folder 



Misc folder 



Personal folder 



Xprotocol folder 



To Do List 



Figure 12-5. xmenuS: cascaded spring-loaded menus 

either menu, the callback function associated with the chosen pane will be invoked. When 
the button is released outside of either menu, both menus pop down. If the pointer is moved 
back out of the submenu into the main menu, only the submenu pops down. 

To create the submenu, we create a new pop-up shell, Box widget, and a set of Command 
widgets, and add callbacks for each function the submenu panes will invoke (in this example, 
one common callback). Then we write three actions; PlaceMenu (which you have already 
seen), CheckRightAndPopupSubmenu (which places and pops up the submenu if the 
pointer leaves the main menu pane through its right side), and CheckLef tAndPopdown- 
Submenu (which pops down the submenu if the pointer leaves the submenu through the por 
tion touching the main menu). These actions are shown in Example 12-5. 

Example 12-5. xmenuS: actions that place, pop-up, and pop-down main menus and sub 
menus 

void PlaceMenu (w, event) 
Widget w; 

XButtonEvent *event; 
{ 

Arg args [5] ; 

int i; 

/* should make sure coordinates let menu fit on screen */ 



Menus, Gadgets, and Cascaded Pop Ups 



363 



Example 12-5. xmenuS: actions that place, pop-up, and pop-down main menus and sub 
menus (continued) 

/* move submenu shell to slightly left and above button 
* press position */ 

i = 0; 

XtSetArg(args[i] , XtNx, event->x_root - 10); 
XtSetArg(args[i] , XtNy, event->y_root - 10); 
XtSetValues (pshell, args, i) ; 

} 

void CheckRightAndPopupSubmenu (w, event) 
Widget w; 

XLeaveWindowEvent *event; 
{ 

Arg arg; 

int i; 

Dimension height; 

i = 0; 

XtSetArg(arg, XtNheight, Sheight) ; i++; 

XtGetValues (w, &arg, i) ; 

if ( (event->x > 0) && (event->y > 0) && (event->y < height)) { 
/* move submenu shell to start just right of pane, 

* using an arbitrary offset to place pointer in 

* first item. */ 
i = 0; 

XtSetArg(args [i] , XtNx, event->x_root) ; i++; 
XtSetArg(args [i] , XtNy, event->y_root - 12); 
XtSetValues (subshell, args, i) ; 
XtPopup (subshell, XtGrabNonexclusive) ; 



void CheckLeftAndPopdownSubmenu (w, event, params) 

Widget w; 

XLeaveWindowEvent *event; 

String params; 

{ 

Arg arg; 

Dimension sub_height, menu_height; 

Position dummy_menu_x, menu_y; 

int i; 

i = 0; 

XtSetArg(arg, XtNheight, &sub_height) ; 

XtGetValues (subbox, &arg, i) ; 

i = 0; 

XtSetArg(arg, XtNheight, &menu_height) ; 

XtGetValues (menubox, &arg, i) ; 

XtTranslateCoords (menubox, /* Widget */ 

(Position) 0, /* x */ 

(Position) 0, /* y */ 

&dummy_menu_x, &menu_y) ; /* coords on root window */ 

if ( (event->x < 0) && (event->y >= 0) && 
(event->y <= sub_height) && 



364 X Toolkit Intrinsics Programming Manual 



Example 12-5. xmenuS: actions that place, pop-up, and pop-down main menus and sub 
menus (continued) 

(event->y_root <= menu_y + menu_height) ) { 
/* moved out left side (requires that it 

* move out directly into the main menu) */ 
XtPopdown (subshell) ; 



As usual, the application-defaults file specifies which events trigger these actions. We ll 
show this file in a moment, but for now you need to know just that CheckRightAnd- 
PopupSubmenu and CheckLeftAndPopdownSubmenu are triggered by Leave- 
Notify events. We want the submenu to pop up and down only when the pointer leaves 
through certain parts of certain sides of the widget the entire right side of a pane for pop 
ping it up, and the part of the submenu touching the main menu on the left side for popping it 
down. These two actions are called in response to all LeaveNotify events, and they 
check if the pointer left through the correct parts before popping up and down the submenu. 

As you may recall, we mentioned earlier that no matter what the arguments, xt Popup and 
all other Xt facilities for grabbing, except MenuPopup, make no passive grab, and therefore 
can t be used for spring-loaded or drop-down main menus. It turns out that for submenus the 
opposite is true XtPopup and xtCallback* work fine, and but MenuPopup is inap 
propriate, because no new passive grab is needed. The original grab directs events normally 
to all widgets in the application including the submenu, and directs all events that occur out 
side the application to pshell. 

The CheckRightAndPopupSubmenu action calls XtPopup with a grab mode of Xt- 
GrabNonexclusive. This grab mode controls Xt s event dispatching within the applica 
tion it has nothing to do with the passive grab that Xt makes from the MenuPopup action. 
XtGrabNonexclusive means that widgets in the cascade but outside of the submenu 
will continue to get events normally. The grab mode specified in the call to XtPopup, or 
specified by the standard pop-up callback function selected (xtCallbackExclusive or 
xtCallbackNonexclusive) merely control the event dispatching within the applica 
tion. 

As an exercise, you may want to modify the example so that CheckRightAndPopup 
Submenu calls XtPopup with a grab mode of XtGrabNonexclusive. The xtGrab- 
Exclusive mode means that only the most recent pop up popped up will get events, while 
XtGrabNonexclusive means that all pop ups in a popped up cascade will get events. In 
this case, when the submenu is popped up, it alone will get pointer events if you use grab 
mode XtGrabExclusive, while both it and the main menu will get pointer events if you 
use grab mode XtGrabNonexclusive. Because of the logic that pops down the sub 
menu when the pointer leaves it through the portion adjoining the main menu, you can see 
this difference only if you move out through another part of the submenu and then around 
into the main menu again. (In the example code distribution, xmenuS.c uses XtGrab 
Nonexclusive and xmenu4.c uses XtGrabExclusive, so that you can compare the 
results of these two flags.) 



Menus, Gadgets, and Cascaded Pop Ups 365 



The user-interface conventions for a particular widget set usually specify which kinds of pop 
ups should have exclusive grabs and which nonexclusive. Note that the effect of these two 
grab modes is the same unless there is more than one pop-up widget in a cascade visible. 

CheckRightAndPopupSubmenu places the submenu itself (instead of using a separate 
action) because the menu should be placed only when it is first popped up. If the placement 
code were a separate action, it would be called every time a Leavewindow event arrived, 
even if not through the correct border of the widget (Remember that this code is in an action 
rather than a callback because it uses the contents of the event.) 

The translation portion of the application-defaults file forxmenuS is shown in Example 12-6. 
Example 12-6. XMenuS: translation portion of application-defaults file 

! Appearance resources 
*menupane3 . label : Colors Menu > 
(other appearance resources not shown) 

i 

! Translation resources 
i 

! popping up Main Menu 
* label . translations : \ 

<BtnDown>: placeMenuO MenuPopup (pshell) 

i 

! Main Menu translations 
*menubox . Command . translations : \ 

<EnterWindow>: highlight () \n\ 

<LeaveWindow> : reset () \n\ 

<BtnUp>: set() notify () unset () 

t 

! SubMenu translations 
*subbox . Command . translations : \ 

<EnterWindow>: highlight () \n\ 

<LeaveWindow> : reset () \n\ 

<BtnUp>: set() notify () unset () 

i 

! popping down both menus 
*pshell . translations : \ 

<BtnUp>: MenuPopdown (subshell) MenuPopdown (pshell) 

i 

! popping up submenu (maybe) 
*menubox .menupane3 . translations : \ 

<LeaveWindow> : CheckRightAndPopupSubmenu ( ) 

i 

! popping down submenu (maybe) 
*subbox . translations : \ 

<LeaveWindow> : checkLeftAndPopdownSubmenu (subbox) 

The first three translation tables handle popping up the main menu and making the menu 
Command widgets work as expected. We ve seen these in previous examples. 



366 X Toolkit Intrinsics Programming Manual 



The translation table for pshell pops down one or both menus; no error or warning is 
caused if only the main menu is up. This translation table works because the button release is 
sent to pshell if it occurs outside a menu regardless of whether just the main menu or both 
menus are up. 

In this case, menu pane 3 is the pane that will pop up the submenu. The label for this pane is 
shown at the top of Example 12-6. The translation for this pane replaces all the normal trans 
lations for highlighting and notifying with a single translation for LeaveWindow events. 
These events in this widget trigger the CheckRightAndPopupSubmenu action which 
has already been described. 

The translations for the subbox widget invoke CheckLeftAndPopdownSubmenu 
action to check whether the pointer left the submenu through its left side (i.e., if it went back 
into the previous pop-up menu in the cascade). In this case, the submenu is popped down, 
but the original pop up remains visible. 

The pane that will pop up the submenu and its event handling characteristics is controlled 
from the application-defaults file. Therefore, it may seem like you can change which menu 
pane invokes the submenu simply by changing the application-defaults file. This is true here, 
because the menu actions are nonfunctional, and simply call a common callback. But it 
would not be possible if each pane invoked its own callback. To give the user the freedom to 
rearrange the menu, you would have to use actions instead of callbacks. 

Note that you can define accelerators for any of the menus shown up to this point simply by 
placing settings for the XtNaccelerators resource in the application-defaults file. You would 
set this resource for every Command widgets in the menus. This provide keyboard shortcuts 
for popping up the menu and choosing a pane. However, remember to make sure that each 
key combination is unique. 

12.2.4 Using the R4 SimpleMenu Widget 

Once you have R4, you can use a real menu widget; the R4 SimpleMenu widget. This inter 
nals of this widget and its children, which are gadgets, will be described later. This section 
describes a simple application that uses the SimpleMenu widget* 

R4 supplies three types of panes to be used with the SimpleMenu widget SmeBSB (and 
entry composed of a bitmap, a string, and another bitmap), SmeLine (a horizontal line 
between entries), and Sme (a blank entry). The SimpleMenu widget is itself a subclass of the 
pop-up shell widget, and therefore no separate pop-up shell needs to be created. 

R4 also provides a MenuButton widget, which is a subclass of Command with built-in place 
ment and pop-up code. Using a MenuButton to invoke a menu makes it even simpler to 
implement a drop-down menu, since the pop up and placement code can be eliminated from 
the application. 



*Note that if you have an R3 version of the Xt Intrinsics library, you cannot use the SimpleMenu widget even if you 
can get its code. The widget depends on changes to Xt introduced in R4. 



Menus, Gadgets, and Cascaded Pop Ups 367 



The xmenu? application shown in Example 12-7 creates a SimpleMenu widget with panes of 
all three types. The menu is invoked in drop-down style using the R4 MenuButton widget* 

As an additional enhancement, the menu marks or unmarks each item when it is selected in 
addition to calling a callback function. This iteration marks entries with the X logo, which is 
available as a standard bitmap in lusrlincludelXll /bitmaps (on UNIX systems). 

Figure 12-6 shows the appearance of the program. 



Click here for menuj 



Quit 

Show Scrollbar 
Enable Reverse Video 
Enable Bell 



Unmark 



Reply 

Forward 

Print 



Figure 12-6. xmenu?: a menu using the Athena SimpleMenu widget 



Example 12-7. xmenu?: using the SimpleMenu widget and its children 

tinclude <stdio.h> 

tinclude <Xll/Intrinsic .h> 
tinclude <Xll/StringDef s .h> 
tinclude <Xll/bitmaps/xlogol6> 

/* works under R4 and later only */ 
tinclude <Xll/Xaw/MenuButton.h> 
tinclude <Xll/Xaw/SimpleMenu .h> 
tinclude <Xll/Xaw/SmeBSB.h> 
tinclude <Xll/Xaw/SmeLine .h> 

tdefine NUM_MENU_ITEMS 12 

static String menu_entry_names [ ] = { 
"quit", 
"iteml", 
"item2", 
"item3", 
"line", 
" itemS ", 
"itemG" 



*This example was written by Chris Peterson of MIT Project Athena, and modified only slightly by the authors. 



355 



X Toolkit Intrinsics Programming Manual 



Example 12-7. xmenu?: using the SimpleMenu widget and its children (continued) 

"itemV", 
"blank", 
"menul", 
"menu2", 
"menu3", 
}; 

static Boolean status [NUM_MENU_ITEMS] ; 
static Pixmap mark; 

/* ARGSUSED */ 

static void 

MenuSelect (w, pane_num, garbage) 

Widget w; 

int pane_num; /* client_data */ 

caddr_t garbage; /* call_data */ 

{ 

Arg arglist [1]; 

Cardinal num_args =0; 

print f( "Menu item %s has been selected. \n", XtName (w) ) ; 

if (pane_num == 0) /* quit selected. */ 

exit (0) ; 

if (status [pane_num] ) 

XtSetArg(arglist [num_args] , XtNleftBitmap, None); 
else 

XtSetArg (arglist [num_args] , XtNleftBitmap, mark) ; 
num_args++; 
XtSetValues (w, arglist, num_args) ; 

status [pane_num] = ! status [pane_num] ; 

} 

void 

main(argc, argv) 

char ** argv; 

int argc; 

{ 

Widget topLevel, menu, button, entry; 

int i; 

Arg arglist [1] ; 

topLevel = Xtlnitialize (argv [0] , "XMenu7", NULL, 0, 
(unsigned int*) &argc, argv); 

button = XtCreateManagedWidget ("menuButton", 

menuButtonWidgetClass, topLevel, 

arglist, (Cardinal) 0) ; 
menu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, 

button, NULL, 0) ; 



for (i = 0; i < NUM_MENU_ITEMS ; 

String item = menu_entry_names [i] ; 

if (i == 4) /* use a line pane */ 
entry = XtCreateManagedWidget (item, 

lineMenuEntryObjectClass, menu, 



Menus, Gadgets, and Cascaded Pop Ups 369 



Example 12-7. xmenu7: using the SimpleMenu widget and its children (continued) 

NULL, 0); 
else if (i == 8) /* blank entry */ 

entry = XtCreateManagedWidget (item, 

menuEntryObjectClass, menu, NULL, 0) ; 
else { 

entry = XtCreateManagedWidget (item, 

bSBMenuEntryObjectClass, menu, NULL, 0) ; 

XtAddCallback (entry, XtNcallback, MenuSelect, 
(caddr_t) i) ; 

} 

} 

mark = XCreateBitmapFromData (XtDisplay (topLevel) , 

RootWindowOf Screen (XtScreen (topLevel) ) , 
xlogo!6_bits, xlogo!6_width, xlogo!6_height) ; 

XtRealizeWidget (topLevel) ; 
XtMainLoop ( ) ; 

} 

You will notice that each pane has a xtNle ft Bitmap resource, which is alternately set to 
the X logo or to nothing each time that item is selected. 

The application-defaults file for xmenu? is shown in Example 12-8. 

Example 12-8. XMenu7: application-defaults file 
t 

! For Color workstations only, 
t 

! Xmenu2*SimpleMenu*f oreground: SteelBlue 

! Xmenu2*SimpleMenu*menuLabel . foreground: Gold 
! Xmenu2*SimpleMenu*line . foreground: Grey 

Xmenu2*menuButton. label : Click here for menu 

Xmenu2*SimpleMenu*menuLabel .vert Space: 100 

Xmenu2*SimpleMenu*menuLabel . leftMargin: 70 

Xmenu2*SimpleMenu. label : Main Menu 

Xmenu2*SimpleMenu*quit*label : Quit this stupid demo. 

Xmenu2*SimpleMenu*RowHeight : 16 

Xmenu2* SimpleMenu* item7* sensitive: off 

Xmenu2*SimpleMenu*HorizontalMargins: 30 

! Just for fun: 

Xmenu2*menuLabel*font: -* -courier-medium-r-normal 34-*-100-100-*-*-iso8859-l 



Xmenu2*iteml*font 
Xmenu2*item2*font 
Xmenu2*item3*font 
Xmenu2*item4*f ont 
Xmenu2*item5*font 
Xmenu2*item6*font 
Xmenu2*item7*font 
Xmenu2* itemS* font 



-courier-medium-r-normal ll-*-100-100-*-*-iso8859-l 
-courier-bold-r-normal ll-*-l 00-1 00-*-*-iso885 9-1 
-courier-medium-r-normal 14-*-100-100-*-*-iso8859-l 
-courier-bold-r-normal 14-*-100-100-*-*-iso8859-l 
-courier-medium-r-normal 17-*-100-100-*-*-iso8859-l 
-courier-bold-r-normal 17-*-100-100-*-*-iso8859-l 
-courier-medium-r-normal 20-*-100-100-*-*-iso8859-l 
-courier-bold-r-normal 20-*-l 00-1 00-*-*-iso885 9-1 



370 X Toolkit Intrinsics Programming Manual 



This file simply sets various cosmetic features of the menu. (See Appendix D, Naming Con 
ventions for information on font-naming conventions.) Naturally, you could easily set the 
strings for each menu entry in this file. Note that there are no translation tables in this file 
because MenuButton and SimpleMenu are doing exactly what they were designed to do. 

Accelerators can be defined for menus with gadget children, but not in the usual sense. They 
cannot be defined to invoke the actions of the gadget children, but they can invoke global 
application actions, which for menus is usually good enough. For example, in the R4 xmh, 
one item on one of the menus incorporates new mail. From the widget, the notify action 
of the menu pane gadget calls the DolncorporateNewMail callback function. The 
xtNaccelerators resource for the SimpleMenu widget itself (not the gadgets) maps a 
Meta-I key event into a call to the XmhlncorporateNewMail global action. Xmh- 
IncorporateNewMail then calls DolncorporateNewMail. This use of accelera 
tors depends on having both a callback and an action form of each function. 



12.3 About Dialog Boxes 

Although we have been talking so far exclusively about menus, much that has been said is 
also true of dialog boxes. Both menus and dialog boxes that get user input usually need to 
get that input before other application functions can be invoked. Of course, one way to dis 
able all other application functions is to make them insensitive with xtSetSensitive 
(passing it FALSE). Setting the sensitivity of one common ancestor does the trick, but even 
this is too slow because all the widgets redraw themselves dimmed or grayed. It is much fas 
ter to use a grab. Unlike menus, which require the grab in order to get button release events 
outside the application so they can pop down properly, dialog boxes do not, strictly speaking, 
need a grab. But they usually make the grab anyway to disable other application functions. 

Dialog boxes can also invoke other dialog boxes. For example, a dialog box that gets input 
might check the validity of the input before popping down the dialog, and if incorrect, pop up 
a message telling the user the problem with the input. Cascaded dialog boxes are imple 
mented the same way as cascaded menus. Note that, as a general rule, sub-dialog boxes are 
popped up with grab mode xtGrabExclusive, which means that the user must satisfy 
the most deeply nested dialog first. 

Some pop ups do not need to disable other application functions. For example, imagine a 
dialog box that informed the user of some fact without requiring confirmation. This kind of 
pop up would be popped up with grab mode xtGrabNone, allowing the user to continue 
with other application functions. 

We pointed out earlier that the built-in callback functions for popping up a widget are not 
useful for menus because they make no passive pointer grab. However, they come in handy 
for dialog boxes. The functions xtCallbackNone, xtCallbackExclusive, and 
xtCallbackNonexclusive can be used to pop-up dialog boxes, as long as the position 
of the dialog box need not depend on information in an event 

We haven t shown how to use Xt s standard callback for popping down a widget xt- 
CallbackPopdown. Instead of calling xtPopdown in the callback functions for each 
menu entry, we can add xtCallbackPopdown to the callback list after the existing 



Menus, Gadgets, and Cascaded Pop Ups 



callback function. XtCallbackPopdown requires an XtPopdownld structure to be 
passed as the client_data argument This structure must contain the pop-up shell and 
the widget that invoked the pop up (the MenuButton or Command widget). 

All three of the standard pop-up callbacks set the invoking widget to insensitive mode before 
popping up the widget xtCallbackPopdown resets the invoking widget to sensitive 
mode. Therefore, if you use XtCallbackNone, XtCallbackNonexclusive, or 
xtCallbackExclusive, without also using XtCallbackPopdown, remember to set 
the widget to sensitive mode yourself. This feature is useless but also harmless when the pop 
up is spring-loaded, because the invoking widget is often the main application window and 
that widget rarely responds to sensitivity. 

In certain rare cases, you may want to use xtAddGrab and xtRemoveGrab directly to 
append a widget to or remove a widget from the current pop-up cascade. These functions are 
called internally by the Xt facilities that pop widgets up and down, and should not be neces 
sary on their own. Note that these functions never make a request to the server to start or 
release a passive pointer grab they affect only Xt s internal event dispatching. 



12.4 Gadgets 



When an application includes many different menus with many fields each, the overhead of 
having separate widgets for every menu pane becomes significant. Because each widget 
requires structures on the client side and windows on the server side, every widget increases 
the executable size and server memory usage. It is always a good idea to minimize the num 
ber of widgets used in your application. 

Writing a single widget that implements an entire menu, including all its panes, solves this 
problem. The widget could define subresources for configuring each pane. (The callback list 
would be one of these subresources. XtCallCallbacks could not be used to invoke 
these callbacks because it cannot distinguish between subparts. However, the callbacks can 
be called directly by looping through the callback list. This is awkward, but not too diffi 
cult) This widget would not lack flexibility if the subparts are implemented as completely 
separate code so that the types of menu panes are extensible. However, gadgets turn out to be 
a more elegant solution to the problem. 

As of Release 4, Xt provides gadgets, which are simplified widgets that do not create win 
dows. 41 Gadgets require less memory than widgets on the client side (and less disk space for 
the executable file) and consume none at all on the server side. Gadgets can be used for the 
panes of a menu, solving all of the problems just discussed. A gadget is fully configurable 
using the resource database just like a widget and can have its own callback list. 

However, the reduced consumption of gadgets does have a price. Gadgets have to draw on 
their parent s window, and they share this space with the parent and with all other gadget 
children. The gadgets and the parent must agree to draw in certain areas only. For this 



"Some versions of the R3 Intrinsics have been modified to support gadgets. One of these is the version supplied by 
OSF with early releases of the Motif widget set However, the Intrinsics as released by the X Consortium in R3 do 
not support gadgets. 



372 X Toolkit Intrinsics Programming Manual 



reason, gadgets must be used with a special composite widget parent that is prepared to man 
age them properly. 

The Release 4 SimpleMenu widget is such a parent It is a composite widget designed to 
manage gadget children. The gadgets provided by Release 4 are Sme, SmeBSB, and Sme- 
Line (where Sme stands for Simple Menu Entry). These provide a blank entry (and generic 
menu entry superclass), an entry which can contain a bitmap, a string, and another bitmap 
(thus BSB), and an entry that draws a horizontal line. We will use and describe this widget 
and these gadgets both to show how menu widgets are built and to demonstrate how the par 
ent and the gadgets work together. 

Gadgets do not handle events automatically like widgets, and because they have no windows, 
the server does not handle overlapping between them. This places certain demands on the 
parent All the gadgets that are children of a particular parent share that parent s window. 
The parent is responsible for coordinating the gadget children, telling them about events by 
calling their functions. Therefore, the composite widget that manages a group of gadgets 
must be specially designed for that purpose, not a general-purpose composite or constraint 
widget such as Box or Form. It is possible for a composite widget to manage both gadget and 
widget children, but its code has to be more involved to do this. 

Like normal widgets, gadgets provide their own code to redraw themselves in their expose 
method. However, since gadgets do not receive events, they depend on the parent to directly 
call their expose method. The parent keeps track of the geometry of each child, and when 
the parent s expose method is called, this method calculates whether the area exposed 
overlaps any of the gadget children. If the area exposed does overlap a gadget, the parent s 
expose method calls that gadget s expose method, which redraws the area. 

A gadget s actions also have to work differently from widget actions because of the fact that 
gadgets don t get events. A gadget defines its actions as methods as fields in its class part 
structure instead of in an action list and translation table. It initializes these fields directly 
to pointers to functions during class initialization. The parent widget has corresponding 
actions that are defined and operate like normal actions, except that they determine which 
gadget the event that invoked the action occurred in and call the gadget method correspond 
ing to that action. In other words, the parent has actions that operate the gadget children. 

One weakness of a menu composed of gadget panes is that gadgets cannot have an accelera 
tor table. Therefore, accelerators cannot be used to provide a keyboard equivalent that would 
invoke each menu pane. 

The parent of gadgets has to position the gadget children so that they do not overlap, or take 
care of the consequences if they do overlap. Since the gadgets draw on the parent s window, 
if they did overlap they would draw over each other s graphics, with unpredictable results. 
The parent would have to calculate the area of overlap between two gadgets, and clear this 
area before letting one of the gadgets draw itself. (A gadget could clear its own area before 
drawing, but this would be unnecessary in many cases, and would cause flashing.) 



Menus, Gadgets, and Cascaded Pop Ups 373 



Gadgets are subclasses of RectObj, one of the invisible superclasses of Core that we have so 
far ignored because for widgets it is safe to assume that Core is the top of the widget class 
hierarchy.* The actual class hierarchy leading up to Core is shown in Figure 12-7. 



Object 



RectObj 



Windo wObj 



Core 



defines callback handling 



defines geometry resources 
and sensitivity 



defines window attribute 
resources 



packages superclasses for 
inheritance by widgets 



Figure 12-7. Class hierarchy derivation of Core 

The superclasses of Core are not real classes in the sense that they do not play by all the rules 
we have described in Chapter 5, Inside a Widget. For one thing, each shares what we have 
been calling the Core class structure instead of adding its own part structure. Applications 
are never intended to create instances of these superclasses they are really just part of the 
implementation of Xt. Instead of developing all the characteristics of widgets in one large 
base class Core, it made more sense to implement Xt in object-oriented fashion by dividing 
the implementation into separate pseudo-classes. It is important to know what each early 
class defines simply so that you know what characteristics are available in gadgets and which 
are available only in widgets. Each class defines the following features: 

Object defines only the xtNdes troy Callback resource, and the underlying support 
for callbacks in general. 

RectObj defines the geometry resources (xtNx, XtNy, XtNwidth, xtNheight, and 
XtNborder_width) and the resources that control sensitivity: 



*In R3, the header files for these invisible classes are not so invisible. They were all present in lusrlinclude/Xll with 
all the other Xt header files. In R4, only the header files for RectObj are public, so that you can write and compile 
gadgets. 



374 



X Toolkit Intrinsics Programming Manual 



XtNancest or Sensitive and xtNsensitive. RectObj itself doesn t use the 
sensitivity resources. They are provided at this level in the hierarchy so that sensitivity 
can be set for gadgets. Gadgets draw themselves according to these resources (gray if 
insensitive), and check these resources in their action routines (stored in their class part 
methods), invoking their callback function only if sensitive. 

WindowObj adds many window-oriented resources: ones that control window attributes 
such as the background pixmap, permanent window features such as the window depth, 
and event resources such as translations and accelerators. It also includes the xt- 
NmappedWhenManaged resource. The WindowObj class is known as the "unnamed 
class" because it never appears in widget, gadget, or application code. Widgets are sub 
classed from Core, while gadgets are subclassed from RectObj. The exact features of 
WindowObj are subject to change and should not be relied upon. For example, a system 
vendor is allowed to move some of the characteristics of WindowObj into Core. 

The Core class structure actually is inherited all the way from RectObj. Therefore, the class 
structure in gadgets is the Core class structure you are already familiar with. All the event- 
related fields in the Core class part structure of gadgets are unused. The only exception is the 
expose method, which is present, but draws on the parent s window and is not called in the 
usual way by Xt because the gadget receives no events. The remaining non-event-related 
fields have the same purpose as for widgets, including all the remaining methods. 

Without further ado, let s take a look at a gadget, and then at a gadget parent. 

12.4.1 Inside a Gadget 

Many portions of a gadget s code are exactly the same as those of a widget, as described in 
Chapter 5, Inside a Widget. This section briefly summarizes the parts that are identical so 
that you know that nothing is left out, and describe the differences in detail. 

The code for gadgets and widgets includes the same three implementation files with the same 
naming conventions. As in Chapter 5, we ll take the three implementation files one at a time, 
beginning with the private header file, then the code file, and then the public header file. 

As in widget code, many of the conventions described here are automatically taken care of 
for you when you are writing a new gadget if you copy all three files of an existing gadget 
and then globally change the gadget class name. 

The Athena menu pane gadgets are implemented in two class levels: 

Sme (Simple Menu Entry) defines the callback for an entry, the actions to highlight, 
unhighlight, and notify, and the code that allows subclasses to inherit or replace these 
actions (because they are defined as methods). The actual functions for highlight and 
unhighlight are empty, while the notify action calls the callback. The expose method 
of this gadget is also empty. This gadget can be used by itself to create a blank entry. 

SmeBSB and SmeLine are each subclasses of Sme. SmeLine replaces only the expose 
method of its superclass. SmeBSB replaces both the expose method and the highlight 
and unhighlight actions of the superclass. (Sme can be subclassed to create new types of 
menu entries.) 



Menus, Gadgets, and Cascaded Pop Ups 375 



The following sections describe both Sme and SmeBSB. 



12.4.2 Private Header File 

The private header file for a gadget is identical in format to the private header file for a 
widget It defines a class part structure for this class of gadget, and then a complete class 
structure including the class parts of superclasses and this class. The only difference is that a 
gadget inherits its features from Object and RectObj while a widget inherits from Core. 
Example 12-9 shows the complete class structure of the R4 Athena Sme gadget. 

Example 12-9. Sme gadget: class part and complete class structure declaration 

typedef struct _SmeClassPart { 

void ("highlight) () ; 

void (*unhighlight) ( ) ; 

void (*notify) () ; 

XtPointer extension; 
} SmeClassPart; 

/* Full class record declaration */ 
typedef struct _SmeClassRec { 

RectOb jClassPart rect_class; 

SmeClassPart menu_entry_class; 
} SmeClassRec; 

tdefine XtlnheritHighlight ( (_XawEntryVoidFunc) _XtInherit) 
fdefine XtlnheritUnhighlight XtlnheritHighlight 
I! tdefine XtlnheritNotify XtlnheritHighlight 

Notice that the complete class structure declaration does not include the class part for the 
Object class, even though it is a superclass. This is because all the superclasses of Core share 
the same class part structure. 

The class part structure for Sme defines three methods these are essentially the gadget s 
actions, but they will be invoked by the gadget parent s actions, not directly by Xt. The 
extension field allows fields to be added to this structure in a future version while retain 
ing binary compatibility. In a future version this field could be changed to point to an exten 
sion structure.* 

Any class that defines methods must provide code to allow them to be inherited or replaced 
by subclasses. The Sme class therefore must define the Xt Inherit constants that allow 
the methods to be inherited. The .c code file provides the class_part_init method that 
allows them to be replaced. (See Section 11.4.5.) 

In the private header file for SmeBSB, the class part structure would contain only the exten 
sion field, because SmeBSB will be using the highlight, unhighlight, and notify fields defined 
by Sme. However, the .c file will initialize these fields to point to its own functions. 



*Note that the extension field is defined as type XtPointer. In R4, all occurrences of caddr_t have been 
replaced with XtPointer. On most systems, XtPointer will be defined to be caddr_t. But for some archi 
tectures, caddr_t is too small to hold a pointer to a function. On such systems, XtPointer will be defined to be 
larger. The caddr_t type will continue to work on most systems, but you are advised to use XtPointer instead 
for maximum portability. 



376 X Toolkit Intrinsics Programming Manual 



The instance part structure and complete instance structure of Sme are shown in Example 
12-10. 

Example 12-10. Sme gadget: instance part and complete instance structure declaration 

typedef struct { 

/* resources */ 

XtCallbackList callbacks; /* The callback list */ 
} SmePart; 

typedef struct _SmeRec { 

ObjectPart object; 

RectObjPart rectangle; 

SmePart menu_entry; 
} SmeRec; 

The SmePart adds a callbacks resource. The complete SmeRec includes the prior ele 
ments in the widget hierarchy: ObjectPart and RectObjPart. Note that unlike the 
class structure, the Object class does appear in the complete instance structure, because the 
superclasses of Core do not share instance structures. 

The instance part structure for SmeBSB includes the usual fields to maintain the graphics 
state of the entry, including the label, colors, font, GCs, and positioning information. The 
complete instance structure for SmeBSB is the same as the one for Sme but with the Sme- 
BSBPart structure added at the end. 



12.4.3 The Gadget Source File 

The source file for a gadget is identical in form to a widget source file. The only differences 
are that the superclass of a gadget in the class structure initialization is rectObjClass- 
Rec, and the complete instance structure type is called SmeOb ject for a gadget where it 
would have been SmeWidget if the entry was a true widget. Therefore, SmeOb ject is 
the type into which you cast the pointer to the instance structure before accessing the struc 
ture s fields in all the widget methods. 

In addition, several of the Core class structure fields that might be used in a widget are never 
used in gadgets. The following is the complete list of fields that are always initialized to a 
certain value in a gadget: 

realize set to NULL 

actions set to NULL 

num_a c t i o n s set to (zero) 

compress_motion set to FALSE 

compress_exposure set to FALSE 

compress_enterleave set to FALSE 

visible interest set to FALSE 



Menus, Gadgets, and Cascaded Pop Ups 



377 



resize set to NULL 

display_accelerators set to NULL 

Setting these fields otherwise (of the right type) probably won t cause the gadget to crash, but 
won t accomplish anything useful either. 

Gadgets, like widgets, should always define the query_geometry method, and either 
define set_values_almost or initialize it to xtlnheritSetValuesAlmost. The 
remainder of the fields and methods have the same purpose and are used in the same way as 
for widgets. 

There are, however, slight differences in the code for certain gadget methods. The expose 
method checks not only its own sensitivity but also its parent s sensitivity before deciding 
whether to draw the entry in normal colors or grayed. When creating GCs using XGreate- 
GC or creating any other server resources from the initialize method using an Xlib call, 
you must remember to use the parent s window, since the gadget has no window, (xt- 
window is not smart enough to give you the parent s window ID in the case of gadgets.) 
Also, the parent s resource values, such as background_pixel, may be used to provide 
data in common among all instances of a subclass like SmcBSB. 



12.4.4 The Public Header File 

The only difference in the public header file between widgets and gadgets is that what would 
have been widget for a widget is Object for a gadget. As mentioned previously, if you 
are writing a gadget you should start by copying the files for an existing gadget and then 
globally change names. Then you will start with the proper conventions already in place. 

12.4.5 The Gadget Parent 

A gadget parent is a composite widget designed to manage gadget children. Gadget parents 
perform all the geometry management tasks that all composite widgets perform, described in 
Chapter 11, Geometry Management. Gadgets also follow all the rules of normal widget chil 
dren. However, gadget parents also have the added responsibility of managing the overlap of 
gadgets or making sure they don t overlap, and of handling events for the gadgets and calling 
gadget code. This section describes the gadget-managing role of the gadget parent 

The Athena SimpleMenu widget is designed to manage the gadget children already 
described, Sme, SmeLine, and SmeBSB (and any other subclass of Sme that is written later). 
It forms a vertical menu with horizontal panes. It is quite a large widget because it contains 
all the geometry management code in addition to code for managing events for the gadgets. 
We ll concentrate just on the code that manages events for the gadgets, since the geometry 
management code is as described in Chapter 11, Geometry Management. 

Let s begin with the expose method. SimpleMenu s expose method does no drawing of 
its own. It simply calls the expose methods of the gadget children. However, it compares 
the region passed into its expose method to determine which gadgets need redrawing. 
Example 12-11 shows SimpleMenu s expose method. 



375 X Toolkit Intrinsics Programming Manual 



Example 12-11. SimpleMenu: expose method calling gadget children s expose methods 

tdefine ForAllChildren (smw, child?) \ 

for ( (childP) " (SmeObject *) (smw) ->composite .children ; \ 

(child?) < (SmeObject *) { (smw) ->composite .children + \ 
(smw) ->composite.num_children ) ; (childP)++ ) 

/* ARGSUSED */ 

static void 

Redisplay (w, event, region) 

Widget w; 

XEvent * event; 

Region region; 

{ 

SimpleMenuWidget smw =- (SimpleMenuWidget) w; 

MenuEntryOb ject * entry; 

MenuEntryOb jectClass class; 

if (region = = NULL) 
XClearWindow (XtDisplay (w) , XtWindow (w) ) ; 

/* 

* Check and Paint each of the entries - including the label. 
*/ 

ForAllChildren (smw, entry) { 

if ( IXtlsManaged ( (Widget) *entry) ) continue; 

if (region != NULL) 

switch (XRectlnRegion (region, (int) (*entry) ->rectangle .x, 
(int) (*entry) ->rectangle .y, 
(unsigned int) (*entry) ->rectangle .width, 
(unsigned int) (*entry) ->rectangle .height) ) { 
case Rectangleln: 
case RectanglePart : 

break; 
default: 

continue; 
} 
class = (MenuEntryOb jectClass) ( *entry) ->ob ject . widget_class; 

if (class->rect_class . expose != NULL) 

(class->rect_class . expose) ( (Widget) *entry, NULL, NULL) 



Note that this expose method is also called from elsewhere in the widget code (specifically, 
from the resize and geometry_manager methods) to redraw the gadgets. In these 
cases, the region passed in is set to NULL, and the method clears its window and redraws all 
the gadgets. 

Also note how this expose method invokes the expose methods of its children. All 
expose methods (and in fact all methods) are stored in the class structure, not the instance 
structure. Composite widgets keep only a list of the instance structures of their children. 
However, one field in each instance structure points to the class structure for that child. This 



Menus, Gadgets, and Cascaded Pop Dps 



is the widget_class field of the Object instance part.* In this example, the entry 
counter variable is a pointer to the gadget ID (opaque pointer to the instance structure) of one 
of the children. Another variable, class, declared as a pointer to the SmeOb jectClass 
class structure (the expected class of the children), is set to the widget_class field in the 
instance structure of one of the children. Then the expose field of this class structure is 
checked to see if it is NULL, and if not it is invoked. 

Note that the class of the children is hardcoded in this method. This widget can manage only 
Sme widgets and its subclasses. 

The resize method of SimpleMenu must resize the children when it is resized itself. 
(Actually, this is unlikely, since the SimpleMenu widget itself is a subclass of Shell and is 
therefore not managed by any parent.) This method is invoked only when the user resizes the 
menu using the window manager. Since this widget has the authority to determine the geom 
etry of its children, it can simply resize them. This particular resize method (shown in 
Example 12-12) simply sets their width to be the same as its own. 

Example 12-12. SimpleMenu: resize method 

static void 
Resize (w) 
Widget w; 
{ 

SimpleMenuWidget smw = (SimpleMenuWidget ) w; 

MenuEntryOb ject * entry; 

if ( !XtIsRealized(w) ) return; 

ForAllChildren (smw, entry) /* reset width of all entries. */ 
if (XtIsManaged( (Widget) *entry) ) 

(*entry) ->rectangle .width = smw->core .width; 

Redisplay (w, (XEvent *) NULL, (Region) NULL); 
} 

Notice that this resize method invokes the expose method (Redisplay) because the 
gadgets don t have resize methods, and will not redraw themselves in response to their 
size change.f 

Now let s look at SimpleMenu s actions. Their only purpose is to call the gadgets actions 
when the appropriate events arrive. These actions are added in the usual way: they are 
declared at the top of the .c file, then registered with an action list that is entered into the 
class structure initialization, and then defined. One of the three actions is shown in Example 
12-13. 



*The Core instance part structure (not complete) is the concatenation of the instance parts of the three superclasses 
Object, RectObj, and WindowObj. Therefore, it also includes a widget_class field. Since composite widgets 
do not normally need to invoke the methods of their children, you shouldn t need to access this field. 
fThe gadget children could have re si ze methods, and this resize method could call the children s re si ze meth 
ods. The gadget s resize methods would simply call their expose method. However, this does exactly the same 
thing as the code shown while being more complicated. 



380 X Toolkit Intrinsics Programming Manual 



Example 12-13. SimpleMenu: the Notify action routine 

/* ARGSUSED */ 

static void 

Notify(w, event, params, num_params) 

Widget w; 

XEvent * event; 

String * params; 

Cardinal * num_params; 

{ 

SimpleMenuWidget smw = (SimpleMenuWidget) w; 

MenuEntryObject entry = smw->simple_menu.entry_set; 

MenuEntryOb jectClass class; 

if ( (entry == NULL) || IXtlsSensitive ( (Widget) entry) ) return; 

class = (MenuEntryOb jectClass) entry->ob ject . widget_class; 
(class->menu_entry_class. notify) ( (Widget) entry ); 
} 

This action determines whether the chosen entry is sensitive and, if so, calls the notify 
method of that gadget. As described above in the section on the gadget children, gadgets 
define their actions as methods so that they can conveniently be called by their parent Since 
these methods are stored in the class structure not the instance structure, this is done using 
the technique described above for the expose method. 

Although not critical to its handling of gadgets, SimpleMenu does one more interesting thing. 
It registers the PositionMenuAction action in the global application action list (as 
opposed to the internal widget action list) so that the application or application-defaults file 
can refer to this action in translation tables without needing to register the action. This action 
can be triggered by any type of event in the widget and positions the menu according to data 
in the event type. (SimpleMenu has a resource that controls whether this placement process 
makes sure that the menu is not off the screen.) 

A widget can add an action to the global action list by calling xtAddAction just like an 
application would, but from its class_initialize method. 



Menus, Gadgets, and Cascaded Pop Dps 381 



13 



Miscellaneous Toolkit 
Programming Techniques 



This chapter describes various Xt functions that have not been treated else 
where in the book. 



In This Chapter: 

Errors and Warnings 385 

Macros For Getting Widget Information 388 

The Keyboard Focus and acceptjocus Method 389 

Keyboard Interpretation 391 

Memory Allocation 392 

Application Contexts 393 

Multiple Application Contexts 394 

Rewriting XtMainLoop for Multiple Application Contexts 394 

Multiple Top-level Shells 395 

Connecting to Multiple Servers 396 



13 

Miscellaneous Toolkit 
Programming Techniques 



This chapter discusses various Xt facilities that didn t fit neatly into any other chapter. Some 
of them are nonetheless quite important for accomplishing certain tasks. You should scan the 
contents of this chapter to familiarize yourself with these facilities so that you will be aware 
of them when you need them. 

The topics covered are errors and warning messages, a description of all of Xt s macros, the 
Core accept_f ocus method, how to interpret key events, and Xt s facilities for memory 
management. 



Errors and Warnings 

There are several broad categories of errors that may occur in Xt applications. One is the X 
server error, which is a form of event that tells the client that some parameter in an earlier 
request was illegal, or that no more server memory is available. A second is the connection 
failure error generated by Xlib when the connection with the server fails (usually due to a 
system crash or network interruption). Xlib provides the XSetErrorHandler and 
XSetlOErrorHandler functions to allow the application to provide a routine to handle 
these two types of errors. Xt provides no interface to these routines Toolkit applications 
must use the Xlib routines to customize these error handlers (Xlib uses default error handlers 
when the application does not use these routines to specify them). For a description of these 
error handlers and the routines for changing them, see Volume One, Xlib Programming Man 
ual. 

A third category is made up of error and warning messages that Xt reports when function 
parameters are specified improperly, when a translation is incorrectly specified, and for many 
other reasons. For a complete listing of all errors and warnings that can be generated by Xt, 
see Volume Five, X Toolkit Intrinsics Reference Manual, Appendix D, Standard Errors and 
Warnings. Xt provides separate parallel routines for errors and for warnings. The difference 
between Xt errors and Xt warnings is that errors are fatal and the application exits after print 
ing the error, while warnings are nonfatal and the application continues. The main purpose 
of these facilities is to generate consistent messages. 



Miscellaneous Toolkit Programming Techniques 385 



Two levels of interface are provided: 

A high-level interface that takes an error name and class and looks the error up in an error 
resource database. The high-level fatal error handler is invoked by a call to xtError- 
Msg or xtAppErrorMsg; the high-level nonfatal error handler is invoked by a call to 
XtWarningMsg or XtAppWarningMsg. 

A low-level interface that takes a simple string, which is printed out as the error message. 
The low-level fatal error handler is invoked by a call to xtError or xtAppError; the 
low-level nonfatal error handler is invoked by a call to xt Warning or xtApp- 
Warning. 

The high-level functions construct a string to pass to the lower-level interface. Widget or 
application code can also use Xt s error and warning reporting system. For example, when a 
resource is given an illegal value in a resource file, the widget or application can report the 
error or warning to the user (which depends on whether the widget or application can con 
tinue after the error most widgets issue only warnings and then fall back on their default 
value). Unless you are writing a widget set and therefore need to keep track of an extensive 
set of error and warning messages, you should use the low-level handlers because they are 
easier to use. To use the low-level handlers, you specify the string message as the sole argu 
ment to XtError or XtWarning. 

Contrary to what you might expect, the high-level handlers xtErrorMsg and xt- 
WarningMsg are actually harder to use than the low-level handlers. You must pass six 
arguments to the calls that generate the errors or warnings, and then to take advantage of 
their benefits you must set up an error resource database. The first three arguments are the 
name, type, and class of the error. The use of these three arguments is not yet standardized 
since they are not widely used. However, in Xt itself, the name identifies the error message, 
and the type identifies the task that was in progress when the error occurred (or the section of 
code). The class, within Xt, is always XtToolkitError. The three remaining arguments 
of XtErrorMsg and XtWarningMsg are a default message, a parameter list, and the 
number of parameters. The default message will be printed only if no matching message is 
found in the database. Because Xt does not define or install any error database, it uses these 
default messages only, and ignores the name, type, and class information. The parameter list 
is used together with the message in the database. The message may be in standard printf 
format, and the parameters are used to fill in any variable fields. 

Example 13-1 shows one of the rare cases where XtErrorMsg is invoked in the Athena 
widgets. 

Example 13-1. How to invoke XtErrorMsg (from AsciiSrc.c) 

if (src->ascii_src . string == NULL) 

XtErrorMsg ("NoFile", "asciiSourceCreate", "XawError", 

"Creating a read only disk widget and no file \ 
specified. ", 
NULL, 0); 

The error resource database is stored in a file, lusrlliblXHIXtErrorDB, under most UNIX 
operating systems. Since this database is made up of one file, you must append the resource 
settings you need to this file rather than replacing it. The resource name searched for in the 



386 X Toolkit Intrinsics Programming Manual 



database is the concatenation of the name and type arguments specified in the calls to xt- 
ErrorMsg or XtWarningMsg. 

You can redefine the routine that prints the message in order to change the fixed part of the 
message or to add features like logging of errors and warnings. Use XtSetErrorMsg- 
Handler and xtSetWarningMsgHandler (if you are using the high-level handlers) 
or XtSetErrorHandler and XtSetWarningHandler (if you are using the low- 
level handlers). See the reference pages for xtErrorMsgHandler(2) and xtError- 
Handler(2) in Volume Five, X Toolkit Intrinsics Reference Manual, for a description of 
how to define a new error or warning handler. The default error and warning messages 
printed are: 



X Toolkit Error: message. 
X Toolkit Warning: message. 



(for errors) 
(for warnings) 



Remember that Xt itself uses these messages (not just your widget code), so that they must 
remain appropriate when called from anywhere in the Xt, widget, or application code. If you 
want the message to identify the name of the widget set or widget, you must include this 
information in the part of the message filled in from the string you pass or from the resource 
database. 

Table 13-1 summarizes Xt s calls for issuing errors and warnings and for modifying the mes 
sages issued. 



Table 13-1. Xt Error and Warning Message Utilities 



Message 



Issue Error 
Issue Warning 
Set Error Handler 
Set Warning Handler 



Low Level 



XtError 

XtWarning 

XtSetErrorHandler 

XtSetWarningHandler 



High Level 



XtErrorMsg 
XtWarningMsg 
XtSetErrorMsgHandler 
XtSetWarningMsgHandler 



All eight of these calls have xt App equivalents, as described in Section 13.6. 

In other words, all the error and warning functions have application context versions with the 
same name but with App inserted after xt in their names. Note, however, that for the high- 
level routines that use the error and warning resource database, there is only one database 
common to all application contexts, at least in the sample implementation of Xt provided by 
MIT under R3 and R4. 

When writing a high-level error or warning handler you will need to call xtGetError- 
Database to get a pointer to the error resource database and xtGetErrorDatabase- 
Text to get the message for a particular set of arguments passed to XtErrorMsg or Xt 
WarningMsg. For details on how to use these functions, see the reference pages in Volume 
Five, X Toolkit Intrinsics Reference Manual. 

xtStringConversionWarning is a convenience routine to be used in resource type 
converters that convert from xtRString to a resource type not defined by Xt. It calls Xt 
WarningMsg with the appropriate arguments to issue a suitable warning. Note however, 



Miscellaneous Toolkit Programming Techniques 



387 



that the class used is xtToolkitError. It would probably be better to use a class that 
describes the widget or widget set that uses the converter. 



13.2 Macros For Getting Widget Information 

Xt provides several macros and functions for getting information about widgets. Some of 
these, such as xtlsRealized and xtlsManaged, you have seen before in the context 
of widget methods. 

Some of these are macros and some are functions, and some are macros when used in widget 
code and functions when used in application code. This does not affect how they can be 
used, so we won t bother to specify which can be both functions and macros. We will use the 
term "macro" for all of these informational routines. In Volume Five, they are listed alpha 
betically, together with all of the Intrinsics functions. 

Xt provides two macros for determining the class of a widget xtlsComposite and xt- 
is Subclass. These are primarily used internally by Xt to implement geometry manage 
ment, but you may find a use for them. For example, you might write a composite widget 
that uses XtlsComposite to treat composite children differently than simple children, or 
uses xt is Subclass to treat constraint children or one of your own classes uniquely. 

XtlsManaged you have already seen used in composite widgets. See Chapter 11, Geome 
try Management. 

You have also already seen XtlsRealized used in various methods to make sure a widget 
has a window before operations are attempted on the window. For example, the expose 
method calls XtlsRealized before drawing into the window. 

Xt is Sensitive checks the value of the XtNsensitive resource for a widget and its 
ancestors. If any of them is FALSE, it returns FALSE. Remember that sensitivity controls 
whether a widget responds to user events. 

xtHasCallbacks lets you tell whether a widget class has a callback of a certain resource 
name, and whether any callback functions have actually been added to it It returns the 
enum value XtCallbackNoList if there is no callback list, XtCallbackHasNone if 
there is a callback list with no functions on it, and xtCallbackHasSome if there is a call 
back list containing functions pointers. 

xtNameToWidget gets the widget ID for the specified widget instance name. Its primary 
use from the application is to get the IDs of the child widgets of a compound widget such as 
Dialog, so that their resources can be set directly. This is a violation of the rules of data hid 
ing however, and is not recommended. In widget code, it is used to provide a layer of 
abstraction so that widgets can be identified using string names. 

The XtNameToWidget function takes two arguments, reference and name. The 
search begins from the widget specified in the re ference argument and works down the 
hierarchy. The name argument is the instance name of the child being searched for, possibly 
with several segments. For example, for a simple hierarchy made up of a form widget as the 
parent of a box widget as the parent of a command button, the code shown in Some- 



388 X Toolkit Intrinsics Programming Manual 



Function in Example 13-2 shows the two calls that would return the IDs of the two widg 
ets. 

Example 13-2. Getting widget IDs with XtNameToWidget 

Widget form; 

main(argc, argv) 
int argc; 
char **argv; 
{ 

Widget box, button; 

/* create form */ 

box = XtCreateWidget ("box", boxWidgetClass, 
form, ) ; 

button = XtCreateWidget ("button", commandWidgetClass, 
box, ) ; 



SomeFunction ( ) 
{ 

Widget box, button; 

box = XtNameToWidget (form, "box") ; 

button = XtNameToWidget (form, "box. button") ; 



xtWindowToWidget gives you the X window ID of the window created by a widget 
This is used mainly by Xt, but you may find a use for it 



13.3 The Keyboard Focus and accept_focus Method 

The keyboard focus is the window to which the server sends keyboard events. The window 
manager controls which window this is. Under click-to-type window managers, the window 
that was most recently clicked on (usually with some keyboard key held) receives the key 
board focus. Under a real-estate-driven or pointer-following window manager, the keyboard 
focus is always the root window, and this results in keyboard events being sent to the applica 
tion (and to the individual window) the pointer is currently in. In any case, even 
click-to-type window managers set the keyboard focus only to children of the root win 
dow the application top-level windows. 

The Core class part structure includes a field for the accept_f ocus method. This method 
lets a widget set the keyboard focus to one of its children when it gets the keyboard focus. A 
typical example is an application that wants to set the keyboard focus to the text entry child 
of a dialog box whenever the dialog box is given the keyboard focus by the window manager. 



Miscellaneous Toolkit Programming Techniques 389 



This would be done so that the user can type with the pointer anywhere in the dialog widget 
instead of just with the pointer in the text entry widget. 

To implement this example, the text entry child would need an accept_f ocus method 
that would set the keyboard focus to itself using the Xlib call xSetlnputFocus, and the 
dialog box would need an accept_f ocus method that called xtCallAcceptFocus 
on the text entry widget child. The application can call XtCallAcceptFocus on the dia 
log widget in response toFocusln events to start this process, and set the focus back to 
PointerRoot on FocusOut events.* For details on these events and how to set the key 
board focus with XSetlnputFocus, see Volume Two, Xlib Reference Manual. (The 
Athena Dialog widget and Text widget do not define the appropriate accept_f ocus 
methods for this to work.) This procedure is illustrated in Figure 13-1. 



Window Manager gives keyboard 
focus to Dialog widget 



Application calls 

XtCallAcceptFocus 

on Dialog 



Application Code 



Xt calls Dialog s 

accept focus method 



Dialog accept_focus method 

calls XtCallAcceptFocus 



Xt Calls Text s accept_ 

method, which calls 

XtSetlnputFocus to set the 

keyboard focus to itself 



Xt Intrinsics 




Figure 13-1. Using XtCallAcceptFocus to set the keyboard focus to a child of a dialog widget 



*XtCal 1 AcceptFocus is not provided in MIT s version of the R3 Intrinsics. It may be present in some vendor s 
versions of R3, but this is unlikely. It is available in all versions of the R4 Intrinsics. 



390 



X Toolkit Intrinsics Programming Manual 



This procedure for giving the child of Dialog the keyboard focus is necessary because the 
application can t find out the name of the child of Dialog that should have the focus without 
breaking widget encapsulation rules. 

The accept_f ocus returns a Boolean value to report whether it succeeded in setting the 
keyboard focus, and XtCallAcceptFocus returns this same value. 

The KtSetKeyboardFocus function can be used to redirect keyboard events that occur 
anywhere within a dialog box to a child of the dialog, usually a text entry widget. (This func 
tion affects only Xt s event dispatching, and is independent of the X server keyboard focus, 
which has a similar but more widespread effect.) The Dialog widget can itself call this func 
tion instead of calling XtCallAcceptFocus. Dialog can also provide a resource or pub 
lic function to allow the application to control it 



13.4 Keyboard Interpretation 

Keyboard handling in X is designed so that you can write a program that will operate on sys 
tems with widely different physical keyboards. To accomplish this, there are several layers 
of mappings: 

The first mapping is between physical keys and keycodes (a number for each key), and 
varies between servers. A KeyPress event includes only the keycode and information 
about what other keys and buttons were being held at the time of the keypress. Programs 
that interpret keycodes directly will operate on only one type of system. 

The next mapping is between keycodes and keysyms, which are symbolic constants 
beginning with XK_ that represent the meaning of a key press. This mapping takes into 
account whether Shift or other modifier keys were being held during the press. Xlib pro 
vides the routine XLookupString that converts the keycode in a key event to the 
appropriate keysym. Portable programs use keysyms to interpret key events. The key- 
code to keysym mapping is server-wide. It can be changed, but this is normally done 
only to accomplish radical changes in the placement of keys such as changing a QWERTY 
style keyboard to DVORAK. 

The final mapping is between keysyms and strings. For printing characters, XLookup 
String also returns a string representation of the interpretation of the key pressed. For 
example, if the key marked A was pressed with no other keys held down, the string 
returned would be a. A text entry widget, for example, would append this string to the 
string being displayed, but modify the string in other ways to handle keysyms that do not 
have a string representation such as XK_Backspace. The values of keysyms are 
arranged logically so that all printing characters have a particular range. 

When you write an action that accepts key events, you will usually need to interpret the 
meaning of the key pressed. Xt provides its own interface to XLookupString: xt- 
TranslateKeycode. You pass several fields of the key event to Xt Trans late- 
Keycode, and it returns the keysym. However, xt Trans lateKeycode does not return 
the string interpretation of the key event that would be returned by XLookupString. If 
you need that string, you will have to call XLookupString. 



Miscellaneous Toolkit Programming Techniques 391 



Xt provides Xt Trans lateKeycode because Xt also provides routines for changing the 
way the translation returned by XtTranslateKeycode is done. XtSetKey- 
Translator allows you to specify your own procedure to convert from the key event 
information to a keysym. The default key event translation procedure isxtTranslate- 
Key, and so you can restore the default translator if necessary, and so that you can call it 
from your own translator to get default translations (you need to add only the code that 
makes the translations not done by the default translator). See xtKeyProc in Volume Five, 
X Toolkit Intrinsics Reference Manual, for details on providing a key event translation proce 
dure. 

Among these routines for modifying the interpretation of key events is a facility for changing 
the handling of capitalization. For example, most keyboards have the question mark (?) sym 
bol over the slash (/) symbol on one key. The standard case converter converts a press of this 
key with the Shift key held down to the XK_question keysym. In rare cases a keyboard 
may have a different symbol over / and put ? somewhere else. Also, some keyboards have 
two or more symbols on a single key, some of which are not represented at all by standard 
keysyms. The case converter handles these situations. The case converter is usually called 
from the key translator described above. To call the case converter, use XtConvertCase, 
and to change the case converter, call xtRegisterCaseConverter. See xtCase- 
Proc in Volume Five, X Toolkit Intrinsics Reference Manual, for details on writing a case 
converter procedure. 

Note that the translation manager uses these same key translation and case converter routines 
to interpret translation tables. Therefore, make sure that you add features only to them, keep 
ing existing features. 



13.5 Memory Allocation 

Xt provides routines for performing routine memory allocation and deallocation. The rou 
tines XtMalloc, XtCalloc, xtRealloc, and XtFree are equivalents of the standard 
C routines malloc, calloc, realloc, and free but they add error checking and 
reporting. The allocation routines make sure the allocation succeeded, and if it did not, they 
print a (fatal) error message. XtFree makes sure the passed pointer is not NULL before cal 
ling free. 

xt New is a macro which allocates storage for one instance of the passed type and returns a 
pointer. For example, xtNew (xtCallbackList ) allocates storage for one callback list 
structure. xtNewString is a macro that allocates storage for a string, copies the string 
into the new storage, and returns the pointer. For example, a string can be copied into new 
storage using the following: 

static String buf [ ] = "How do you do?"; 
String p; 

p = XtNewString (buf ); 

After this sequence, p points to a separate string that contains "How do you do?" Then buf 
can be changed without affecting p. 



392 X Toolkit Intrinsics Programming Manual 



13.6 Application Contexts 



The introduction to application contexts in Section 3.8 described their use in 99 percent of 
applications. As you may recall, their purpose is chiefly to attain portability to certain sys 
tems that do not provide a separate address space for each process. Xt provides parallel ver 
sions of many routines one that uses the default application context, and one that has an 
explicit application context argument To acheive the desired portability, you have to use the 
versions with the explicit argument Table 13-2 shows the complete list of routines that have 
two versions. 

Table 13-2. Xt Routines That Use Default and Explicit Application Contexts 



Default 



( registering functions ) 
XtAddActions 
XtAddConverter 
XtAddlnput 
XtTimeOut 
XtWorkProc 
(creating shells) 

XtCreateApplicationShell 
( event dispatching ) 
XtMainLoop 
XtNextEvent 
XtPeekEvent 
XtPending 
XtProcessEvent 
(error and warning messages) 
XtError 
XtErrorMsg 
XtGetErrorDat abase 
XtGetErrorDatabaseText 
XtSetErrorHandler 
XtSetErrorMsgHandler 
XtSetWarningHandler 
XtSetWarningMsgHandler 
XtWarning 
XtWarningMsg 
(selection timeouts) 
XtGet Select ionTimeout 
Xt Set Select ionTimeout 



Explicit 



XtAppAddActions 

XtAppAddConverter 

XtAppAddlnput 

XtAppTimeOut 

XtAppWorkProc 

XtAppCreateShell 

XtAppMainLoop 

XtAppNextEvent 

XtAppPeekEvent 

XtAppPending 

XtAppProcessEvent 

XtAppError 

XtAppErrorMsg 

XtAppGetErrorDat abase 

XtAppGetErrorDatabaseText 

XtAppSetErrorHandler 

XtAppSetErrorMsgHandler 

XtAppSetWarningHandler 

XtAppSetWarningMsgHandler 

XtAppWarning 

XtAppWarningMsg 

XtAppGet Select ionTimeout 
XtAppSet Select ionTimeout 



Note that XtCreateApplicationShell and XtAppCreateShell have names that 
don t follow the example set by all the rest 



Miscellaneous Toolkit Programming Techniques 



393 



Changing an application from the default application context to explicit arguments is mostly 
a matter of global changes. However, the xt initialize routine must be substituted for 
as described in Section 3.8. If you want to avoid making the application context a global 
variable, you can use the widgetToApplicationContext macro as the application 
context argument in these functions. 

13.6.1 Multiple Application Contexts 

The use of more than one application context in a single program presents possibilities that 
you might wish to explore. Having more than one application context in the same program 
allows you to have one program that when run looks like two or more independent programs. 
This approach saves disk space and memory on systems that don t provide shared libraries, 
since the grouped programs can share a single copy of the libraries. In Sun View, many of the 
basic applications were grouped in a single binary probably for this reason. The Xlib and Xt 
libraries are quite large. For example, on a Sony NWS -841 workstation, the executable 
image of a "hello, world" application written with Xt uses 300K of disk space. One of the 
most complicated existing X applications, xterm, uses 450K of disk space on this system. 
Therefore, the various libraries account for about two-thirds of the disk space used, even for a 
large program. 

Having two application contexts makes each sub-application more separate than if they were 
just under different top-level Shell widgets. Each widget has a separate action list, and each 
application context has a separate action list. When the translation manager looks for an 
action, it looks in the widget action list first, and then the application context action list. 
Therefore, each sub-application could add an action to its application context without con 
flict with another sub-application adding a different action of the same name. 

On parallel processing machines, each separate application context could run in parallel. 
However, it is difficult to write portable code to take advantage of this, since each architec 
ture has different conventions for indicating parallelisms in C code. 

13.6.2 Rewriting Xt Main Loop for Multiple Application Contexts 

To use multiple application contexts, you need to write your own equivalent of xtMain- 
Loop to dispatch events to your multiple application contexts. The available tools are xt- 
AppNextEvent, XtAppPeekEvent, XtAppPending, XtAppProcessEvent, and 
the Xlib functions XFlush and XSync. This is tricky, because you don t want to let the 
dispatching of any one application context get behind. It is not as simple as dispatching 
events from each application context in a cycle. There is little experience in how this should 
be done properly, and no examples in the distribution from MIT. However, hypothetically, 
the following describes how it could work. 

To do this properly, you have to understand how Xlib s network optimization works. Xlib 
buffers up many types of requests and sends (flushes) them to the server as a group.* A flush 



* For a detailed discussion of Xlib s network optimization and its effects, see the introduction to Volume Zero, X Pro 
tocol Reference Manual. 



394 X Toolkit Intrinsics Programming Manual 



is most commonly caused by a routine such as xtNextEvent or xt AppNextEvent that 
waits for an event if none are available. Because XtNextEvent and xt AppNextEvent 
wait forever for an event, if they were used with multiple application contexts the routine 
could get locked waiting for events in one application context while the user types frantically 
in the other. 

The answer is to use XtAppPending to determine whether an event is available on a par 
ticular application context, and then call xtAppProcessEvent if there is an event to pro 
cess. Then continue to do the same on each other application context. However, this alone is 
not enough. Neither XtAppPending nor XtAppProcessEvent called in this manner 
cause Xlib s buffer of requests to be sent to the server. Therefore, periodic calls to xsync or 
XFlush are necessary to flush the output buffer. The difficult part is to call these enough to 
flush the buffer when necessary, but not so much as to eliminate the advantages of the buffer 
ing. There is no ideal solution to this problem. 



13.7 Multiple Top-level Shells 

A single application can have more than one top-level window. In other words, you are not 
restricted to containing your application s entire user interface in a single rectangle. If you 
have one section of the application that is most appropriate as a long, thin vertical window 
that looks like a long, permanent menu, and another section that is a long, horizontal bar such 
as a ruler, each of these could be a separate top-level window. That way, not only is less 
screen space wasted than if these two windows were placed within a single rectangle, but the 
user can move the two windows around separately using the window manager. The user can 
also iconify them separately when not needed. 

To create additional top-level application shell widgets, you call xt Great e- 
ApplicationShell or xtAppCreateShell (the former uses the default application 
context, while the latter has an explicit application context argument). The class specified in 
the call should be topLevelShellWidgetClass. 

As you may know, a single server may have several screens attached. At present, all shells 
created will appear on the default screen. There is no way for the application to specify that 
a shell be created on a particular screen, but then again, doing this is usually unwise anyway 
because not many users actually have more than one screen. The user can specify which 
screen is considered the default screen using the -display command-line option. 



Miscellaneous Toolkit Programming Techniques 395 



13.8 Connecting to Multiple Servers 

One of the great features of the server-client model is that a single program can connect to 
several servers to display on the screens of several users. For example, this would allow you 
to create an X based version of the UNIX utility wall in which one user can make a message 
appear on all user s screens throughout a network. You could also create a conferencing pro 
gram in which every user has a window on their screen in which they can type and view typ 
ing by others in real time, and their typing will appear in all the other user s screens. 

The Xt application opens a connection with a server using xtOpenDisplay (this routine 
requires an explicit application context argument). Once you have opened the connection, 
you will want to create a shell widget on the server s default screen using xtCreate- 
ApplicationShell or xtAppCreateShell. Then, you create widgets for each 
server simply by using the appropriate Shell widget as parent Thereafter, xtAppMain- 
Loop dispatches events from all the connections to the appropriate widget 



396 X TooM Intrinsics Programming Manual 



A 



OPEN LOOK and Motif 



This appendix gives an overview of the widgets available in the AT&T and 
OSF/Motif widget sets. It gives a sense of the look and feel of applications 
developed with each set, and provides the inheritance hierarchy and overview 
of the available widgets. 

In This Appendix: 

The AT&T OPEN LOOK Widgets 403 

Application Controls 404 

Command Buttons 404 

Exclusive and Nonexclusive Settings 406 

Analog Controls 407 

Composite Widgets 408 

Menus and Control Areas 408 

General-purpose Composite Widgets 408 

Scrollbars and Scrollable Windows 409 

PopUps 410 

Text Widgets 413 

Drawing Areas 413 

The OSF/Motif Widgets 413 

Application Controls 416 

Command Buttons 416 

Analog Controls 417 

Composite Widgets 417 

Menus and Control Areas 417 

General Purpose Composite Widgets 420 

Scrollable Windows 421 

PopUps 422 

Text Widgets 423 

Drawing Areas 423 




This section provides an overview and comparison of the widgets in MIT s Athena widget 
set, AT&T s OPEN LOOK widget set, and the Open Software Foundation s Motif.* 

As we ve already discussed, the Athena widgets were developed to test and demonstrate the 
Xt Intrinsics. They are used as the basis for some of the standard MIT clients and many pub 
lic domain applications, but are not expected to be used for most commercial applications 
because Xaw is not a complete environment. 

A number of vendors have developed proprietary widget sets. For example, Sony Microsys 
tems offers S-windows, a widget set for its News workstation. However, given that one of 
the purposes of widgets is to provide a common look and feel for X applications, it is natural 
that there should be a shakeout as vendors align themselves with one or two major con 
tenders. 

As it has turned out, the two major contenders for a graphical user-interface standard, OPEN 
LOOK and Motif, are put forth by the two major contenders for an underlying UNIX operating 
system standard, AT&T and the Open Software Foundation. 

OPEN LOOK is somewhat unusual in that it started out not as a set of widgets, but as a user- 
interface specification. The specification, originally developed by Sun Microsystems with 
AT&T backing, was widely circulated for comment before any implementations were begun. 
The objective was to develop a graphical user-interface standard for UNIX worksta 
tions one that would be implementation-independent, and, it was hoped, implemented sep 
arately by many different vendors. 

At present, the two major implementations of OPEN LOOK are Sun s XView toolkit (which is 
not based on Xt, but instead provides an application-programmer s interface similar to Sun s 
proprietary Sun View windowing system), and AT&T s OPEN LOOK Xt-based widget set 
Both of these toolkits will be available to all AT&T UNIX System V Release 4 licensees. In 
our discussions, we are referring specifically to AT&T s OPEN LOOK toolkit, which does not 
necessarily include every OPEN LOOK feature. Nor should its implementation be considered 
the only way to provide features called for by OPEN LOOK. 



*OPEN LOOK is a registered trademark of AT&T, and Motif is a registered trademark of Open Software Foundation. 



Appendix A: OPEN LOOK and Motif 399 



The Open Software Foundation s Motif toolkit is based on a combination of widget sets orig 
inally developed by two OSF sponsors, Digital and Hewlett-Packard. The look and feel of 
the widget set was proposed by HP/Microsoft It is designed to emulate the look and feel of 
the IBM/Microsoft Presentation Manager standard widely expected to be adopted in the 
microcomputer world. 

Motifs API (Application Programmer s Interface) is based on DECWindows. Digital also 
provided Motif with some underlying enhancements to the Xt Intrinsics (most notably a form 
of windowless widgets called gadgets) and various supporting utilities. 

Table A-l compares the widgets available in Athena, AT&T OPEN LOOK set, and Motif. 

Table A-1. Comparison of Athena, OPEN LOOK, and Motif Widgets 
Simple widgets (mostly controls): 



Athena 


OPEN LOOK 


Motif 


Description 


Command 


OblongButton 


PushButton 


Invokes a command 








DrawnButton 


Invokes a command 


Toggle (R4) 


ToggleButton 


RectButton 


Chooses a setting 





CheckBox* 





Alternate way of 








choosing a setting 


MenuButton (R4) 


ButtonStack 


CascadeButton 


Invokes a menu, dis 








plays label 





AbbrevStack 





Invokes a menu, dis 








plays default 








ArrowButton 


Reverses direction of 








movement 





ScrollingList* 


List 


Displays a list of select 








able strings 


Scroll 


Scrollbar 


ScrollBar 


Scrolls through an 








associated window 





Slider 


Scale* 


Sets (or displays) an 








analog value 


Grip 








Resize point for panes 








in VPaned 


Label 


StaticText 


Label 


Displays a fixed string 


Text 


Text 


Text 


Displays editable text 





TextField 


Text 


Displays a single line 








of editable text 








Separator 


Displays a line or other 








separator 



Pop ups (subclasses of shell): 



Athena 


OPEN LOOK 


Motif 


Description 


SimpleMenu (R4) 


Menu 
Notice 


MenuShell 
DialogShell 


Parents a popup menu 
Displays a dialog 
requiring input 



400 



X Toolkit Intrinsics Programming Manual 



Table A-1. Comparison of Athena, OPEN LOOK, and Motif Widgets (continued) 



Athena 


OPEN LOOK 


Motif 


Description 





Popup Window 
Help 





Displays a more com 
plex dialog 
Displays a help win 
dow 



Composite and Constraint Widgets: 



Athena 


OPEN LOOK 


Motif 


Description 





BulletinBoard 


BulletinBoard 


Free-form placement 








area 








DrawingArea 


Free-form drawing area 


Box 








Displays children in 








order added 





ControlArea 


RowColumn 


Arranges children in 








rows or columns 


Form 


Form 


Form 


Manages children rela 








tive to each other 


__ 


Exclusives 





Makes RectButton chil 








dren exclusive 


__ 


Nonexclusives 





Makes RectButton chil 








dren nonexclusive 


^___ 


FooterPanel 





Provides a consistently- 








sized message area 


^_ 





Frame 


Gives consistent border 








to enclosed widgets 





ScrollingList* 


SelectionBox 


Provides a selectable 








list of strings, plus a 








text area for entering a 








new value 







Command 


Provides a selectable 








list of commands 




_ 


FileSelectionBox 


Provides a selectable 








list of filenames 


__ 


Caption 





Displays a label and 








one child widget 


Viewport 


Scrolling Window 


ScrolledWindow 


Displays a scrollable 








child window 






MainWindow 


ScrolledWindow with 








special appearance 


VPaned 


_ 


PanedWindow 


Displays panes resiz 








able in one direction 



*Checkbox, ScrollingList, and Scale are technically composite widgets. 



Appendix A: OPEN LOOK and Motif 



401 



Comparable widgets share a line in the table. Widgets for which no equivalent occurs in a 
given set are indicated by a hyphen in the appropriate column. Note that comparisons are 
approximate only, since widgets have complex behavior that may distinguish them signifi 
cantly from another widget with an ostensibly similar purpose. 

The following sections provide an overview of the widgets available in the OPEN LOOK and 
Motif widget sets. Throughout, we contrast them with the Athena widgets, which have been 
used as examples in this book, to give you an idea of the additional features provided by the 
commercial widget sets. 

Keep in mind that the look and feel of an application is controlled by the window manager as 
well as by the widget set. Both AT&T and OSF supply window managers to complement 
their widgets. 

Note that there may be additions to the basic X Toolkit API as well. 

In the AT&T OPEN LOOK widget set, these API additions are rather minor. There is one 
essential function, Olinitialize, which sets initial values needed by other routines, and 
by certain widgets. Olinitialize creates a base window, which from the programmer s 
point of view is identical to the Intrinsics-supplied TopLevelShell widget class, but which 
automatically handles certain features of the OPEN LOOK interface. There are also several 
convenience functions, mostly having to do with conversions between pixel sizes and various 
standard units. More importantly, there is a facility for registering help screens for each ele 
ment in an application. 

Motif has made more extensive API additions, modifying all of the base widget classes, and 
other Intrinsics features. For example, all resources are referred to by names beginning with 
xmN or xmC rather than the familiar xtN and xtc. In Chapter 12, we mentioned Motifs 
support for windowless widgets, or "gadgets." (Both MIT s Release 4 of Xt and AT&T s 
latest release of its OPEN LOOK toolkit also support gadgets.) 

In addition, Motif makes heavy use of convenience functions. Rather than using xt- 
CreateManagedWidget to create each widget, there is a separate creation routine for 
each widget. In some cases, a convenience routine creates more than one widget Rather 
than using separate calls to XtCreatePopupShell and XtCreateManagedWidget 
to create a pop-up shell and the dialog box it displays, you might call a function such as Xm- 
CreateMessageDialog to create both widgets at once. Some convenience routines cre 
ate special configurations of a single, complex widget (e.g., a composite widget with specific 
children.) 

Motif also uses call data extensively. Almost every widget has a struct defined as 
widgetclassCallbackStruct (e.g., XmToggleButtonCallbackStruct). 
This struct contains different fields for each widget, but each contains a field called rea 
son. The reason field defines which callback has been called. So using this feature 
allows you to have a single piece of code to handle all callbacks for a widget. 

In Motif s version of the Intrinsics, the search path for resources has been expanded to sup 
port language-specific resource defaults (to support internationalization of applications). 

Both Motif and OPEN LOOK offer clear advantages over Xaw. Unfortunately, however, the 
choice of which one to use may depend on company marketing goals and politics rather than 
on clear technical merit. We encourage independent developers to try both and to base your 



402 X Toolkit Intrinsics Programming Manual 



opinions on the ease of programming and the preferences of your users, rather than on mar 
keting hype by one side or the other. Eventually, there will be one common set of widgets, 
with resources to provide the appropriate look and feel (in conjunction with the window 
manager). 



A.1 The AT&T OPEN LOOK Widgets 



Figure A-l shows the overall look and feel of an OPEN LOOK application. 

title 



pane 



footer 



-L 

area 


[7j Edit - No File 







v Button J (^Menu Button v) 


Z3 

i 






-C 






z 


New Document Page One 

b 



resize corner 



vertical scrollbar 



horizontal scrollbar 



Figure A-1. An OPEN LOOK application 



The base window of an application always has these elements: 

A title bar, or header, with a title supplied by the application centered in the bar. The title 
might be the application name, or the name of a file being edited. If the application 
doesn t provide a title, the title bar displays the string "Untitled." 

A "window mark" on the left side of the title bar. If the user clicks on this mark with the 
first (leftmost) pointer button, the window closes. 

A window menu, that comes up automatically when you click on the title bar with the 
third (rightmost) pointer button. 

One or more panes for input and display of application data. 

One or more control areas, containing buttons that invoke application actions or menus 
containing additional actions. Control areas can be horizontal, vertical, or both. 



Appendix A: OPEN LOOK and Motif 



403 



Optional elements include resize corners (which allow the user to resize the application by 
dragging them with the first pointer button), horizontal and/or vertical scrollbars, and a footer 
area for displaying messages. 

Some of these elements do not correspond to widgets, but are produced by the OPEN LOOK 
window manager, olwm, as window decoration. For example, the header, including title bar, 
window mark and window menu, are provided by the window manager, as are the optional 
resize corners. However, control areas, panes, scrollbars, and the footer area do correspond 
to particular widgets. 

In addition to base windows, applications may have several kinds of pop up. Both drop 
down and pure pop-up menus are supported, as well as several standard kinds of notices and 
dialogs. Probably OPEN LOOK S best-known feature is the "pushpin" metaphor that allows 
frequently-accessed pop-up menus to be kept on the screen rather than hidden again after 
they have been used. 

The following sections discuss some of the widgets AT&T has provided to support the OPEN 
LOOK user interface. Figure A-2 shows the overall widget inheritance hierarchy. 

Note that there are a number of widgets that are never instantiated by the application pro 
grammer, but are used by other widgets. For example, the checkbox is actually a composite 
widget that manages a check widget as its child! The Pushpin used in pop ups and the Mag 
nifier used in Help windows (and the Help window itself) are examples of other widgets that 
are not instantiated directly. 

A.1.1 Application Controls 

Most applications will have at least one control area, with pointer-selectable buttons that 
invoke commands or menus, or choose settings. 

One of the areas where OPEN LOOK clearly stands out over the Athena widgets is in the rich 
set of controls it provides. Athena has one kind of Command widget; OPEN LOOK has six. 

A.1.1 .1 Command Buttons 

The Athena Command widget implements one of the most basic user-interface idioms a 
button that invokes an action when you click on it with the pointer. In R4, the Athena widg 
ets include a subclass of Command, the MenuButton widget, which includes code for placing 
a pop-up menu. 



404 X Toolkit Intrinsics Programming Manual 




Primitive * 




Stack | 


Button) 


Scrollbar 


| Slider | 


| StaticText 






T 











Button- 
Stack 



Reel- Oblong 
Button Button 



Others not instantiated by 
application programmer: 

Arrow Magnifier 
Check Pushpin 
ListPane TextPane 
Help 





Base Window 



I MenuShell I [ NoticeShell I [ PopupWindowShell 



ScrolledWindow i 



Caption 



BulletinBoard 



ControlArea 



FooterPanel 



ScrollingList 



* New in Release 2 of OpenLook Toolkit 



Figure A-2. Class inheritance hierarchy of the AT& TOPEN LOOK widgets 

The OPEN LOOK widget set implements similar functions using the OblongButton and 
ButtonStack widgets. Figure A-3 shows a Control Area containing OblongButton and 
Buttons tack widgets. 



Appendix A: OPEN LOOK and Motif 



405 



- |Vj Draui 

Line ] (Rectangle j ( Circle ) ( Fill >] 



Figure A-3. An OPEN LOOK ControlArea with OblongButton and ButtonStack widgets 

The OblongButton widget provides many niceties lacking from the Athena Command 
widget. One of the most important is that OblongButton has a resource that allows one but 
ton among several to be designated as the default, in which case it is bordered by a double 
line, to give the user immediate visual feedback about which button to choose when several 
are available. 

The OblongButton also has the notion of a "busy" state in which it cannot perform the action 
because it is already doing it. (This is different from a widget that is insensitive (meaning its 
function is unavailable), though in practice, the effect is quite similar.) The label and border 
of an insensitive button are dimmed; the background of a busy button is filled with a stippled 
pattern. 

The ButtonStack widget is similar to the OblongButton, but invokes a menu rather than a 
single command. Clicking on it with one button (usually Button 3) pops up a menu (which 
may in turn include other ButtonStack widgets, for cascading pop ups.) Clicking on it with 
another button (usually Button 1) activates the default item for the menu. Visually, a Button- 
Stack is differentiated from an OblongButton by the presence of an arrowhead, pointing in 
the direction that the menu will pop up.* 

In addition, there is an AbbrevStack widget, which performs similar functions as the Button- 
Stack widget, but shows up only as a small unlabelled box, with the default choice for the 
menu displayed beside it. 

A.1 .1 .2 Exclusive and Nonexclusive Settings 

In R3, the Athena widget set lacks the concept of a button that establishes a setting (for 
example, sets an application resource) rather than performs an action. There is nothing to 
keep the programmer from using a Command widget for this purpose, but if so, an important 
user-interface distinction fails to be made.t 

In contrast to OblongButton, which always indicates that an action will be performed, a Rect- 
Button indicates that an option setting will be chosen. This setting may be exclusive or 
nonexclusive. This is not determined by the RectButton widget itself, but depends on 
whether the widget is managed by an Exclusives or Nonexclusives composite widget. The 



*In an earlier implementation of the toolkit, a ButtonStack widget had a double border on its bottom half, giving it 
the appearance of a stack of regular buttons. Hence its name, which is now merely historical. 
fR4 Xaw adds a Toggle widget for this purpose. 



406 X Toolkit Intrinsics Programming Manual 



RectButton widget class will not work correctly unless managed by one of these two compo 
site widgets. The Exclusives and Nonexclusives widgets are themselves usually children of a 
Menu or ControlArea widget 

In an Exclusives widget, RectButton widgets are laid out side by side in one or more col 
umns. One or none of the RectButton widgets is chosen as the default, which is indicated by 
a double border. Once a RectButton is selected, it is shown with a dark border. The Exclu 
sives widget makes sure that no more than one RectButton is selected at a time. 

In a Nonexclusives widget, RectButtons are displayed with separation between each button. 
As when used in an Exclusives widget, a dark border indicates that the option has been cho 
sen. However, more than one button may be chosen at a time. 

Figure A-4 shows examples of exclusive and nonexclusive settings on menus. Note that, like 
the OblongButton, a RectButton may display a pixmap instead of a label. This makes it use 
ful for a palette in a paint program. 




( Patterns V) 




(Underline 
(Overstrike ) 



Figure A-4. OPEN LOOK RectButtons controlled by Exclusives and Nonexclusives widgets 

The CheckBox widget provides an alternate way to display nonexclusive settings to the user. 
It displays a small box next to the label, and displays a checkmark in the box when the option 
is selected. Checkboxes appear in ControlAreas, rather than on menus. Figure A-5 shows 
examples of CheckBox widgets. 









Appendix A: OPEN LOOK and Motif 



407 



Search String A 

Ignore case \ Whole word only 

Search |) f Cancel 



Figure A-5. An OPEN LOOK ChockBox widget 



A. 1.1. 3 Analog Controls 

In addition to the various kinds of buttons outlined above, OPEN LOOK provides an analog 
control called a Slider. A Slider widget is used analogously to a Scrollbar, but is used for set 
ting a numeric value. Figure A-6 shows a Slider widget 



G 







Figure A-6. An OPEN LOOK Slider widget 



A.1.2 Composite Widgets 

Composite widgets are in many ways the most important widgets in any widget set They 
define the way that widgets work together, and they give consistency to an application. 

A.1 .2.1 Menus and Control Areas 

As we ve already discussed, command buttons of any kind are usually displayed as part of a 
menu or control area. 

Menus can either pop up below a ButtonStack or an AbbrevStack, or if the button is itself 
displayed on a menu, to the right, in a menu cascade. Figure A-4 showed examples of menus. 

The Menu widget is a pop-up widget created with xtCreatePopupShell. It has a 
single child, which is a ControlArea widget 



408 



X Toolkit Intrinsics Programming Manual 



The ControlArea widget places its children in rows or columns. Resources allow the applica 
tion to specify a fixed width and/or height, or a fixed number of rows or columns. Control- 
Area widgets are usually used as the parent of OblongButton, Buttons tack, Exclusives or 
Nonexclusives widgets (which in turn manage RectButton widgets, as described in the next 
section). 

A.1 .2.2 General Purpose Composite Widgets 

We ve already discussed the Composite widgets relating to control areas and menus. How 
ever, there are several general-purpose composite widgets in the OPEN LOOK set as well. 

The BulletinBoard widget provides a free-form area for placing subwindows. Widgets can 
be placed on a BulletinBoard at arbitrary x and y coordinates; if no coordinates are specified, 
they appear in the upper left corner. The BulletinBoard provides no management of its chil 
dren, and is often used to estabish the base frame for an application, since it allows the appli 
cation programmer to place the major components of the application, rather than having to go 
by some Composite widget s arbitrary placement decisions. 

A BulletinBoard is often used as the main window of an application. 

The Form widget is a constraint widget similar to the Athena Form widget It allows the 
placement of widgets to be specified relative to each other, and with rules governing their 
separation or relative position. 

The Caption widget is like an Athena Label widget turned inside out. Like the Label widget, 
it prints a string. However, while the label widget s string is printed inside a visible widget 
border, a Caption string appears outside a bordered area. Caption is a composite widget 
class, and its label typically refers to a child widget of any size, which the Caption widget 
manages. The label can be aligned on either the right, left, top or bottom of the child widget. 

The FooterPanel widget provides a consistent method for placing a footer along the bottom 
of another window. The footer panel takes two children. The top child is typically the main 
composite widget of the application; the bottom widget may contain a control or message 
area. The basic feature of the FooterPanel widget is that when the widget is resized, it 
applies all the change in the vertical direction to the top child, maintaining the bottom child 
at a constant height 

A.1 .2.3 Scrollbars and Scrollable Windows 

OPEN LOOK scrollbars use the visual metaphor of an elevator on a cable, but functionally 
they are similar to the Athena Scroll widget The drag area (the thumb in an Athena Scroll 
widget) doesn t change size; instead, as shown in Figure A-7, there is a separate area that 
indicates the proportion of the data that is currently being displayed. 



Appendix A: OPEN LOOK and Motif 



elevator 



CD- 



CD- 



top cable anchor 
up arrow 



drag area 



down arrow 
proportion indicator 

cable 

bottom cable anchor 



Figure A-7. An OPEN LOOK Scrollbar 



Scrollbars may be oriented either horizontally or vertically. 

Scrollbars are used as a component of a ScrolledWindow widget, which, like the Athena 
Viewport widget, provides a scrollable view of a data area in a child widget. The child 
widget is typically larger than the view area, but only the area in the parent s view area can 
be seen at any one time. Figure A-l showed a ScrolledWindow widget as the main applica 
tion pane. The ScrollingList widget displays a scrollable list of editable text fields, and pro 
vides facilities for choosing and displaying one of the fields as "currently selected." Items 
can be selected from the list, changed, copied, and so on. This widget is useful for providing 
an interface to select a file for reading or writing. 

Figure A-8 shows a ScrollingList widget. 



410 



X Toolkit Intrinsics Programming Manual 



Current Item border 
surrounding Current Item 







, 


I 

Zl _ 








Appendix A 


Chapter 1 
Chapter 2 
Chapter 3 





scrollbar 



Figure A-8. An OPEN LOOK ScrollingList widget 



A. 1.3 Pop Ups 



In addition to Menu widgets, the OPEN LOOK widget set contains three other special types of 
pop-up widgets: Notices, PopupWindows, and Help windows. 

A Notice is used to request confirmation or other information from the user. The widget con 
tains a text area, where the message to the user is displayed, and a control area containing 
one or more buttons, one of which must be the default button. 

Figure A-9 shows an OPEN LOOK Notice widget 



Appendix A: OPEN LOOK and Motif 



411 



File Exists. Overwrite it? 




Figure A-9. An OPEN LOOK Notice 

A Notice grabs the pointer. The only input allowed is to the Notice. Once the user has 
clicked a button, the Notice disappears. 

The second special pop-up type is a PopupWindow, which can be used for more complex pop 
ups. Unlike a Notice, which is a subclass of OvenideShell, a PopupWindowShell is a sub 
class of WMShell, and so is decorated by the window manager. It has all the visual attributes 
of a top-level window, including resize corners, etc. In addition, it displays a pushpin in the 
upper left corner. If the user clicks on the pushpin with the pointer, the menu doesn t go 
away when its action has been performed, but stays on the screen. This allows the user to 
keep menus (and other frequently-referenced pop ups, such as help screens) "pinned" on the 
display, where they can be moved like regular windows. (Menus can also display a pushpin; 
its presence or absence is controlled by a widget resource.) 

A PopupWindow typically contains an upper control area that may include menus, and a 
lower control area that may be used for buttons invoking widget actions. Resources allow for 
automatic creation of several buttons, including a "reset to factory" button, a "set defaults" 
button, and several other ways of setting standard properties for an application. 

Figure A- 10 shows a PopupWindow. 



X Toolkit Intrinsics Programming Manual 



& Edit: Search and 


Replace 




Search For: 


Replace With: 








| Ignore Case ] 


Forward 




Backward 


I Wi Id Card Searches | 






| Wraparound Searches | 




O L2ilJ (.Replace & Search} CReplace All} 





Figure A-10. An OPEN LOOK Popup Window 

A Help window is not instantiated in the usual way. Instead, an application uses the 
OlRegisterHelp function to register help text with the toolkit. Text can be associated 
with a widget class, a widget instance, or a window. When the user clicks the second pointer 
button on an object, the Help widget is automatically displayed by the toolkit. The Help 
widget includes a Magnifier subwidget, which displays a magnifying glass containing an 
image of the part of the screen on which the user clicked the pointer. Figure A- 11 shows a 
Help window. 



{> Edit Help: Pushpin 




t^\ 


Use the pushpin to keep a pop-up window 
or a menu pinned to the workspace for 
continued access. 

Move the pointer to an unpinned pushpin and 
click SELECT to push the pin into the hole, 
pinning the window or menu to the workspace. 
Click SELECT on a pinned pushpin to pop the 
pin out of the hole and dismiss the pop-up 
window or the menu. 


P 





Figure A-11. An OPEN LOOK Help window 



Appendix A: OPEN LOOK and Motif 



413 



A. 1.4 Text Widgets 

OPEN LOOK offers three separate text widgets. The StaticText widget is similar to the 
Athena Label widget, in that it displays a fixed text string. However, it can handle longer 
strings by using wordwrapping to break the string onto multiple lines. 

The OPEN LOOK Text widget is very similar to the Athena Text widget. It provides a gen 
eral-purpose editable text widget, with editing commands customizable via a translation 
table. 

One of the great weaknesses of the Athena Text widget is that it is difficult and inefficient to 
use as a single-line editable field. (A program can add translations for the Return key to limit 
the text to a single line.) OPEN LOOK addresses this need with the TextField widget, useful 
for developing form driven applications. TextField widgets were shown in Figure A-l 1. 

The TextField widget provides simple editing commands, and scrolling if the string is too 
long to be displayed. When the keyboard focus leaves the widget, or when the Tab or Return 
key is pressed, it passes the data in the field to the application for validation. 



A. 1.5 Drawing Areas 

Like the Athena widget set, the AT&T OPEN LOOK widgets provide no widget explicitly 
labeled as a drawing area. As described in this book, one is expected either to create a cus 
tom widget for an application s main window, or to use a very basic widget class, and add 
actions for drawing. 

The AT&T OPEN LOOK widget set does include a Stub widget class (which is not docu 
mented in the manual, but is included in the source) which is useful for providing a window 
for drawing. 



A.2 The OSF/Motif Widgets 

Figure A-12 shows the general look of a Motif application, the Motif Reference Editor, mre. 
mre was developed by Mitch Trachtenberg and is OSF demo software available as part of the 
Motif distribution. 



414 X Toolkit Intrinsics Programming Manual 

























4*H 


-J 






1) 


tire 


im 

j 


PI 










File 




Edit View 


Options Heir. 


) (1 


!) 





























R 






Items 














ILJ 






* Foreground . . 


black 




A 











HWMMB 




*activeForeground 


black 












i 


N 




*activeBackground . 


. srav 












r 


V 




*topShadowColor . . 


white 












.z_ 
m 


^ 




*bottomShadowColo 


r black 




x 








3 


^ 










> ~ 








sm 

mmmmm 


1 




^J 


1 ^ 


















Selection 








































Edit 1 Add 


Delete | Help 

















































Figure A- 12. Look and f&el of a Motif application 

As with the AT&T OPEN LOOK widget set, some of the features of a main application win 
dow are actually decoration provided by the window manager, mwm. As shown in Figure 
A- 12, these include the title bar, which displays: 

The title provided by the application. 

A Menu button, which drops down a menu containing basic window manipulation com 
mands. 

A "Minimize" button, which iconifies the application. 

A "Maximize" button, which causes the application window to fill the entire screen. 



Appendix A: OPEN LOOK and Motif 



415 



You will also recognize Motifs version of many of the common controls discussed in the 
section on the AT&T OPEN LOOK widget set 

Figure A- 13 shows the inheritance hierarchy of the Motif widgets. The Intrinsics-supplied 
widget classes are shaded grey. 



1 Core 


I 


r n 


Primitive ! Cora 


)0site Shell 


| 


I i 


1 \ i 




\ Label 1 Scrollbar ] Text 


OvemdeSheil WMShell j 




MenuShelF | VeodorShell 


| List | 1 Separator ArrowButton 




1 


1 I 1 


1 1 


Drawn- Push- j Toggle- Cascade- 
Button Button jj Button Button 


TopLevelSbeil TransiemShell 


1 L 


Cons 


AppficationShell DialogShell 


rrairtt 


~Ma~r 


lager 






T "j" 


1 1 


ScrolledWindow | PanedWindow 


[ Frame [ RowColumn [ 




Scale DrawingArea BulletinBoard 






MainWindow j 


i 


Form | SelectionBox MessageBox 


_ L .- . 


j _| 


Command] j FileSelectionBox | 





Figure A- 13. Class inheritance hierarchy of the Motif widget set 

The Primitive and Manager widgets are not generally instantiated and exist only to provide 
resources and other features inherited by other widgets. 

In addition, Motif supports a Gadget class, which, as described in Chapter 12, is subclassed 
from RectObj rather than Core. Gadget equivalents exist for the Label widget, some classes 
of Button widgets, and the Separator widget Gadgets are not shown in Figure A- 13. 



416 



X Toolkit Intrinsics Programming Manual 



A.2.1 Application Controls 

Like OPEN LOOK, Motif has a much richer set of application controls than Athena. 
A.2.1 .1 Command Buttons 

Motifs PushButton is equivalent to Athena s Command widget and OPEN LOOK S Rect- 
Button. It has a 3-D appearance and seems to be depressed when clicked on. It invokes sep 
arate callbacks for button up, button down, and button click, much like the equivalent widg 
ets in other sets. 

The DrawnButton works similarly, but allows the programmer to provide a pixmap for the 
appearance of the button. 

Figure A- 14 shows a DrawnButton and a PushButton. 




Cancel 



Figure *A- 14. Motif DrawnButton and PushButton widgets 

The CascadeButton is similar in effect to OPEN LOOK S ButtonStack it can have a particu 
lar appearance that indicates that a menu is invoked, rather than a single callback. Typically, 
this is simply an arrow pointing in the direction where the menu will appear. 

A ToggleButton is used for option setting, much like OPEN LOOK S RectButton or Check- 
Box. Figure A- 15 shows a box containing a set of ToggleButtons. 

The Separator widget can be used to draw a line or other separator between a group of widg 
ets in a menu or other box. It is typically used in menus. 

The List widget displays a list of strings set by the application, and allows the user to select 
one or more of the strings. The selected data is passed to a callback function. (We ll talk 
more about this widget in the section on scrolling.) 



Appendix A: OPEN LOOK and Motif 



417 



A. 2.1 .2 Analog Controls 

Motifs Scale widget is similar to AT&T s Slider, but more powerful, since it can be used to 
display as well as to control analog values. 

A.2.2 Composite Widgets 

As with OPEN LOOK, we ve divided the discussion of Composite widgets into three areas, 
Menus and Control Areas, General-Purpose Composite Widgets, and Scrollable Windows. 
These distinctions are somewhat arbitrary, and in the case of menus, the sections overlap with 
the one on Pop ups, which appears later. 

A.2.2. 1 Menus and Control Areas 

Motif provides a special Shell widget class called MenuShell for managing pop-up menus. 
However, most actual menu displays are managed by the RowColumn composite widget, 
which, like OPEN LOOK S ControlArea, displays buttons in rows or columns. 

Through resources, the RowColumn widget can be configured to create such specialized, 
predefined elements as a MenuBar (which can only accept CascadeButton widgets as chil 
dren), several different styles of pull-down or pop-up menu panes, and several preconfigured 
control areas, such as a "Radio Box" containing multiple exclusive ToggleButton gadgets. 

Here you can begin to see the wide divergence in programming style made possible by the Xt 
Intrinsics. It is possible to create a hierarchy of relatively simple widgets to perform separate 
parts of a task, or a single, very complex widget which is highly configurable. In one of its 
incarnations, the RowColumn widget is equivalent to an OPEN LOOK ControlArea plus an 
Exclusives widget; in another, a ControlArea plus a Nonexclusives. 

In general, Motif widgets are more complex, and have many more resources, than widgets 
provided in other widget sets. To simplify their use, though, Motif provides numerous conve 
nience functions. For example, XmCreateRadioBox will create a RowColumn widget 
with one specialized set of resources, while XmCreateMenuBar will create one that is 
entirely different in appearance and function. 

Figure A- 15 shows a RowColumn widget configured as a MenuBar and Figure A- 16 shows 
one configured as a RadioBox (each with appropriate children). 



418 X Toolkit Intrinsics Programming Manual 




menu 
bar 






File 



Edit 



View 



Options 



Help (Fl) 



Figure A-15. A Motif RowColumn widget configured as a Menu Bar 





\ 
/ 


^1 Font Selection j 1 Jjl 


j 


Italics Weight Family Point Size 


\S Don t care >/ Don t care ^ Don t care >y 10 point 
^ Normal ^ Normal ^ Times ^ 12 point 
^ Oblique ^ Bold >,,/ Helvetica ^ 14 point 
^Italic N/r Eterni N/r Avant Garde v 18 point 

>, Reverse xx Book 
Italic 











-76. >4 Motif RowColumn widget configured with four Radio Boxes 



Appendix A: OPEN LOOK and Motif 



419 



Figure A- 17 shows a RowColumn widget implementing a drop-down menu. 



mre 



J 



File | 

New . . . 
Qpen . . 



View 



Options 



Help (Fl) 



A N 
A O 



Save 
Save As 
Exit . 



A S 

A A 
A E 



Figure A-17. A Motif RowColumn widget configured as a drop-down menu 

Items on Motif menus can be selected by dragging the pointer down the menu and releasing 
it when the chosen item is highlighted. Alternately, the pointer can simply be clicked on the 
menu title to drop down the menu. Clicking on an item in the menu selects it; clicking any 
where other than in the menu pops the menu down without executing any item. 

Note also that as a general feature, Motif menus support accelerators. That is, there are key 
board equivalents for every menu item. These keyboard accelerators are listed after the 
menu label, as shown above. In addition, typing the underlined letter in any menu item label 
when the pointer is in the menu will select that menu item. These are called "mnemonics." 

The items on a menu bar or menu pane simply appear as labels, but when selected, take on 
the 3-D appearance of a PushButton. 



420 



X Toolkit Intrinsics Programming Manual 



.2.2.2 General Purpose Composite Widgets 

The BulletinBoard widget provides simple composite management, allowing widgets to be 
placed arbitrarily anywhere within its confines. The only constraint is that they are not 
allowed to overlap. 

The Form widget is a subclass of BulletinBoard, that, like the widgets of the same name in 
other sets, allows children to be laid out relative to each other or to one or another of the 
sides of the Form. The children will thus always maintain their proper relative position when 
the application is resized. 

Figure A- 18 shows a fully configured Form. 



widget 

3 



widget 3 above widget 2 




widget 

2 



widget 



widget 4 

(en of 

widget 3 



widget 2 right of widget 1 







Figure A-18. A Motif Form widget and children 

The Frame widget is used simply to provide a consistent border for widgets that might not 
otherwise have one. One use is to give a RowColumn widget a border with a 3-D appear 
ance. 



Appendix A: OPEN LOOK and Motif 



421 



A.2.2.3 Scrollable Windows 

A Motif ScrollBar is illustrated in Figure A- 19. 



A 



Figure A-19. A Motif ScrollBar 

Like the Athena Scroll widget, the scrollbar has a "thumb" or slider that can be dragged up 
and down to scroll the associated window. You can also click above or below the thumb to 
move it a screenful at a time. Unlike the Athena widget, it also displays arrows at either end 
that can be used to scroll line by line. The associated window scrolls in the indicated direc 
tion as long as the pointer button is held down in one of the arrows. 

There are several different types of scrolling windows. The ScrolledWindow widget, like 
Athena s Viewport, provides a general mechanism for attaching scrollbars to some other win 
dow. 

The MainWindow widget is a subclass of ScrolledWindow with a special appearance 
reserved for application main windows. Figure A- 14 showed a MainWindow widget 

Using the XmCreateScrolledList function, a List widget can be created as a child of 
a ScrolledWindow, giving the effect of a simple scrolled list. In addition, there are several 
flavors of more complex scrolling lists. These include the SelectionBox widget, and its two 
subclasses, Command and FileS election Box. 

A general-purpose SelectionBox is akin to a ScrolledWindow/List combination, but adds a 
Text widget for entering additional data not on the list, and at least three buttons, labeled by 
default OK, Cancel and Help. 



422 



X Toolkit Intrinsics Programming Manual 



Figure A-20 shows a SelectionBox. 











Items 






*Foregroimrl black ,., .,- ,\. , 






*activeForeground black 


list box 




*activeRackgronnd , , gray 1 






*topShadowColor white 






*bottomShadowColor black / 






N" Jl ":"" * I 












^ 


scroll bars 




Selection 














box 










Edit Add Delete Help 


push 






button 









Figure A-20. A Motif SelectionBox 
/ 

A FileSelectionBox is a SelectionBox specially designed to present a list of filenames for 
selections. A Command widget is a special kind of SelectionBox whose list consists of the 
history of commands entered in the Text widget Each time a new command is entered, it is 
added to the history list. 



A.2.3 Pop Dps 



Motif defines two classes of Shell widgets: DialogShell, which is used for parenting Dialog 
boxes, and MenuShell, which is used for menus. These classes are rarely instantiated 
directly, but are instead created by convenience functions that also create their composite 
children. 

For example, functions exist to create a DialogShell with a variety of pre-configured 
MessageBox widgets as the visible child. 



Appendix A: OPEN LOOK and Motif 



423 



As we ve already discussed, a specially configured RowColumn widget is used to create a 
menu pane as the visible child of a MenuShell widget. 

A.2.4 Text Widgets 

Like Athena and the AT&T OPEN LOOK widgets, Motif provides a Text widget that supports 
a complete editing command set Like Athena, and unlike AT&T s OPEN LOOK widget set, 
both single- and multiline editing is supported by a single widget 

A.2.5 Drawing Areas 

As you may recall, to do drawing in the Athena widgets, we either created a custom widget, 
or instantiated a Core widget in order to obtain a window for drawing. The Motif Drawing- 
Area widget class answers this need in Motif. It provides a window for drawing, and very 
simple, bulletin-board like composite management of children. 

Though the name of this widget class sounds promising, you should be aware that Motif 
really provides no more sophisticated drawing capabilities than Athena or the AT&T OPEN 
LOOK widget set In each case, once you have selected the widget to draw on, you simply 
draw in its window using Xlib calls. 



424 X Toolkit Intrinsics Programming Manual 



B 



The Varargs Interfaces 



This appendix describes the WidgetWrap and R4 libraries that allow you to 
replace argument lists with resource settings placed directly in the calls that 
require them. 



In This Appendix: 

The R4 Varargs Interface 427 

XtVaTypedArg and XtVaNestedList 428 

WidgetWrap 429 



B 

The Varargs Interfaces 



As noted in Chapter 3, Other Widget Programming Techniques, there are two varargs 
libraries, one called WidgetWrap, written independently of MIT and available in R3 in the 
directory contriblwidgetslwidgetwrap , and one that is part of the Xt standard but only avail 
able starting in R4. This appendix describes both of these libraries. The description of the 
R4 interface is preliminary, since the specification is now under public review and may 
change slightly before Release 4. 



B.1 The R4 Varargs Interface 



All Xt interfaces that require ArgList arguments have analogs that conform to the ANSI C 
variable-length argument-list calling convention. The name of the analog is formed by 
inserting Va in the name of the corresponding procedure that takes an ArgList argument; 
e.g., xtVaCreateWidget is the varargs version of xtCreateWidget. Each proce 
dure named XtVa* takes as its last arguments, in place of the corresponding Arg- 
List/Cardinal parameters, a variable-length parameter list of resource name and value 
pairs where each name is of type String and each value is of type Xt ArgVal. The end of 
the list is identified by a name entry containing NULL. The ArgList and varargs forms of 
the calls can be used interchangeably. 

Table B-l presents all the varargs calls and their xtArgVal equivalents. 
Table B- 1. Varargs Calls and XtArg Val Equivalents 



Varargs Version 



XtVaCreateWidget 

XtVaAppCreateShell 

XtVaAppInitialize 

XtVaCreateManagedWidget 

XtVaCreatePopupShell 

XtVaCreatePopupShell 

XtVaGetSubresources 

XtVaGetApplicationResources 

XtVaGetValues 



XtArgVal Version 



XtCreateWidget 

XtAppCreateShell 

XtApp Initialize 

XtCreateManagedWidget 

XtCreatePopupShell 

XtCreatePopupShell 

XtGetSubresources 

XtGetApplicationResources 

XtGetValues 



Appendix B: The Varargs Interfaces 



427 



Table B-1. Varargs Calls and XtArgVal Equivalents (continued) 



Varargs Version 



XtVaGetSubvalues 

XtVaSetValues 

XtVaSetSubvalues 



XtArgVal Version 



XtGetSubvalues 
XtSetValues 
Xt Set Subva lues 



B.1.1 XtVaTypedArg and XtVaNestedList 

Two special names are defined for use only in varargs lists; XtVaTypedArg and Xt 
VaNestedList. If the name XtVaTypedArg is specified in place of a resource name, 
then the four arguments immediately following are interpreted as a name, type, value, and 
size, where name is of type String, type is of type String, value is of type XtArgVal, 
and size is of type int. When a varargs list containing XtVaTypedArg is processed, a 
resource type conversion is performed, if necessary, to convert the value into the format 
required by the associated resource. If the type is xtRString, then the value contains a 
pointer to the string and the size contains the number of bytes allocated, including the trailing 
NULL byte. If the type is not xtRString, then if the size is less than or equal to 
sizeof (XtArgVal) , the value should be the data cast to the type XtArgVal; otherwise 
the value is a pointer to the data. If the type conversion fails, for any reason, a warning mes 
sage is issued and the list entry is skipped. 

If the name XtVaNestedList is specified in place of a resource name, then the argument 
immediately following is interpreted as a pointer to another varargs list that is logically 
inserted into the original list at the point of declaration. The end of the nested list is identi 
fied with a name entry containing NULL. Varargs lists may nest to any depth. 

xtVaCreateArgsList dynamically allocates a varargs list for use with Xt 
VaNestedList in multiple calls. 

SYNOPSIS 

typedef XtPointer XtVarArgsList; 
XtVarArgsList XtVaCreateArgsList (unused, . . . ) 

ARGUMENTS 

unused This argument is not currently used and must be specified as NULL. 

. . . Specifies a variable-length parameter list of resource name and value 

pairs. 



428 X Toolkit Intrinsics Programming Manual 



DESCRIPTION 

XtVaCreateArgsList allocates memory and copies its arguments into a single list 
pointer which may be used with xtVaNestedList. The end of both lists is identified 
by a name entry containing NULL. The list may be freed using xtFree when no longer 
needed. 

Note that XtVaTypedArg is not supported for XtVaSetSubvalues. 



B.2 WidgetWrap 

The WidgetWrap library was written by Dan Heller, who can be reached at 
<island!argv@sun.com> or <dheller@ucbcory.berkeley.edu>. What follows is the summary 
documentation written by Dan in the WidgetWrap source file: 

WidgetWrap provides four interfaces: 

WidgetCreate (name, class, parent, varargs...); 
WidgetSet (name, varargs); 
WidgetGet (name, varargs) ; 
GenericWidgetName (buf ) ; 

The purpose of this module is to allow the programmer to create widgets and set/get widget 
attributes via a variable argument list style of function call. This eliminates the need for 
many local variables and bothersome xt Set Arg ( ) calls. An example of usage: 

Widget foo; 

J foo = WidgetCreate ("foo", labelWidgetClass, toplevel, 
XtNlabel, "Widget", 

XtNforeground, WhitePixelOf Screen (XtScreen (toplevel) ) , 
XtNbackground, BlackPixelOfScreen (XtScreen (toplevel) ) , 
XtNborderWidth, 1, 
NULL) ; 

As you can see, the list must be NULL terminated. You may pass up to MAXARGS argument 
pairs. Increase this number in WidgetWrap. h, if necessary. 

Special args are available to the WidgetCreate, WidgetSet, and WidgetGet func 
tions: 



Resource Names 



XtNmanaged 
XtNargList 
XtNpopupShell 
XtNapplicShell 



Decription 



Pass FALSE to create a non-managed widget 
Takes two parameters. 
Pass TRUE to create a PopupShellWidget. 
Pass TRUE to create an applicationShellWidget. 



The XtNargList makes it possible to pass attributes to the WidgetCreate, Widget- 
Set, and WidgetGet calls that are probably common to many widgets to be created or 
reset. 



Appendix B: The Varargs Interfaces 429 



static Arg args [ ] = { 

XtNforeground, black, 

XtNbackground, white, 

XtNwidth, 20, 

XtNheight, 10, 
>; 
foo = WidgetCreate ("bar", widgetClass, toplevel, 

XtNargList, args, XtNumber (args) , NULL); 

Most large applications will create huge numbers of widgets, and the programmer has to 
think up unique names for all of them. What s more, typically, as noted by the examples 

above, the names are constant strings which take up memory, disk spaces, etc So, if 

WidgetCreate () gets NULL as the name of the widget, then a widget name will be 
created automatically. Since most of the time, users don t care what the name of a widget is, 
this capability is available. 

Finally, note that there are many different implementations of varargs. To maintain portabil 
ity, it is important to never return from a function that uses varargs without calling 
va_end(). va_start() and va_end() should always exist in the same block of 
{ } s. There can be blocks between them, but va_end ( ) shouldn t be in a block inside of 
the va_start () stuff. This is to allow support for weird implementations which define 
va_start ( ) to something like: " { " (Pyramid computers, for one). Also, if you use 
varargs, never declare "known" arguments; extract them from the vararg list later. 



430 X Toolkit Intrinsics Programming Manual 



c 



Specifying Fonts and Colors 



This appendix describes the possible values for color, font, and geometry 
resource specifications. 

In This Appendix: 

Color Specification 433 

Color Names 433 

Hexadecimal Color Specification 434 

The RGB Color Model 435 

How Many Colors are Available? 436 

Font Specification 438 

Font Naming Conventions 439 

Font Name Wildcarding 441 

Font Name Aliasing 442 

Making the Server Aware of Aliases 443 

The fonts.dir Files 444 

Window Geometry 445 




This appendix describes the possible values for color, font, and geometry resource specifica 
tions. 



C.1 Color Specification 

Many clients have resources and command-line options that allow you to specify the color of 
the window background, foreground (the color that text or graphic elements will be drawn 
in), or window border. For example, the following resources might be set for a Label widget: 

. *background: orange set the background color to orange 

* foreground: black set the foreground color to black 

*borderColor : black This must be Halloween! 

The corresponding command-line options have the form: 
-bg col or sets the background color 
-fg col or sets the foreground color 
-bd col or sets the border color 

Some clients allow additional options to specify color for other elements, such as the cursor, 
highlighting, and so on. 

By default, the background is usually white and the foreground black, even on color worksta 
tions. You can specify a new color using either the names in the X Window System s color 
name database or hexadecimal values. 



C.1.1 Color Names 

The rgb.txt file, usually located in lusrlliblXll on UNIX systems, is supplied with X and con 
sists of predefined colors assigned to specific (but not necessarily intuitive) names.* 

*A corresponding compiled file called rgb.pag contains the definitions used by the server, the rgb.M file is the hu 
man-readable equivalent 



Appendix C: Specifying Fonts and Colors 



The following are the default color names that come with the X Window System. (See 
Appendix A, System Management, in Volume Three, X Window System User s Guide, for 
information on customizing color name definitions.) This file is not part of the X standard, so 
vendors are free to modify it However, most will just add to it, or redefine the values associ 
ated with each color name for better effects on their display hardware. 



aquamarine 

cadet blue 

lightsteelblue 

navyblue 

steelblue 

gold 

darkgreen 

mediumforestgreen 

seagreen 

darks lategray 

lightgray 

orange 

pink 

mediumvioletred 

sienna 

darkturquoise 

wheat 



mediumaquamarine 

cornf lowerblue 

mediumblue 

navy 

coral 

goldenrod 

darkol i vegreen 

mediumseagreen 

springgreen 

dimgrey 

khaki 

orchid 

plum 

orangered 

tan 

med i umt urquoi se 

white 



black 

darks lateblue 

mediumslateblue 

skyblue 

cyan 

mediumgoldcnrod 

forestgreen 

mediumspringgreen 

yellowgreen 

dimgray 

magenta 

darkorchid 

red 

violetred 

thistle 

violet 

yellow 



blue 

lightblue 

midnightblue 

slateblue 

firebrick 

green 

limegreen 

palegreen 

darks lategrey 

lightgrey 

maroon 

med iumor chid 

indianred 

salmon 

turquoise 

blueviolet 

greenyellow 



These names can be used directly when the specific color is wanted. 
For example, the command line: 

% xterro -bg lightblu* -f g darkslategray -bd plum & 

creates an xterm window with a background of light blue, foreground of dark slate gray, and 
border of plum. Note that the RGB values in the color database provided by MIT are correct 
for only one type of display; you may find that the color you get is not exactly what you 
expect given the name. Vendors may have corrected the RGB values to give colors closer to 
what the name implies. 

At the command line, a color name should be typed as a single word (for example, dark- 
s lategray). However, you can type the words comprising a color name separately if you 
enclose them in quotes, as in the following command line: 

% xtezm -bg "light blue" -fg "dark slata gray" -bd plum & 



C.1.2 Hexadecimal Color Specification 

You can also specify colors more exactly using a hexadecimal color string. You probably 
won t use this method unless you require a color not available by using a color name. More 
over, you shouldn t use this method unless necessary because it tends to discourage the shar 
ing of colors between applications. In order to understand how this works, you may need a 
little background on how color is implemented on most workstations. 



434 



X Toolkit Intrinsics Programming Manual 



C.1 .2.1 The RGB Color Model 

Most color displays on the market today are based on the RGB color model. Each pixel on 
the screen is actually made up of three phosphors: one red, one green, and one blue. Each of 
these three phosphors is excited by a separate electron beam. When all three phosphors are 
fully illuminated, the pixel appears white to the human eye. When all three are dark, the 
pixel appears black. When the illumination of each primary color varies, the three phosphors 
generate a subtractive color. For example, equal portions of red and green, with no admix 
ture of blue, makes yellow. 

As you might guess, the intensity of each primary color is controlled by a three-part digital 
value and it is the exact makeup of this value that the hexadecimal specification allows you 
to set 

Depending on the underlying hardware, different servers may use a larger or smaller number 
of bits (from 4 to 16 bits) to describe the intensity of each primary. To insulate you from this 
variation, clients are designed to take color values containing anywhere from 4 to 16 bits (1 
to 4 hex digits), and the server then scales them to the hardware. As a result, you can specify 
hexadecimal values in any one of the following formats: 

#RGB 
tRRGGBB 
#RRRGGGBBB 
#RRRRGGGGBBBB 

where R, G, and B represent single hexadecimal digits and determine the intensity of the red, 
green, and blue primaries that make up each color. 

When fewer than four digits are used, they represent the most significant bits of the value. 
For example, #3a6 is the same as #3000a0006000. 

What this means concretely is perhaps best illustrated by looking at the values that corre 
spond to some colors in the color name database. We ll use 8-bit values (two hexadecimal 
digits for each primary) because that is the way they are defined in the rgb.txt file: 

#000000 black 

tFCFCFC white 

#FFOOOO red 

tOOFFOO green 

tOOOOFF blue 

#FFFFOO yellow 

#OOFFFF cyan 

tFFOOFF magenta 

#5F9F9F cadet blue 

#42426F cornflower blue 

#BFD8D8 light blue 

#8F8FBC light steel blue 

#3232CC medium blue 

I23238E navy blue 

t3299CC sky blue 

#007FFF slate blue 

#236B8E steel blue 



Appendix C: Specifying Fonts and Colors 



435 



As you can see from the colors given above, pure red, green, and blue result from the corre 
sponding bits being turned full on. All primaries off yields black, while all nearly full on 
gives white. Yellow, cyan, and magenta can be created by pairing two of the other primaries 
at full intensity. The various shades of blue shown above are created by varying the intensity 
of each primary sometimes in unexpected ways. 

The bottom line here is that if you don t intimately know the physics of color, the best you 
can do is to look up existing colors from the color name database and experiment with them 
by varying one or more of the primaries till you find a color you like. Unless you need pre 
cise colors, you are probably better off using color names. 

In any event, using hexadecimal values for colors is not generally recommended, since it dis 
courages sharing of color cells. 

C.1 .2.2 How Many Colors are Available? 

The number of distinct colors available on the screen at any one time depends on the amount 
of memory available for color specification. 

A color display uses multiple bits per pixel (also referred to as multiple planes or the depth of 
the display) to select colors. Programs that draw in color use the value of these bits as a 
pointer to a lookup table called a colormap, in which each entry (or color cell) contains the 
RGB values for a particular color.* As shown in Figure C-l, any given pixel value is used as 
an index into this table for example, a pixel value of 16 will select the sixteenth colorcell. 



" There is a type of high-performance display in which pixel values are used directly to control the illumination of the 
red, green, and blue phosphors, but far more commonly, the bits per pixel are used indirectly, with the actual color 
values specified independently, as described here. 



436 X Toolkit Intrinsics Programming Manual 



Frame 
Buffer 




Colormap 

RGB 




Figure C-1. Multiple planes used to index a colormap 

This implementation explains several issues that you might encounter in working with color 
displays. 

First, the range of colors possible on the display is a function of the number of bits available 
in the colormap for RGB specification. If 8 bits are available for each primary, then the 
range of possible colors is 256 3 (somewhere over 16 million colors). This means that you 
can create incredibly precise differences between colors. 

However, the number of different colors that can be displayed on the screen at any one time 
is a function of the number of planes. A four-plane system can index 2 4 colorcells (16 dis 
tinct colors); an eight-plane system can index 2 8 colorcells (256 distinct colors); and a 
24-plane system can index 2 u colorcells (over 16 million distinct colors). 

If you are using a four-plane workstation, the fact that you can precisely define hundreds of 
different shades of blue is far less significant than the fact that you can t use them all at the 
same time. There isn t space for all of them to be stored in the colormap at one time. 

This limitation is made more significant by the fact that X is a multiclient environment. 
When X starts up, usually no colors are loaded into the colormap. As clients are invoked, 
certain of these cells are allocated. But when all of the free colorcells are used up, it is no 
longer possible to request new colors. When this happens, you will usually be given the 
closest possible color from those that have already been allocated. However, you may 
instead be given an error message and told that there are no free colorcells. 

In order to minimize the chance of running out of colorcells, many programs use "shared" 
colorcells. Shared colorcells can be used by any number of applications, but they can t be 
changed by any of them. They can be deallocated only by each application that uses them, 



Appendix C: Specifying Fonts and Colors 



437 



and when all applications have deallocated the cell, it is available for setting one again. 
Shared cells are most often used for background, border, and cursor colors. 

Alternately, some clients have to be able to change the color of graphics they have already 
drawn. This requires another kind of cell, called private, which can t be shared. A typical 
use of a private cell would be for the pallette of a color mixing application. Such a program 
might have three bars of each primary color, and a box which shows the mixed color. The 
primary bars would use shared cells, while the mixed color box would use a private cell. 

In summary, some programs define colorcells to be read-only and shareable, while others 
define colorcells to be read/write and private. 

To top it off, there are even clients that may temporarily swap in a whole private colormap of 
their own. Because of the way color is implemented, if this happens, all other applications 
will be displayed in unexpected colors. 

In order to minimize such conflicts, you should request precise colors only when necessary. 
By preference, use color names or hexadecimal specifications that you specified for other 
applications. 

For more information on color, see Chapter 7, Color, in Volume One, Xlib Programming 
Manual. 



C.2 Font Specification 

Most widgets that display text allow you to specify the font to be used in displaying text in 
the widget, via either the xtNf ont resource, or the -fn and -font command line options. 

The X Window System supports many different display fonts, with different sizes and type 
styles. (These are screen fonts and are not to be confused with printer fonts.) 

In Release 2, not many of the fonts were very good. In Release 3, Adobe Systems, Inc., and 
Digital Equipment Corporation jointly contributed five families of screen fonts (Courier, Hel 
vetica, New Century Schoolbook, Symbol and Times) in a variety of sizes, styles, and 
weights for 75 dots per inch monitors. Bitstream, Inc., contributed its Charter font family in 
the same sizes, styles, and weights for both 75 and 100 dots per inch monitors. 

Most Release 2 fonts have been moved to the user-contributed distribution 
(lusrIXl 1 r3lcontriblfonts). 

In Release 3 and later, fonts are stored in three directories: 



Directory 



lusrlliblXlllfontslmisc 

lusrlliblXlllfontsl75dpi 
lusrlliblXl 1 /fonts/ 100dpi 



Contents 



Six fixed-width fonts (also available in Release 2), 
the cursor font 

Fixed- and variable- width fonts, 75 dots per inch 
Fixed- and variable- width fonts, 100 dots per inch 



438 X Toolkit Intrinsics Programming Manual 



These three directories (in this order) comprise X s default font path. The font path can be 
changed with the/p option to the xset client, as described in Volume Three, X Window Sys 
tem User s Guide. (The font path, together with a great deal of other information about the 
server defaults, can be listed with xset query.) All fonts in the font path can be listed with 
xlsfonts, and the characters in a font can be displayed on the screen with xfd. 

The names of each font file in the font directories has a filename extension of .snf, which 
stands for server natural format. Fonts are distributed in binary distribution format (bdf), 
and may need to be adapted for a given server. 



C.2.1 Font Naming Conventions 

In Release 2, font names were determined by the names of the files in which they are stored, 
without the .snf extension. For example, the Glefg-16.snf contains the font named fg-16. 

If you do a listing of any of the Release 3 font directories, you ll notice that the filenames 
also have .snf extensions. However, Release 3 font names are not determined by the names 
of the files in which they are stored. 

As of Release 3, a font s name is determined by the contents of the font property named 
FONT* rather than the name of the file in which the font is stored. 

If you run xlsfonts, you ll get an intimidating list of names similar to the one shown in Figure 
C-2, which upon closer examination contains a great deal of useful information: 



vertical resolution in dpi 



foundry 



weight 



set width 



points (in tenths 
of a point) 



average width (in 
tenths of a pixel) 



-adobe-courier-bold-o-normal 10-100-75-75-m-60-,iso8859-l 



font family 



slant 



pixels 



spacing character set 



horizontal resolution in dpi 



Figure C-2. A Release 3 font name 






This rather verbose line is actually the name of the font stored in the file courBOlO (in the 
75dpi directory). This font name specifies the foundry (Adobe), the font family (Courier), 
weight (bold), slant (Oblique), set width (normal), size of the font in pixels (10), size of the 



*A property is a piece of information associated with a window or a font See Volume One, Xlib Programming 
Manual, for more information about properties. 



Appendix C: Specifying Fonts and Colors 



439 



font in tenths of a point (100 measured in tenths of a point, thus equals 10 points), horizon 
tal resolution (75dpi), vertical resolution (75dpi), spacing (m, for monospace), average width 
in tenths of a pixel (60 measured in tenths of a pixel, thus equals 6 pixels) and character set 
(iso8859-l). 

The meaning of many of these statistics is obvious. Some of the less obvious information is 
explained below. 

Foundry: The type foundry (in this case, Adobe) that digitized and supplied the 

font 

Set width: A value describing a font s proportionate width, according to the foun 

dry. Typical set widths include: normal, condensed, narrow, double 
width. All of the new Release 3 fonts have the set width normal. 

Pixels and points: Type is normally measured in points, a printer s unit equal to 1/72 of an 
inch. The size of a font in pixels depends on the resolution of the display 
font in pixels. For example, if the display font has 100 dots per inch (dpi) 
resolution, a 12 point font will have a pixel size of 17, while with 75 dpi 
resolution, a 12 point font will have a pixel size of 12. 



Spacing: 



Either m (monospace, i.e., fixed- width) or p (proportional, i.e., variable- 
width). 



Horizontal and vertical resolution: 

The resolution in dots per inch that a font is designed for. Horizontal and 
vertical figures are required because a screen may have different capaci 
ties for horizontal and vertical resolution. 

Average width: Mean width of all characters in the font, measured in tenths of a pixel, in 
this case 6 pixels. 

Character set ISO, the International Standards Organization, has defined character set 
standards for various languages. The iso8859-l in Figure C-2 represents 
the ISO Latin 1 character set, which is used by all of the Release 3 fonts 
in the 75dpi and 100dpi directories. The ISO Latin 1 character set is a 
superset of the standard ASCII character set, which includes various spe 
cial characters used in European languages other than English. See 
Appendix H of Volume Two, Xlib Reference Manual, for a complete list 
ing of the characters in the ISO Latin 1 character set 

This font naming convention is intended to allow for the unique naming of fonts of any style, 
resolution and size. It is powerful, but unwieldy. 

To create a label widget that displays text in the font stored in the file courBOlO, you could 
use the resource setting: 

* label: -adobe-courier-bold-o-normal--10-100-75-75-m-60-iso8859-l 

Since typing a font name of this length is neither desirable nor practical, the X Window Sys 
tem developers have provided two alternatives: wildcarding and aliasing. 



440 



X Toolkit Intrinsics Programming Manual 



C.2.2 Font Name Wildcarding 

Any unnecessary part of a font name can be "wildcarded" by specifying a question mark (?) 
for any single character, and an asterisk (*) for any group of characters. 

For example, using a wildcarded font name, the resource specification above could be writ 
ten: 

*label: *courier-bold-o-*-100* 

(Note that when using wildcards with the -fn command line option, you must take care to 
quote the font names, since the UNIX shell has special meanings for the wildcard characters * 
and ?. This can be done by enclosing the entire font name in quotes, or by escaping each 
wildcard character by typing a backslash before it.) 

If more than one font in a given directory matches a wildcarded font name, the server 
chooses the font to use. If fonts from more than one directory match the wildcarded name, 
the server will always choose a font from the directory that is earlier in the font path. Thus, if 
a wildcarded font name matches a font from both the 75dpi and 100dpi directories, and the 
75dpi directory comes first in the font path, the server chooses the font from that directory. 

In creating a wildcarded font name, you need to decide which parts of the standard font name 
must be explicit and which parts can be replaced with wildcards. As the previous example 
illustrates, you can use a single wildcard character for multiple parts of the font name. For 
instance, the final asterisk in the example stands for the sequence: 

-75-75-m-60-iso8859-l 

in the explicit font name. The idea is to specify enough parts of the font name explicitly so 
that the server gives you the font you have in mind. 

It s helpful to familiarize yourself with the available font families, weights, slants, and point 
sizes. The following list gives these statistics for the fonts in the directories 75dpi and 
100dpi in the standard X distribution from MIT.* (The fonts in the misc directory are hold 
overs from Release 2 and have short, manageable names that should not require wildcarding.) 

Font families: Charter, Courier, Helvetica, New Century Schoolbook, Symbol, Times. 

Weights: medium, bold. 

Slants: Roman (r), an upright design; 

Italic (i), an italic design slanted clockwise from vertical; 

Oblique (o), an obliqued upright design, slanted clockwise from vertical. 
Point sizes: 8, 10, 12, 14, 18, 24. 

If you re unfamiliar with the general appearance of a particular font family, try displaying 
one of the fonts with xfd, as described in Volume Three, X Window System User s Guide. 



*For fonts other than those shipped by MIT, other families, weights, slants, point sizes, etc., may apply. 



Appendix C: Specifying Fonts and Colors 44 1 



As a general rule, we suggest you type the following parts of a font name explicitly: 

Font family 

Weight 

Slant 

Point size 

Note that it s better to match the point size field, which is measured in tenths of a point (the 
100 in the previous example, equal to 10 points), than the pixel field (the 10). This allows 
your wildcarded font name to work properly with monitors of different resolutions. For 
example, say you use the following name to specify a 24 point (size), medium (weight), Italic 
(slant) Charter (family) font: 

*charter-medium-i-*-240-* 

This will match either of the following two font names (the first for 75 dpi monitors and the 
second for 100 dpi monitors): 

-bitstream-charter-medium-i-normal--25-240-75-75-p-136-iso8859-l 
-bi tstream-charter-medium-i -normal --33-2 4 0-10 0-1 00-p-136-iso8 85 9-1 

depending on which directory comes first in your font path. Specifying font size explicitly in 
pixels (25 for the first or 33 for the second) rather than in points would limit you to matching 
only one of these fonts. 

Given the complexity of font names and the rules of precedence used by the server, you 
should use wildcards carefully. 

C.2.3 Font Name Aliasing 

Another way to abbreviate font names is by aliasing that is, by associating them with alter 
native names. You can create a file (or files) called fonts. alias, in any directory in the font 
search path, to set aliases for the fonts in that directory. The X server uses bolhfonts.dir files 
(see Section C.2.5) said fonts. alias files to locate fonts in the font path. 

Be aware that when you create or edit afonts.alias file, the server does not automatically 
recognize the aliases in question. You must make the server aware of newly created or edited 
alias files by resetting the font path with xset as described in Section C.2.4. 

The, fonts. alias file has a two-column format similar to \hefonts.dir file: the first column con 
tains aliases, the second contains the actual font names. If you want to specify an alias that 
contains spaces, enclose the alias in double quotes. If you want to include double quotes or 
other special characters as part of an alias, precede each special symbol with a backslash. 

When you use an alias to specify a font in a command line, the server searches for the font 
associated with that alias in every directory in the font path. Therefore, a. fonts. alias file in 
one directory can set aliases for fonts in other directories as well. You might choose to create 
a single alias file in one directory bf the font path to set aliases for the most commonly used 
fonts in all the directories. Example C-l shows a sample fonts.alias file. 



442 X Toolkit Intrinsics Programming Manual 



Example C-1. Sample fonts.alias file 

xterm!2 -adobe-courier-medium-r-normal 12-120-75-75-m-70-iso8859-l 
xterm!4 -adobe-courier-medium-r-normal 14-140-75-75-m-90-iso8859-l 
xtermlS -adobe-courier-medium-r-normal 18-180-75-75-m-110-iso8859-l 

As the names of the aliases suggest, this sample file contains aliases for three fonts (of differ 
ent point sizes) that are easily readable in xterm windows. 

You can also use wildcards within the font names in the right hand column of an alias file. 
For instance, the alias file above might also be written: 

xterm!2 *courier-medium-r *-120* 
xterm!4 *courier-medium-r-*-140* 
xtermlS *courier-medium-r-*-180* 

Once the server is made aware of aliases, you can specify an alias in resource specifications 
or on the command line: 

xterm . font : xterm!2 
or: 

% xterm -fn xterml2 

If you are accustomed to the Release 2 font naming convention (each font name being equiv 
alent to the name of the file in which it is stored, without the .snf extension), there is a way to 
emulate this convention in Release 3 using alias files. In each directory in the font path, cre 
ate a fonts.alias file containing only the following line: 

FILE_NAMES_ALIASES 

Each filename (without the .snf extension) will then serve as an alias for the font the file con 
tains. Note that an alias file containing this line applies only to the directory in which it is 
found. To make every font name equivalent to the name of the file in which it is stored, you 
need to create a fonts.alias file such as this in every font directory. 

If you ve specified FILE_NAMES_ALIASES in an alias file, you can choose the fonts in that 
directory by means of their filenames, as we did in the resource example at the end of Chap 
ter 2, Introduction to the X Toolkit. 



Making the Server Aware of Aliases 

After you create (or update) an alias file, the server does not automatically recognize the 
aliases in question. You must make the server aware of newly created or edited alias files by 
"rehashing" the font path with xset. Enter: 

% xset fp rehash 

on the command line. The xset option.//? (font path) with the rehash argument causes the 
server to reread the fonts. dir and fonts. alias files in the current font path. You need to do this 
every time you edit an alias file. (You also need to use xset if you add or remove fonts. See 
Volume Three, X Window System User s Guide, for details.) 



Appendix C: Specifying Fonts and Colors 443 



C.2.5 The fonts.dir Files 

In addition to font files, each font dkectory contains a file called fonts.dir. The fonts.dir files 
serve, in effect, as databases for the X server. When the X server searches the directories in 
the default font path, it uses the fonts. dir files to locate the font(s) it needs. 

Each fonts. dir file contains a list of all the font files in the dkectory with their associated font 
names, in two-column form. (The first column lists the font file and the second column lists 
the actual font name associated with the file.) The first line in fonts.dir lists the number of 
entries in the file (i.e., the number of fonts in the directory). 

Example C-2 shows the fonts.dir file from the dkectory /usr/lib/Xll /fonts/1 00dpi. As the 
first line indicates, the dkectory contains 24 fonts. 

3*SS 

Example C-2. fonts.dir file in /usr/lib/X1 1 /fonts/1 00dpi 

24 

charBIOS.snf -bitstream-charter-bold-i-normal 11-80-1 00-100-p-68-iso885 9-1 
charBHO.snf -bitstream-charter-bold-i-normal 14-100-100-100-p-86-iso8859-l 
charBI12.snf -bitstream-charter-bold-i-normal 17-120-100-1 00-p-105-iso885 9-1 
charBI14.snf -bitstream-charter-bold-i-normal 19-140-100-100-p-117-iso8859-l 
charBHS.snf -bitstream-charter-bold-i-normal 25-180-100-100-p-154-iso8859-l 

II charB!24 . snf -bitstream-charter-bold-i-normal 33-240-100-100-p-203-iso8859-l 
charBOS.snf -bitstream-charter-bold-r-normal ll-80-100-100-p-69-iso8859-l 
charBlO.snf -bitstream-charter-bold-r-normal 14-100-100-100-p-88-iso8859-l 
charB!2.snf -bitstream-charter-bold-r-normal 17-120-100-100-p-107-iso8859-l 

II charB14.snf -bitstream-charter-bold-r-normal 19-140-100-100-p-119-iso8859-l 
charBlS.snf -bitstream-charter-bold-r-normal 25-180-100-100-p-157-iso8859-l 

I! charB24 . snf -bitstream-charter-bold-r-normal 33-240-100-100-p-206-iso8859-l 
charlOS.snf -bitstream-charter-medium-i -normal Il-80-100-100-p-60-iso8859-l 
charllO.snf -bitstream-charter-medium-i-normal 14-1 00-1 00-1 00-p-76-iso885 9-1 
charI12.snf -bitstream-charter-medium-i -normal 17-120-100-100-p-92-iso8859-l 
charI14.snf -bitstream-charter-medium-i-normal 19-140-100-100-p-103-iso8859-l 
charllS.snf -bitstream-charter-medium-i-normal 25-180-100-100-p-136-iso8859-l 
charI24.snf -bitstream-charter-medium-i -normal 33-240-100-100-p-179-iso8859-l 
charROS.snf -bitstream-charter-medium-r-normal 11-80-100-1 00-p-61-iso885 9-1 
charRlO.snf -bitstream-charter-medium-r-normal 14-100-100-100-p-78-iso8859-l 
charR12.snf -bitstream-charter-medium-r-normal 17-120-100-100-p-95-iso8859-l 
charR14.snf -bitstream-charter-medium-r-normal 19-140-100-100-p-106-iso8859-l 
charRlS.snf -bitstream-charter-medium-r-normal 25-180-100-100-p-139-iso8859-l 
charR24 . snf -bitstream-charter-medium-r-normal 33-240-100-100-p-183-iso8859-l 

The fonts. dir files are created by the mkfontdir client when X is installed, mkfontdir reads the 
font files in directories in the font path, extracts the font names, and creates a fonts.dir file in 
each dkectory. If fonts. dir files are present on your system, you probably won t have to deal 
with them, or with mkfontdir, at all. If the files are not present, or if you have to load new 
fonts or remove existing ones, you will have to create files with mkfontdir. Refer to Volume 
Three, X Window System User s Guide, for details. 



444 X Toolkit Intrinsics Programming Manual 



C.3 Window Geometry 



All clients that display in a window take a geometry option that specifies the size and loca 
tion of the client window.* The syntax of the geometry option is: 

-geometry geometry 

The -geometry option can be (and often is) abbreviated to -g, unless there is a conflicting 
option that begins with g. 

The corresponding resource is XtNGeometry, which can be set in a resource file as fol 
lows: 

*mywidget . geometry : geometry _str ing 

The argument to the geometry option (geometry), referred to as a "standard geometry 
string," has the form: 

wi dthxhei gh txoffyoff 

The variables, width and height, are values in pixels for many clients. However, appli 
cation developers are encouraged to use units that are meaningful to the application. For 
example, xterm uses columns and rows of text as width and height values in the xterm win 
dow, xoff (x offset), and yoff (y offset) are always in pixels. 

You can specify any or all elements of the geometry string. Incomplete geometry specifica 
tions are compared to the resource manager defaults and missing elements are supplied by 
the values specified there. If no default is specified there, and uwm is running, the window 
manager will require you to place the window interactively. 

The values for the jc and y offsets have the following effects: 
Table C-1. Geometry Specification: x andy Offsets 



Offset Variables 



Description 



+xoff 
+yoff 
-xoff 
-yoff 



A positive x offset specifies the distance that the left edge of the win 
dow is offset from the left side of the display. 

A positive y offset specifies the distance that the top edge of the win 
dow is offset from the top of the display. 

A negative x offset specifies the distance that the right edge of the win 
dow is offset from the right side of the display. 

A negative y offset specifies the distance that the bottom edge of the 
window is offset from the bottom of the display. 



*For compatibility with Release 2, the alternative syntax: 

= geometry 
is still supported for Release 3. This syntax will not be supported in future releases, however. 



Appendix C: Specifying Fonts and Colors 



445 



For example, the command line: 

% xclock -geometry 125x125-10+10 t 

places a clock 125x125 pixels in the upper-right corner of the display, 10 pixels from both 
the top and the right edge of the screen. 

For xterm, the size of the window is measured in characters and lines. (80 characters wide by 
24 lines long is the default terminal size.) If you wanted to use the vtlOO window in 132-col- 
umn mode, with 40 lines displayed at a time, you could use the following geometry options: 

% xterm -geometry 132x40-10+350 & 

This will place an xterm window 132 characters wide by 40 lines long in the lower-right cor 
ner, 10 pixels from the right edge of the screen and 350 pixels from the top of the screen. 

Some clients may allow you to specify geometry strings for the size and position of the icon 
or an alternate window. In Release 2, this could be done using command line options.* As 
of Release 3, command line options for setting the geometry of an icon or an alternative win 
dow are supported only for compatibility with older versions of X. (These options will not be 
supported in future releases.) However, several Release 3 clients, including xterm, allow you 
to set the size and position of the icon or alternative window using resource variables (in an 
Xdefaults or other resource file). See the appropriate client reference pages in Part Three of 
Volume Three, X Window System User s Guide, for a complete list of available resources. 

You should be aware that, as with all user preferences, you may not always get exactly what 
you ask for. Clients are designed to work with a window manager, which may have its own 
rules for window or icon size and placement However, priority is always given to specific 
user requests, so you won t often be surprised. 



*The Release 2 version of xterm takes a geometry string beginning with % rather than = as the geometry for the Tek 
tronix window, and one beginning with # as the geometry for the icon. Neither of these options requires a preceding 
-geometry or -g. 



446 X Toolkit Intrinsics Programming Manual 



D 



Naming Conventions 



777/s appendix describes a suggested set of conventions for naming widgets, 
and elements within widget code. 



Naming Conventions 



This appendix proposes a set of conventions for naming certain elements of widget code.* If 
the naming conventions used in all widget sets are consistent, there will be several benefits: 

It will be much easier for programmers to move from toolkit to toolkit without needing to 
constantly refer to manuals to figure out how to properly name various items. 

It will be easier to mix widgets from different widgets sets in one application. 

It will make it possible for automatic code generators to work with lots of widgets with 
out making special modifications for any toolkit. 

These conventions are common between the OPEN LOOK and Motif widget sets with a few 
minor differences. However, the Athena widget set currently does not follow the conven 
tions described. 

It is important to note that these suggestions are in no way blessed (or damned) by the X 
Consortium they are simply a guideline that we suggest you follow in the interests of pro 
moting the benefits listed above. We will use Motif as an example. 

A toolkit uses a special prefix with all its widgets. In the case of Motif, this prefix is m. 
Using that prefix and a hypothetical Label widget as an example, the conventions are as fol 
lows: 



Toolkit library name 
Widget class name 
Include directives 

class_name field in 
the core structure 

Enumerated resource values 
Public function names 



libXm.a 
XmLabel 
<Xm/Label.h> 
Label 

XmC AP I T AL I Z ED_WORD S 
XmLabelFunctionName ( ) 



*This appendix is based on a comp. windows x netwoik news posting by Gene Dykes of Cornell University. 



Appendix D: Naming Conventions 



449 



Truncated include file names 



Strip the lower case letters a word at a time until the 
basename is nine characters or fewer (but strip as few 
letters as possible from the initial word). Thus: 

<Xm/VeryLongWidgetName . h> 
becomes: 



<Xm/VeryLWN.h> 



but 



Macro names for preprocessor 
in include files 



<Xm/Verylongwidgetname . h> 
becomes: 

<Xm/Verylongw . h> 

(Note difference in VeryLong (two words) and Very- 
long (one word).) 

#ifndef XM_LABEL_H 

This is to prevent header files from being included more 
than once. 

If a widget has a corresponding gadget, then Gadget is 
appended to the widget name, so XmLabelGadget is 
the gadget class name. 

xmLabelWidgetClass 
xmLabelGadgetClass 

Widget XmCreateLabel (parent, name, 
arglist, argcount) 

This is a shortcut to using XtCreateWidget. How 
ever, in the case of top-level widgets (menus, dialogs, 
Main Window), it also creates the shell widget and creates 
the requested widget within it 

The special Create functions can also be used as conve 
nience routines for specialized widget instances. For 
example, XmCreateWorkingDialog and Xm- 
CreateWarningDialog actually create a Message- 
Box whose XmDialogType resources are respectively 
XmDIALOG_WARNING and XmDIALOG_WORKING. 

OPEN LOOK uses conventions similar to Motif, but leaves the prefixes off the widget class 
name. We recommend that you supply a prefix for any widgets you write, especially if there 
is any chance that some other widget set may use the same class name. In other words, if we 
wrote a new Label widget, we might call it OraLabcl, not just Label, so that we could still use 
the Athena Label widget in the same application. 



Widget class pointer 
Gadget class pointer 

Create function for widgets 
or gadgets 



450 



X Toolkit Intrinsics Programming Manual 



E 



Converting Widgets from 
Xll Release 2 to Xll Release 3 



This appendix summarizes the changes between Release 2 and Release 3 of 
the X Toolkit, as it applies to converting widgets and applications. 

In This Appendix: 

New Core Fields 454 

The Display Accelerator Method 454 

The Extension Pointer 454 

Obsolete Composite Fields 454 

Auditing Data Types 455 

Name Change to Misc.h Header File 455 

Interface Change to accept_focus Method 456 

Data Change to set_values Method 456 

New Geometry Request Mode 456 

Translation Table Syntax 457 

Resource Name and Class Qualifiers 457 

Bug Fix to XtGetValues 458 

Changes to Shell Defaults 458 

XtAddlnput and XtAddTimeout 458 



Converting Widgets from 
X1 1 Release 2 to X11 Release 3 



In the majority of cases, Xt applications correctly written for Release 2 will be source com 
patible with the Release 3 Xt; however, some source changes are necessary to widget imple 
mentations to accommodate the new interfaces. This document summarizes the changes 
required to update a widget that correctly functions under the Release 2 library to do the 
same under the Release 3 library.* 

Release 3 of the X Window System Version 1 1 includes the first version of the Xt Intrinsics 
that have been approved and adopted as part of the core X standard by the MIT X Consor 
tium. From the viewpoint of an applications programmer, the Release 3 library is upward 
compatible with the library distributed with XI 1 Release 2 with two small exceptions, listed 
in the last four sections of this document Of course, many bugs have been fixed in the 
Release 3 implementation, and it is entirely possible that an application that appeared to 
work was actually leaning against such a bug and will now fall over. 

The changes listed here are by no means a complete listing of all the additions that have been 
made to the Intrinsics in Release 3. Only the changes that require source modifications to 
widgets and (possibly) to applications are described. 

Some new core fields and some small changes to old methods will require attention in the 
source code of any widgets written to the Release 2 specification. The following sections 
outline the new core methods, some obsolete composite methods, and some changes to exist 
ing methods. 









*This appendix is an edited version of an appendix of the Xt specification by Ralph R. Swick. 



Appendix E: Converting Widgets from X1 1 Release 2toX11 Release 3 453 



E.1 New Core Fields 

Two new fields have been added to the end of the CoreClassPart structure to allow 
composite widgets to attach event translation bindings to their descendants and to allow for 
future updates to Co re Class. Revised Release 2 widgets can initialize both of these new 
fields to NULL. If the structure initialization followed the template used by the Athena wid 
gets in R2, the C compiler will do this initialization automatically and source code modifica 
tions are not strictly required. 

E.1.1 The Display Accelerator Method 

Xt now supports input accelerators. Accelerators are translation bindings attached to one 
widget that invoke actions in a different widget, usually a parent 

The display_accelerator method is called by the XtlnstallAccelerators 
procedure to notify the widget owning the accelerator table (i.e. the widget in which the 
actions will be dispatched) that its accelerators have been added to the event bindings of 
some other target widget 

Widgets that do not define accelerator tables should initialize the display_accelera- 
tor field to XtlnheritDisplayAccelerator. 



E.1 .2 The Extension Pointer 

In order to allow for future expansion of the CoreClassPart structure and maintain 
binary compatibility with then-existing widget libraries, an extension field has been added 
after the display_accelerators field. This field should be initialized to NULL. 



E.2 Obsolete Composite Fields 

Two methods have been removed from the CompositeClassPart structure. Any wid 
gets that are subclasses of Composite must be modified to remove the initialization for 
these two fields before the widget can be re-compiled. 

The methods move_f ocus_to_next and move_f ocus_to_prev were deemed to be 
insufficient for many desired styles of focus management and were therefore removed. If a 
widget library desires to implement class move_f ocus methods, it should declare a sub 
class of Compos iteWidget Class and add the appropriate focus management methods 
in the subclass. 

The num_mapped_children field has been removed from the CompositePart struc 
ture. This field is no longer used internally by the Intrinsics and widgets that used it them 
selves were probably using it incorrectly. 



454 X Toolkit Intrinsics Programming Manual 



A new field, extension, was added to the end of CompositeClassPart to allow for 
future growth. It should have the value NULL. 

Note that Constraint is a subclass of Composite and therefore these changes apply to all Con 
straint widgets. 



E.3 Auditing Data Types 

The data types Dimension and Position are defined for the fields core. width, 
core. height, core.border_width, and core.x and core.y, respectively. 
Many other fields in specific widgets are appropriately defined as either Dimension, or 
Position. A common programming error in Release 2 was to misdeclare some or all of 
these fields as int, either in a structure declaration, or more subtly in the size field in a 
resource list.* 

In Release 3, it is critical that fields be consistently declared as either int, Dimension, or 
Position. Good compilers, lint, and other similar tools will catch some programming 
errors but cannot check resource lists. Unpredictable run-time errors will result from fields 
that have been misdeclared. 

In addition to auditing all resource lists, all calls to xtMakeResizeRequest in widgets 
should be checked to make sure the return value pointers are of type Dimension* and all 
uses of XtGetValues in both widgets and applications should be checked to insure that 
the pointers used in the argument lists reflect the correct data type for the resource being 
retrieved. 



E.4 Name Change to Misc.h Header File 

The header file <XlllMisc.h> exported by the Athena widgets has been renamed 
<XlllXawMisc.h>. Any widgets or applications that used it will need to refer to the new 
name. 



*This error was exacerbated by the Athena Widget documentation and header files which misdeclared these fields as 
int. 



Appendix E: Converting Widgets from X1 1 Release 2toX11 Release 3 455 



E.5 Interface Change to accepMocus Method 

An additional parameter and a return value have been added to the accept_focus 
method. The new parameter indicates the X time of the event that caused the method to be 
invoked, so that the method can correctly conform to the ICCCM. The accept_f ocus 
method must also return a Boolean value indicating whether or not the widget actually 
wanted the keyboard focus. 



E.6 Data Change to set_values Method 

It is frequently the case that a widget will need to make some request of its parent from 
within its set_values method. In Release 2, the widget data structure was not updated to 
reflect the new resource values until after all class set_values methods had been called. 
In this case, the parent was unable to perform any processing that depended upon the new 
state of the child. 

In Release 3, the widget data structure is updated with the new resource values before calling 
the class set_yalues methods. A copy is made of the widget record before the changes 
are installed. The definition of the arguments to the set_values method has been 
changed so that the "old" argument now points to the copy of the original widget and the 
"new" argument points to the actual widget record. Most simple set_values methods 
will not need any changes to work properly with this swap, but methods which made geome 
try requests or other changes that formerly required use of the "old" widget must be modi 
fied to use the "new" argument instead. 

The set_yalues method must not assume that the current geometry (i.e., the "new" one) 
is the one they will actually get, as the parent s Geometry Manager has not yet been called. A 
reasonable strategy for widgets that need to perform some set_values computation based 
upon their geometry is to use the old geometry and rely solely upon their resize method to 
notify them of any changes after set_values has been called. 



E.7 New Geometry Request Mode 

In order to accommodate some geometry layout semantics that may require a parent to 
respond accurately with XtGeometryAlmost but simultaneously propagate a geometry 
request up the tree, a new option has been added to the values permitted in the 
request_mode field of an XtGeometryRequest. 

If a Composite widget geometry_manager method finds the xtCWQueryOnly flag set 
in the request_mode, it is expected to respond to the query in the normal way but not to 
actually make any changes to its own geometry or the geometry of any of its children. The 
Composite widget can expect that the child will repeat the request without the xt- 
CWQueryOnly flag and may cache any layout state required to quickly re-compute the new 
geometry. 



456 X Toolkit Intrinsics Programming Manual 



E.8 Translation Table Syntax 

Several additions have been made to the syntax permitted in translation tables. Any transla 
tion tables created for the Release 2 Intrinsics should continue to function without change, 
but the widget may wish to take advantage of the new capabilities to fix some obscure bugs. 

In particular, it was impossible in the Release 2 translation syntax to enter a portable (across 
keyboards) event binding for most special characters. The new syntax allows, for example, 
portable key bindings to be made for the "[" and "]" keys independently of whether they 
occur on the same keycap or on separate keycaps on two different keyboards. Other new 
capabilities in the translation manager should be backwards compatible with Release 2. 



E.9 Resource Name and Class Qualifiers 



In Release 2, the name and class passed to xt initialize were prepended to the Shell 
widget name and class to form the full resource name and class of any resources required by 
the widget hierarchy. This prevented a single process from creating separate widget hierar 
chies that behaved as if they were separate applications. 

In Release 3, the "application name" and "application class" are no longer prepended to the 
ApplicationShell name and class. When resources are retrieved for the widget hierarchy, the 
instance name and class of the ApplicationShellWidget created by xtAppCreateShell 
(a new routine) become the left-most resource name and class qualifiers. The compatibility 
interface, Xtlnitialize, arranges to return an ApplicationShellWidget with the appro 
priate instance name and class set from the application_class argument and the com 
mand line options. 

The effect of this change on applications written to the Release 2 specifications is that the 
Shell name/class level of the resource name/class hierarchy has been removed. The 
shell_name argument to Xtlnitialize and the name argument to XtCreate- 
ApplicationShell are no longer evaluated. No source changes to application code 
should be required, but resource files (e.g., application-defaults files) may need to be modi 
fied if they explicitly specify the Shell name and class in any resource specifications. 

In Release 2, the widget argument to XtGetApplicationResources was ignored. In 
Release 3, it must be specified as the ApplicationShellWidget instance that identifies the 
name and class of the application. Applications that specified NULL for the widget argument 
may not retrieve the resources that were expected. 



Appendix E: Converting Widgets from X1 1 Release 2toX11 Release 3 457 



E.10 Bug Fix to XtGet Values 

An implementation bug in XtGet Values in Release 2 caused it to store any resource 
shorter than sizeof(long) into the location specified in the arglist as if the location were 
always declared as long. 

Many applications (knowingly or unknowingly) relied on this bug to clear the high-order 
bytes of fields that were misdeclared. Other applications encountered run-time errors when 
memory was cleared that should not have been cleared. 

In Release 3, it is critical to audit all calls to XtGet Values in widgets and in applications 
and verify that the correct data type is used in the declarations of the variables named in the 
arglists. The most common errors involved declaring an int field for the value of xt- 
Nwidth or xtNheight (which are Dimension) or for the value of XtNx and xtNy 
(which are both Position). Applications that do not call XtGetValues will probably 
work correctly with only a re-compile. 



E.1 1 Changes to Shell Defaults 

The default value for the xtNinput resource of Shell widgets is now FALSE. Applications 
that expect to receive input and that do not perform their own X focus management may need 
to set this to TRUE (with xt Set values) to operate under some window managers. 

XtRealizeWidget now respects the XtNmappedWhenManaged resource of Shell 
widgets. This is unlikely to affect many applications (except those which may have tried to 
work around the automatic MapWindow request for Shells) but it is possible that an overly- 
general resource specification in a resource database might now prevent a hierarchy from 
being mapped when an application expected other behavior. 



E.1 2 XtAddlnput and XtAddTimeout 

In Release 2 it was not possible for an application to query the Toolkit to discover whether or 
not there were X events pending without also executing input or timer callbacks. In Release 
3, the routines XtPending and xtPeekEvent will only return the state of any X events 
and will not dispatch alternate input or timers. 

An application that relied upon timer events being dispatched by one of these two routines 
will have to be modified to use one of the new routines, XtProcessEvent or xtApp- 
ProcessEvent. 



458 X Toolkit Intrinsics Programming Manual 



F 



The xbitmap Application 



This appendix shows the complete code for all versions of xbitmap, which is 
described in Chapters 4 and 5. 



In This Appendix: 

The BitmapEdit Widget 461 

The BitmapEdiP.h Private Header File 473 

The BitmapEdit.h Public Header File 475 

xbitmapS 476 



F 
The xbitmap Application 



This appendix shows the complete code for the BitmapEdit widget, and the complete code 
for an advanced version of the xbitmap application which is similar to xbitmapS described in 
Chapter 4 but adds the ability to read XI 1 bitmap files (xbitmapS was capable of writing 
them only). 

All source code from this book is available free from numerous sources, as described in the 
Preface. 



F.1 The BitmapEdit Widget 

Example F-1. BitmapEdit: complete widget code 

11 /* 

* BitmapEdit .c - bitmap editor widget. 
*/ 

finclude <Xll/IntrinsicP.h> 
finclude <Xll/StringDef s.h> 

finclude <stdio.h> 
finclude "BitmapEdiP.h" 

fdefine INTERNAL_WIDTH 2 
idefine INTERNAL_HEIGHT 4 

fdefine DEFAULT_PIXMAP_WIDTH 32 /* in cells */ 
fdefine DEFAULT_PIXMAP_HEIGHT 32 /* in cells */ 

fdefine DEFAULT_CELL_SIZE 30 /* in pixels */ 

/* values for instance variable is_drawn */ 
fdefine DRAWN 1 
fdefine UNDRAWN 

:>::: 

/* modes for drawing */ 
fdefine DRAW 1 
fdefine UNDRAW 

fdefine MAXLINES 1000 /* max of horiz or vertical cells */ 
fdefine SCROLLBARWIDTH 15 

fdefine of f set (field) XtOf f set (BitmapEditWidget, field) 

Appendix F: The xbitmap Application 46 1 



Example F-1. BitmapEdit: complete widget code (continued) 

static XtResource resources [] = { 
{ 

XtN foreground, 
XtCForeground, 
XtRPixel, 
sizeof (Pixel) , 

offset (bitmapEdit . foreground) , 
XtRString, 
XtDefaultForeground 



XtNcallback, 

XtCCallback, 

XtRCallback, 

sizeof (caddr_t) , 

offset (bitmapEdit .callback) , 

XtRCallback, 

NULL 



XtNcellSizelnPixels, 
XtCCellSizelnPixels, 
XtRInt, sizeof (int), 

offset (bitmapEdit . cell_size_in_pixels) , 
XtRImmediate, 
(caddr_t) DEFAULT_CELL_SIZE 



XtNpixmapWidthlnCells, 
XtCPixmapWidthlnCells, 
XtRDimension, 
sizeof (Dimension) , 

offset (bitmapEdit ,pixmap_width_in_cells) 
XtRImmediate, 
(caddr_t) DEFAULTPIXMAPWIDTH 



XtNpixmapHeightlnCells, 
XtCPixmapHeightlnCells, 
XtRDimension, 
sizeof (Dimension) , 

offset (bitmapEdit .pixmap_height_in_cells) 
XtRImmediate, 
(caddr_t) DEFAULT_PIXMAP_HEIGHT 



XtNcurX, 
XtCCurX, 
XtRInt, 
sizeof (int) , 

offset (bitmapEdit . cur_x) 
XtRImmediate, 
(caddr_t) 



462 X Toolkit Intrinsics Programming Manual 



Example F-1. BitmapEdit: complete widget code (continued) 



XtNcurY, 
XtCCurY, 
XtRInt, 
sizeof (int) , 

offset (bitmapEdit . cur_y ) , 
XtRString, 
(caddr t) NULL 



XtNcellArray, 

XtCCellArray, 

XtRString, 

sizeof (String) , 

offset (bitmapEdit. cell) 

XtRImmediate, 

(caddr_t) 



/* Declaration of methods */ 

/* 

* These don t work under SunOS 4.0.1 and perhaps others, 

* static XtlnitProc Initialize (); 

* static XtExposeProc Redisplay (); 

* static XtWidgetProc Destroy (); 

* static XtWidgetProc Resize (); 

* static XtSetValuesFunc SetValues (); 



static void Initialize (); 

static void Redisplay (); 

static void Destroy (); 

static void Resize (); 

static Boolean SetValues (); 

static XtGeometryResult QueryGeometry () ; 

/* these Core methods not needed by BitmapEdit: 

* 

* static XtProc Classlnitialize (); 

* static XtRealizeProc Realize (); 

* static void Classlnitialize (); 

* static void Realize (); 
*/ 

/* the following are private functions unique to BitmapEdit 
static void DrawPixmaps () , DoCellO, ChangeCellSize () ; 

/* the following are actions of BitmapEdit */ 
static void DrawCelK), UndrawCell () , ToggleCell () ; 

/* The following are public functions of BitmapEdit, 

* declared extern in the public include file: */ 
char *BitmapEditGetArrayString () ; 



static char defaultTranslations[] = 
"<BtnlDown>: DrawCelK) 
<Btn2Down>: UndrawCell () 
<Btn3Down>: ToggleCell () 



\n\ 
\n\ 
\n\ 



Appendix F: The xbitmap Application 



463 



Example F-1. BftmapEdit: complete widget code (continued) 



<BtnlMotion>: DrawCell () 
<Btn2Motion>: UndrawCelK) 
<Btn3Motion>: ToggleCell () 

static XtActionsRec actions [] = { 
{"DrawCell", DrawCell}, 
{"UndrawCell", UndrawCell}, 
{"ToggleCell", ToggleCell}, 



\n\ 
\n\ 



/* definition in BitmapEdit.h */ 
static BitmapEditPointlnf o info; 

BitmapEditClassRec bitmapEditClassRec = { 



/* core class fields */ 




/* superclass 


*/ 


/* class name 


*/ 


/* widget size 


*/ 


/* class_initialize 


*/ 


/* class part initialize*/ 


/* class_inited 


*/ 


/* initialize 


*/ 


/* initialize_hook 


*/ 


/* realize 


*/ 


/* actions 


*/ 


/* num_actions 


*/ 


/* resources 


*/ 


/* num resources 


*/ 


/* xrm class 


*/ 


/* compress motion 


*/ 


/* compress exposure 


*/ 


/* compress enterleave 


*/ 


/* visible interest 


*/ 


/* destroy 


*/ 


/* resize 


*/ 


/* expose 


*/ 


/* set values 


*/ 


/* set values hook 


*/ 


/* set values almost 


*/ 


/* get values hook 


*/ 


/* accept focus 


*/ 


/* version 


*/ 


/* callback private 


*/ 


/* tm_table 


*/ 


/* query_geometry 


*/ 


/* display accelerator 


*/ 


/* extension 


*/ 



(WidgetClass) SwidgetClassRec, 

"BitmapEdit", 

sizeof (BitmapEditRec) , 

NULL, 

NULL, 

FALSE, 

Initialize, 

NULL, 

XtlnheritRealize, 

actions, 

XtNumber (actions) , 

resources, 

XtNumber (resources) , 

NULLQUARK, 

TRUE, 

TRUE, 

TRUE, 

FALSE, 

Destroy, 

Resize, 

Redisplay, 

SetValues, 

NULL, 

XtlnheritSetValuesAlmost, 

NULL, 

NULL, 

XtVersion, 

NULL, 

default Translations, 

QueryGeometry, 

XtlnheritDisplayAccelerator, 

NULL 



/* dummy_field 
}, 



WidgetClass bitmapEditWidgetClass = (WidgetClass) & 

bitmapEditClassRec; 
static void 



464 



X Toolkit Intrinsics Programming Manual 



Example F-1. BitmapEdit: complete widget code (continued) 

GetDrawGC (cw) 
BitmapEditWidget cw; 
{ 

XGCValues values; 

XtGCMask mask = GCForeground | GCBackground I GCDashOffset 
I GCDashList | GCLineStyle; 

/* 

* Setting foreground and background to 1 and looks like 

* a kludge but isn t. This GC is used for drawing into 

* a pixmap of depth one. Real colors are applied with 

* a separate GC when the pixmap is copied into the window. 
*/ 

values. foreground = 1; 

values. background = 0; 

values. dashes = 1; 

values . dash_off set = 0; 

values. line_style = LineOnOf fDash; 

cw->bitmapEdit.draw_gc = XCreateGC (XtDisplay (cw) , 

cw->bitmapEdit .big_picture, mask, (values); 
} 

static void 
GetUndrawGC (cw) 
BitmapEditWidget cw; 
{ 

XGCValues values; 

XtGCMask mask = GCForeground I GCBackgrpund; 

/* this looks like a kludge but isn t. This GC is used for 

* drawing into a pixmap of depth one. Real colors are 

* applied as the pixmap is copied into the window. 
*/ 

values . foreground = 0; 
values .background = 1; 

cw->bitmapEdit .undraw_gc = XCreateGC (XtDisplay (cw) , 
cw->bitmapEdit .big_picture, mask, Svalues); 

} 

static void 
GetCopyGC (cw) 
BitmapEditWidget cw; 
{ 

XGCValues values; 

XtGCMask mask = GCForeground I GCBackground; 

values. foreground = cw->bitmapEdit . foreground; 
values. background = cw->core.background_pixel; 

cw->bitmapEdit .copy_gc = XtGetGC(cw, mask, Svalues); 
} 

/* ARGSUSED */ 

static void 

Initialize (request, new) 

BitmapEditWidget request, new; 

{ 

new->bitmapEdit . cur_x = 0; 



Appendix F: The xbitmap Application 



465 



Example F-1. BftmapEdit: complete widget code (continued) 



new->bitmapEdit .cur_y 
/* 



0; 



/ 



Check instance values set by resources 
that may be invalid. 



if { (new->bitmapEdit.pixmap_width_in_cells < 1) || 

(new->bitmapEdit.pixmap_height_in_cells < 1)) { 
XtWarning("BitmapEdit: pixmapWidth and/or pixmapHeight \ 

is too small (using 10 x 10)."); 
new->bitmapEdit.pixmap_width_in_cells = 10; 
new->bitmapEdit.pixmap_height_in_cells = 10; 
} 

if (new->bitmapEdit.cell_size_in_pixels < 5) { 

XtWarning("BitmapEdit: cellsize is too small (using 5)."); 
new->bitmapEdit . cell_size_in_pixels = 5; 

} 

if ( (new->bitmapEdit.cur_x < 0) | | (new->bitmapEdit .cur_y < 0) 
XtWarning(-BitmapEdit: cur_x and cur_y must be \ 

non-negative (using 0, 0)."); 
new->bitmapEdit . cur_x = 0; 
new->bitmapEdit . cur_y = 0; 

} 

if (new->bitmapEdit.cell == NULL) 
new->bitmapEdit . cell = 

XtCalloc (new->bitmapEdit .pixmap_width_in_cells 

* new->bitmapEdit.pixmap_height_in_cells, 
sizeof (char) ) ; 

new->bitmapEdit.pixmap_width_in_pixels = 

new->bitmapEdit .pixmap_width_in_cells 

* new->bitmapEdit.cell_size_in_pixels; 

new->bitmapEdit.pixmap_height_in_pixels = 

new->bitmapEdit.pixmap_height_in_cells 

* new->bitmapEdit.cell_size_in_pixels; 

if (new->core. width == 0) 

new->core. width = (new->bitmapEdit .pixmap_width_in_pixels 

> 300) ? 300 : 

(new->bitmapEdit .pixmap_width_in_pixels) ; 
if (new->core. height == 0) 

new->core. height = (new->bitmapEdit .pixmap_height_in_pixels 

> 300) ? 300 : 

(new->bitmapEdit .pixmap_height_in_pixels) ; 

CreateBigPixmap (new) ; 

GetDrawGC (new) ; 
GetUndrawGC (new) ; 
GetCopyGC (new) ; 

DrawIntoBigPixmap (new) ; 



/* ARGSUSED 
static void 



466 



x Toolkit Intrinsics Programming Manual 



Example F-1. BitmapEdit: complete widget code (continued) 

Redisplay (cw, event) 
BitmapEditWidget cw; 
XExposeEvent *event; 
{ 

register int x, y; 

unsigned int width, height; 

if (. XtlsRealized(cw) ) 
return; 

if (event) { /* called from btn-event or expose */ 

x = event->x; 

y = event->y; 

width = event->width; 

height = event->height; 
} 
else { /* called because complete redraw */ 

x = 0; 

y = 0; 

width = cw->bitmapEdit . pixmap_width_in_pixels; 

height = cw->bitmapEdit .pixmap_height_in_pixels; 
} 

if (DefaultDepthOfScreen(XtScreen(cw) ) == 1) 

XCopyArea (XtDisplay (cw) , cw->bitmapEdit .big_picture, 
XtWindow (cw) , cw->bitmapEdit . copy_gc, x + 
cw->bitmapEdit . cur_x, y + cw->bitmapEdit . cur_y, 
width, height, x, y) ; 
else 

XCopyPlane (XtDisplay {cw) , cw->bitmapEdit .big_picture, 
XtWindow (cw) , cw->bitmapEdit . copy_gc, x + 
cw->bitmapEdit . cur_x, y + cw->bitmapEdit .cur_y, 
width, height, x, y, 1); 



/* ARGSUSED */ 

static Boolean 

SetValues (current, request, new) 

Widget current, request, new; 

{ 

BitmapEditWidget curcw = (BitmapEditWidget) current; 

BitmapEditWidget newcw = (BitmapEditWidget) new; 

Boolean do_redisplay = False; 

if (curcw->bitmapEdit . foreground != 

newcw->bitmapEdit . foreground) { 
XtReleaseGC (curcw, curcw->bitmapEdit . copy_gc) 
GetCopyGC (newcw) ; 
do_redi splay = True; 

} 

if ( (curcw->bitmapEdit . cur_x != 

newcw->bitmapEdit . cur_x) I I 
(curcw->bitmapEdit . cur_y != 

newcw->bitmapEdit .cur_y) ) { 

do_redisplay = True; 
} 

if (curcw->bitmapEdit . cell_size_in_pixels != 



Appendix F: The xbitmap Application 



Example F-1. BitmapEdit: complete widget code (continued) 

newcw->bitmapEdit . cell_size_in_pixels) 
ChangeCellSize (curcw, 

newcw->bitmapEdit . cell_size_in_pixels) ; 
do_redisplay = True; 



if (curcw->bitmapEdit .pixmap_width_in_cells != 

newcw->bitmapEdit . pixmap_width_in_cells) { 
newcw->bitmapEdit . pixmap_width_in_cells = 

curcw->bitmapEdit . pixmap_width_in_cells; 
XtWarning ("BitmapEdit : pixmap_width_in_cells cannot \ 

be set by XtSetValues. \n") ; 
} 

if (curcw->bitmapEdit .pixmap_height_in_cells != 

newcw->bitmapEdit .pixmap_height_in_cells) { 
newcw->bitmapEdit . pixmap_height_in_cells = 

curcw->bitmapEdit .pixmap_height_in_cells; 
XtWarning ("BitmapEdit : pixmap_height_in_cells cannot \ 

be set by XtSetValues. \n") ; 
} 

return do_redisplay; 



static void 
Destroy (cw) 
BitmapEditWidget cw; 
{ 

if (cw->bitmapEdit .big_picture) 

XFreePixmap(XtDisplay (cw) , cw->bitmapEdit .big_picture) ; 

if (cw->bitmapEdit .draw_gc) 

XFreeGC (XtDisplay (cw) , cw->bitmapEdit .draw_gc) ; 

if (cw->bitmapEdit .undraw_gc) 

XFreeGC (XtDisplay (cw) , cw->bitmapEdit .undraw_gc) ; 

if (cw->bitmapEdit . copy_gc) 

XFreeGC (XtDisplay (cw) , cw->bitmapEdit . copy_gc) ; 

/* NOTE! This should only free when the application didn t 
* allocate it. Need to add another. */ 

XtFree (cw->bitmapEdit . cell) ; 
} 

static void 
DrawCell (w, event) 
BitmapEditWidget w; 
XEvent *event; 
( 

DrawPixmaps (w->bitmapEdit .draw_gc, DRAW, w, event); 
} 

static void 
UndrawCell (w, event) 
BitmapEditWidget w; 
XEvent *event; 



468 X Toolkit Intrinsics Programming Manual 



Example F-1. BitmapEdit: complete widget code (continued) 

DrawPixmaps (w->bitmapEdit.undraw_gc, UNDRAW, w, event); 

static