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. Reader«How 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 */
0 /* 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 form1 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,
0
/* 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
0
XtNy
XtCPosition
Position
0
XtNwidth
XtCWidth
Dimension
0
XtNheight
XtCHeight
Dimension
0
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, /
0 /:
argument list*/
arglist size */
quit = XtCreateManagedWidget (
"quit", /* widget name */
commandWidgetClass, /* widget class */
box, /* parent widget*/
NULL, /'
0 /
argument list*/
arglist size */
pressme = XtCreateManagedWidget (
"pressme",
commandWidget Class ,
box,
NULL,
0
/* 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 */
0 /* arglist size */
);
pshell = XtCreatePopupShell (
"pshell11,
transient ShellWidgetClass,
topLevel,
NULL,
0
);
dialog = XtCreateManagedWidget (
"dialog", /* widget name */
dialogWidgetClass, /* widget class */
pshell, /* parent widget */
NULL, /* argument list */
0 /* arglist size */
);
dialogDone = XtCreateManagedWidget (
"dialogDone", /* widget name */
commandWidgetClass, /* widget class */
dialog, /* parent widget */
NULL, /* argument list */
0 /* 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 0 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. hn 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 ' : ' 0 ' ) ;
(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] , "XBitmapl1
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 [ ] = {
{ nredraw_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 0
tdefine DRAW 1
tdefine UNDRAW 0
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 ' : ' 0 ' ) ;
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},
{"ToggleCell11, 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_jpixels;
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) 0
XtNcurY,
XtCCurY,
XtRInt,
sizeof (int) ,
offset (bitmapEdit . cur_y ) ,
XtRString,
(caddr_t) NULL
XtNcellArray,
XtCCellArray,
XtRString,
sizeof (String) ,
offset (bitmapEdit .cell) ,
XtRImmediate,
(caddr_t) 0
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
0
Position
int
0
Dimension
Dimension
BorderWidth
unsigned int
unsigned int
0
0
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 Is1
"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 0 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, cl±ent_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,
0
);
dialog = XtCreateManagedWidget (
"dialog", /* widget name */
dialogWidgetClass, /* widget class */
pshell, /* parent widget */
NULL, /* argument list */
0 /* 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 */
0 /* 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) 0
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 (wr 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 uwmt 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_ownersh±p_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_procf 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_atomr
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(nNULL") );
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 '%sf 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
AN
AO
Save ...... AS
Save As .... AA
Exit . . AE
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*/
0 /* arglist size */
label = XtCreateManagedWidget (
"label", /* widget name */
labelWidgetClass, /* widget class */
box, /* parent widget*/
NULL, /* argument list*/
0 /* arglist size */
quit = XtCreateManagedWidget (
"quit", /* widget name */
commandWidgetClass, /* widget class */
box, /* parent widget*/
NULL, /* argument list*/
0 /* arglist size */
pshell = XtCreatePopupShell (
"pshell",
transient ShellWidget Class,
topLevel,
NULL,
0
);
menubox = XtCreateManagedWidget (
"menubox", /* widget name */
boxWidgetClass, /* widget class */
pshell, /* parent widget*/
NULL, /* argument list*/
0 /* 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*/
0 /* 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 : 0
*pshell .Box . vSpace : 0
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 I«P 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 0 (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
0
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/rAvant 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)
AN
AO
Save
Save As
Exit .
AS
AA
AE
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 24 colorcells (16 dis
tinct colors); an eight-plane system can index 28 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 t±xoff±yoff
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 0
:>:•:£:£
/* modes for drawing */
fdefine DRAW 1
fdefine UNDRAW 0
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) 0
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) 0
/* 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 0 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 void
ToggleCell (w, event)
BitmapEditWidget w;
XEvent *event;
static int oldx = -1, oldy = -1;
GC gc;
int mode;
int newx, newy;
/* This is strictly correct, but doesn't
* seem to be necessary */
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 {
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;
if ((mode = w->bitmapEdit . cell [newx + newy *
w->bitmapEdit.pixmap_width_in_cells] )
gc = w->bitmapEdit .undraw_gc;
mode = UNDRAW;
}
else {
gc = w->bitmapEdit .draw_gc;
mode = DRAW;
== DRAWN) {
if (oldx != newx | | oldy != newy) {
oldx = newx;
oldy = newy;
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_in_pixels;
int newy = (w->bitmapEdit .cur_y + event->y) /
w->bitmapEdit . cell_size_in_pixels;
XExposeEvent f.ake_event;
Appendix F: The xbitmap Application
469
Example F-1. BitmapEdit: complete widget code (continued)
/* 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_in_pixels*newx + 2,
w->bitmapEdit . cell_size_in_pixels*newy + 2,
(unsigned int) w->bitmapEdit . cell_size_in_pixels - 3,
(unsigned int ) w->bitmapEdit . cell_size_in_pixels -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_in_pixels *
newx - w->bitmapEdit . cur_x;
fake_event.y = w->bitmapEdit . cell_size_in_pixels *
newy - w->bitmapEdit . cur_y;
fake_event .width = w->bitmapEdit . cell_size_in_pixels;
fake_event . height = w->bitmapEdit . cell_size_in_pixels;
Redisplay (w, &fake_event) ;
XtCallCallbacks(w, XtNcallback, Sinfo) ;
}
CreateBigPixmap (cw)
BitmapEditWidget cw;
{
/* always a 1 bit deep pixmap, regardless of screen depth */
cw->bitmapEdit .big_picture = XCreatePixmap (XtDisplay (cw) ,
RootWindow (XtDisplay (cw) , Def aultScreen (XtDisplay (cw) ) )
cw->bitmapEdit .pixmap_width_in_pixels + 2,
cw->bitmapEdit . pixmap_height_in_pixels +2, 1);
}
DrawIntoBigPixmap (cw)
BitmapEditWidget cw;
{
int n_horiz_segments, n_vert_segments;
XSegment segment [MAXLINES] ;
register int x, y;
n_horiz_segments = cw->bitmapEdit .pixmap_height_in_cells + 1;
n_vert_segments = cw->bitmapEdit .pixmap_width_in_cells + 1;
for (x = 0; x < n_horiz_segments; x++) {
segment [x] .xl = 0;
segment [x] .x2 = cw->bitmapEdit .pixmap_width_in_pixels;
segment [x] .yl = cw->bitmapEdit . cell_size_in_pixels * x;
segment [x] .y2 = cw->bitmapEdit . cell_size_in_pixels * x;
}
XDrawSegments (XtDisplay (cw) , cw->bitmapEdit .big_picture,
cw->bitmapEdit .draw gc, segment, n horiz_segments) ;
470 X Toolkit Intrinsics Programming Manual
Example F-1. BitmapEdit: complete widget code (continued)
for (y = 0; y < n_vert_segments; y++) {
segment [y] .xl = y * cw->bitmapEdit . cell_size_in_pixels;
segment [y] .x2 = y * cw->bitmapEdit . cell_size_in_pixels;
segment [y] .yl = 0;
segment [y] .y2 = cw->bitmapEdit .pixmap_height_in_pixels;
XDrawSegments (XtDisplay (cw) , cw->bitmapEdit .big_picture,
cw->bitmapEdit . draw_gc, segment, n_vert_segments) ;
/* draw current cell array into pixmap */
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
DoCell (cw, x, y, cw->bitmapEdit .undraw_gc) ;
}
}
/* A Public function, not static */
char *
BitmapEditGetArrayString (w)
BitmapEditWidget w;
return (w->bitmapEdit . cell) ;
/* 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 >
cw->bitmapEdit ,pixmap_height_in_pixels) ) {
/*
* Calculate the maximum cell size that will allow the
* entire bitmap to be displayed.
*/
Dimension w_temp_cell_size_in_pixels,
h_temp_cell_size_in_pixels;
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)
Appendix F: The xbitmap Application
Example F-1. BitmapEdit: complete widget code (continued)
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_pixels =
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 */
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
DoCell (cw, x, y, cw->bitmapEdit .undraw_gc) ;
}
static void
DoCell (w, x, y, gc)
BitmapEditWidget w;
int x, y;
GC gc;
{
/* otherwise, draw or undraw */
XFillRectangle (XtDisplay (w) , w->bitmapEdit .big_picture, gc,
w->bitmapEdit .cell_size in_pixels * x + 2,
472
X Toolkit Intrinsics Programming Manual
Example F-1. BitmapEdit: complete widget code (continued)
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)
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 s&
answer->heignt == w->core. height)
return XtGeometryNo;
else
return XtGeometryAlmost;
F.2 The BitmapEdiP.h Private Header File
Example F-2. BitmapEdiP.h: complete private header file
/*
* Copyright 1989 O'Reilly and Associates, Inc.
* See ../Copyright for complete rights and liability information.
*/
/*
* Copyright 1989 O'Reilly and Associates, Inc.
* See ../Copyright for complete rights and liability information.
*/
/*
* BitmapEditP.h - Private definitions for BitmapEdit widget
*/
fifndef _ORABitmapEditP_h
fdefine _ORABitmapEditP_h
/*
* This include not needed unless the .c file includes Intrinsic?. h
* after this file. Anyway, it doesn't hurt.
*/
Appendix F: The xbitmap Application 473
Example F-2. BitmapEdiP.h: complete private header file (continued)
linclude <Xll/CoreP .h>
/*
* This one is always needed!
*/
finclude "BitmapEdit .h"
/* New fields for the BitmapEdit widget class record */
typedef struct {
int make_compiler_happy; /* keep compiler happy */
} BitmapEditClassPart;
/* Full class record declaration */
typedef struct _BitmapEditClassRec {
CoreClassPart core_class;
BitmapEditClassPart bitmapEdit_class;
} BitmapEditClassRec;
extern BitmapEditClassRec bitmapEditClassRec;
/* New fields for the BitmapEdit widget record */
typedef struct {
/* resources */
Pixel foreground;
XtCallbackList callback; /* application installed callback fnct(s) */
Dimension pixmap_width_in_cells;
Dimension pixmap_height_in_cells;
int cell_size_in_pixels;
int cur_x, cur_y; /* position of visible corner in big pixmap */
char *cell; /* array 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; /* one plane, for drawing into pixmap */
GC undraw_gc;/* one plane, for drawing into pixmap */
GC copy_gc; /* defaultdepthof screen, for copy'g p'map into wndow */
} BitmapEditPart;
/*
* Full instance record declaration
*/
typedef struct _BitmapEditRec {
CorePart core;
BitmapEditPart bitmapEdit;
} BitmapEditRec;
fendif /* _ORABitmapEditP_h */
474 X Toolkit Intrinsics Programming Manual
F.3 The BitmapEdit.h Public Header File
Example F-3. BitmapEd'rt.h: complete public header Hie
fifndef _ORABitmapEdit_h
fdefine _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.
tinclude <Xll/Core.h>
/* Resources:
* Name
*
* (from RectObj)
* ancestorSensitive
Class
RepType
Ancestor-
Sensitive
Position
*
y
Position
int
*
width
Dimension
unsignei
*
height
Dimension
unsignei
*
borderWidth
BorderWidth
*
sensitive
Sensitive
*
*
(from Core)
*
screen
Screen
Pointer
*
depth
Depth
Int
*
colormap
Colormap
Pointer
*
background
Backgroun
pixel
*
backgroundPixmap
Pixmap
Pixmap
*
borderColor
BorderColor
pixel
*
borderPixmap
BorderPixmap
Pixmap
*
mappedWhenManaged
MappedWhen
Boolean
Managed
translations
accelerators
(from BitmapEdit)
foregroundPixel
backgroundPixel
callback
cellSize
pixmapWidth
pixmapHeight
Foreground
Background
Callback
CellSize
PixmapWidth
PixmapHeight
pixel
pixel
Callback
int
int
int
•I
Default Value
int 0
0
t 0
t 0
Xt Copy Screen
XtCopyFromParent
XtCopyFromParent
White
XtUnspecified-
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
Appendix F: The xb'rtmap Application
475
Example F-3. B'rtmapEd'rt.h: complete public header file (continued)
* cell was turned on (1) or off (0) .
*/
typedef struct {
int mode;
int newx;
int newy;
} BitmapEditPointlnfo;
fdefine XtNcellSizelnPixels "cellSizelnPixels"
fdefine XtNpixmapWidthlnCells "pixmapWidthlnCells"
fdefine XtNpixmapHeightlnCells "pixmapHeightlnCells"
fdefine XtNcurX "curX"
fdefine XtNcurY "curY"
fdefine XtNcellArray "cellArray"
fdefine XtCCellSizelnPixels "CellSizelnPixels"
fdefine XtCPixmapWidthlnCells "PixmapWidthlnCells"
fdefine XtCPixmapHeightlnCells "PixmapHeightlnCells"
fdefine XtCCurX "CurX"
fdefine 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 fendif */
F.4 xbitmapS
Example F-4. xbitmapS: complete application code
/*
* xbitmapS. c
*/
finclude <Xll/Intrinsic.h>
finclude <Xll/StringDef s.h>
fifdef X11R3
finclude <Xll/Form.h>
finclude <Xll/Box.h>
finclude <Xll/Command.h>
felse /* R4 or later */
finclude <Xll/Xaw/Form.h>
476 X Toolkit Intrinsics Programming Manual
Example F-4. xbitmapS: complete application code (continued)
finclude <Xll/Xaw/Box.h>
finclude <Xll/Xaw/Command.h>
fendif /* X11R3 */
finclude "BitmapEdit .h"
finclude <stdio.h>
fdefine DRAWN 1
fdefine UNDRAWN 0
GC draw_gc, undraw_gc, invert_gc;
Pixmap normal_bitmap;
Widget bigBitmap, showNormalBitmap, showReverseBitmap;
Dimension pixmap_width_in_cells, pixmap_height_in_cells;
static void cell_toggled () ;
String filename; /* filename to read and write */
static Boolean f ile_contained_good_data = False;
/* 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) ;
static void
redraw_small_picture (w)
Widget w;
GC gc;
if (w == showNormalBitmap)
gc = DefaultGCOf Screen (XtScreen (w) );
else
gc = invert_gc;
if (Def aultDepthOf Screen (XtScreen (w) ) == 1)
XCopyArea (XtDisplay (w) , normal_bitmap, XtWindow(w),
gc, 0, 0, pixmap_width_in_cells,
pixmap_height_in_cells, 0, 0);
else
XCopyPlane (XtDisplay (w) , normal_bitmap, XtWindow(w),
gc, 0, 0, pixmap_width_in_cells,
pixmap_height_in_cells, 0, 0, 1);
String
FillCell (w)
Widget w;
|
String cell;
int x, y;
Xlmage * image;
cell = XtCalloc(pixmap_width_in_cells * pixmap_height_in_cells,
Appendix F: The xbitmap Application
Example F-4. xbitmapS: complete application code (continued)
sizeof (char) ) ;
/* Convert pixmap into image, so that we can
* read indiviual pixels */
image = XGetlmage (XtDisplay (w) , normal_bitmap, 0, 0,
pixmap_width_in_cells, pixmap_height_in_cells,
AllPlanes, XYPixmap);
for (x = 0; x < pixmap_width_in_cells; x++) {
for (y = 0; y < pixmap_height_in_cells; y
cell [x + (y * pixmap_width_in_cells) ]
i
in_cells; y+ + ) {
i_in_cells) ] = XGetPixel (image, x, y)
return (cell) ;
main (argc, argv)
int argc;
char *argv [ ] ;
Widget topLevel, form, buttonbox, quit, output;
Arg args [5] ;
int i;
extern exit();
unsigned int width, height; /* NOT Dimension: used in Xlib calls */
int junk;
String cell;
static XtActionsRec window_actions [ ] = {
{ "redraw_small_picture", redraw_small_picture}
String trans =
"<Expose> : redraw_small_picture ( ) ";
static XrmOptionDescRec table [] =
{"-pw", "*pixmapWidthInCells", XrmoptionSepArg, NULL},
{ "-pixmapwidth" , "*pixmapWidthInCells", XrmoptionSepArg, NULL},
{"-ph", "*pixmapHeightInCells" , XrmoptionSepArg, NULL},
{ "-pixmapheight" , "*pixmapHeightInCells" , XrmoptionSepArg, NULL},
{"-cellsize", "*cellSize!nPixels", XrmoptionSepArg, NULL},
topLevel = Xtlnitialize (argv [ 0] , "XBitmapS", table, XtNumber (table) ,
targe, argv) ;
if (argv[l] != NULL)
filename = argv[l];
else {
fprintf (stderr, "xbitmap: must specify filename \
on command line.\nn);
exit (1) ;
}
form = XtCreateManagedWidget ( "f orm" , f ormWidgetClass, topLevel,
NULL, 0) ;
buttonbox = XtCreateManagedWidget ("buttonbox", boxWidgetClass,
form, NULL, 0) ;
478 X Toolkit Intrinsics Programming Manual
Example F-4. xbitmapS: complete application code (continued)
output = XtCreateManagedWidget ("output", commandWidgetClass,
buttonbox, NULL, 0);
XtAddCallback (output, XtNcallback, printout, NULL);
quit = XtCreateManagedWidget ("quit", commandWidgetClass,
buttonbox, NULL, 0) ;
XtAddCallback (quit, XtNcallback, exit, NULL);
XtAddActions (window_actions, XtNumber (window_actions) ) ;
switch (XReadBitmapFile (XtDisplay (quit) ,
RootWindowOfScreen (XtScreen (quit) ) , filename,
Swidth, sheight, snormal_bitmap, Sjunk, &junk)) {
case BitmapSuccess :
f ile_contained_good_data = True;
if ( (pixmap_width_in_cells != width) ||
(pixmap_height_in_cells != height)) {
fprintf (stderr, "xbitmap: bitmap \
file dimensions do not match \
resource database, ignoring \
database . \n" ) ;
i = 0;
XtSetArg(args[i] , XtNpixmapWidthlnCells,
width) ; i++;
XtSetArg (args [i ] , XtNpixmapHeightlnCells,
height); i++;
pixmap_width_in_cells = width;
pixmap_height_in_cells = height;
cell = FillCell(quit) ;
XtSetArg (args [i ], XtNcellArray, cell); i++;
}
break;
case BitmapOpenFailed:
fprintf (stderr, "xbitmap: could not open \
bitmap file, using fresh bitmap. \n")
break;
case BitmapFilelnvalid:
fprintf (stderr, "xbitmap: bitmap file invalid. \n") ;
exit(l);
case BitmapNoMemory :
fprintf (stderr, "xbitmap: insufficient \
server memory to create bitmap. \n") ;
exit (1);
default:
fprintf (stderr, "xbitmap: programming error. \n");
exit(l);
/* args are set in if and switch above if file was read */
bigBitmap = XtCreateManagedWidget ("bigBitmap",
bitmapEditWidget Class,
form, args, i) ;
XtAddCallback (bigBitmap, XtNcallback, cell_toggled, NULL);
if ( ! file_contained_good_data) {
i = 0;
Appendix F: The xbitmap Application 479
Example F-4. xbitmapS: complete application code (continued)
XtSetArg (args [i] , XtNpixmapHeightlnCells,
ipixmap_height_in_cells) ; i++;
XtSetArg (args [i] , XtNpixmapWidthlnCells,
£pixmap_width_in_cells) ; i++;
XtGetValues (bigBitmap, args, i);
normal_bitmap = XCreatePixmap (XtDisplay (quit) ,
RootWindowOfScreen (XtScreen (quit) ) ,
pixmap_width_in_cells, pixmap_height_in_cells, 1) j
}
set_up_things (topLevel) ;
i = 0;
XtSetArg (args [i] , XtNwidth, pixmap_width_in_cells) ; i++;
XtSetArg (args [i] , XtNheight, pixmap_height_in_cells) ; i++;
XtSetArg (args [i] , XtN translations,
XtParseTranslationTable (trans) ) ; i++;
showNormalBitmap = XtCreateManagedWidget ("showNormalBitmap",
widgetclass, buttonbox, args, i);
showReverseBitmap = XtCreateManagedWidget ("showReverseBitmap"
widgetclass, buttonbox, args, i);
XtRealizeWidget (topLevel) ;
XtMainLoopO ;
}
set_up_things (w)
Widget w;
{
XGCValues values;
values . foreground = 1;
values .background = 0;
/* note that normal_bitmap is used as the drawable
* because it is one bit deep. The root window may
* not be one bit deep. */
draw_gc = XCreateGC (XtDisplay (w) , normal_bitmap,
GCForeground | GCBackground, Svalues) ;
values . foreground = 0;
values. background = 1;
undraw_gc = XCreateGC (XtDisplay (w) , normal_bitmap,
GCForeground | GCBackground, lvalues) ;
/* this GC is for copying from the bitmap
* to the small reverse widget */
values. foreground = WhitePixelOf Screen (XtScreen (w) );
values. background = BlackPixelOfScreen (XtScreen (w) );
invert_gc = XtGetGC(w, GCForeground | GCBackground, Svalues)
J
/* ARGSUSED */
static void
cell_toggled (w, unused, info)
Widget w;
caddr_t unused; /* client_data */
caddr t info; /* call data (from widget) */
480 X Toolkit Intrinsics Programming Manual
Example F-4. xbitmapS: complete application code (continued)
BitmapEditPointlnfo *cur_info = (BitmapEditPointlnfo *) info
/*
* Note: BitmapEditPointlnfo is defined in BitmapEdit.h
*/
XDrawPoint (XtDisplay (w) , normal_bitmap, ( (cur_info->mode ==
DRAWN) ? draw_gc : undraw_gc) , cur_info->newx,
cur_inf o->newy) ;
redraw_small_picture (showNormalBitmap) ;
redraw_small_picture (showReverseBitmap) ;
Appendix F: The xbitmap Application 48 1
G
Sources of Additional Information
This appendix describes where you can get more information about the X
Toolkit and about X in general, including other books on the subject and the
various ways to get the source code for X.
In This Appendix:
Getting the X Software 485
Bug Fixes 486
Notes 488
Fairness 488
Netnews 489
Training and Consulting 489
Phone Support 490
The X Consortium 490
Finding Out for Yourself 491
G
Sources of Additional Information
This appendix lists a few of the official and unofficial sources for information about the X
Window System and associated software.
Note that some of this detailed information may become dated rather quickly. The best
source of current information is the comp. windows jc network news group, described later in
this appendix.
G.1 Getting the X Software
At this writing, the current public release level is Release 3, but Release 4 is expected to be
released shortly. This book documents Release 3, with some references to Release 4. The
references to R4 are based on the Beta releases of R4 currently available to X Consortium
members only. (O'Reilly and Associates, Inc., is an X Consortium Affiliate Member.) Even
after the public R4 release, many people will continue to use R3 since there is a considerable
lag time between the date that MIT distributes a new release and the date by which vendors
integrate that release into their own products and issue updates. (All changes to Xt in R4 are
backwards compatible so that any software that runs under R3 will also run under R4.)
You can get the X software directly from MIT on three 9-track 1600 BPI magtapes written in
UNIX tar format or on one 9-track 6250 BPI magtape, along with printed copies of MIT's
manuals, by sending a check in U.S. currency for U.S. $400 to:
MIT Software Distribution Center
Technology Licensing Office
MITE32-300
77 Massachusetts Avenue
Cambridge, MA 02139
Their telephone number is (617) 253-6966, and the "X Ordering Hotline" is (617) 258-8330.
If you want the tapes and manuals shipped overseas, the price is $500. The manual set alone
is $125, including U.S. shipping, or $175, including overseas shipping.
Other distribution media or formats are not available from the MIT Software Distribution
Center, but are from other independent vendors such as ICS, mentioned later. The Release
tape comes with source code for sample servers for Sun, HP, IBM, Apollo, Sony, DEC and
Appendix G: Sources of Additional Information 485
several other workstations, source code for clients written by MIT, sources for the toolkits
Xt, XView (in R4), Interviews, and Andrew, contributed software written outside MIT, and
sources and postscript files for all MIT's documentation. Note that the servers supplied are
sample servers only; commercial vendors typically release optimized (faster) servers for the
same machines.
Sites that have access to the Internet can retrieve the distribution from the following
machines using anonymous ftp. Here are the current sites:
Location
Hostname
Address
Directory
West
gatekeeper.dec.com
128.45.9.52
publX.VllRS
nic.mr.net
192.12.250.5
publX.VHR3
East
UUNET.uu.net
192.12.141.129
X/X.V11R3
Northeast
expo.lcs.mit.edu
18.30.0.212
publX.VUR3
Midwest
cygnusxl.cs.utk.edu
128.169.201.12
publX.VHR3
giza. cis. ohio-state. edu
128.146.8.61
publX.VHR3
South
dinorah.wustl. edu
129.252.118.101
publX.VllR3
DO NOT do anonymous ftp during normal business hours, and please use the machine
nearest you.
The distribution is also available by UUCP from UUNET, for sites without Internet access.
The files are split up to be small enough for UUCP distribution.
G.1.1 Bug Fixes
Critical bug fixes as well as a limited number of important new features are available from
the archive server xstuff@expo.lcs.mit.edu. Electronic mail sent to this address is forwarded
to a program which responds with the requested information. The rest of this section and the
two that follow it (entitled Notes and Fairness) explain how to use xstuffP.
The xstuff server is a mail-response program. This means that you mail it a request, and it
mails back the response.
The xstuff server is a very dumb program. It does not have much error checking. If you don't
send it commands that it understands, it will just answer "I don't understand you."
The xstuff server reads your entire message before it does anything, so you can have several
different commands in a single message. It treats the "Subject:" header line just like any
other line of the message. You can use any combination of upper and lower case letters in
the commands.
The archives are organized into a series of directories and subdirectories. Each directory has
an index, and each subdirectory has an index. The top-level index gives you an overview of
what is in the subdirectories, and the index for each subdirectory tells you what it contains.
If you are bored with reading documentation and just want to try something, then send the
server a message containing the line:
486
X Toolkit Intrinsics Programming Manual
send index fixes
When you get the index back, it will contain the numbers of all of the fixes and batches of
fixes in the archive. Then you can send the server another message asking it to send you the
fixes that you want:
send fixes 159 11-20
If you are using a mailer that understands "@" notation, send to xstujf@expo.lcs.mit.edu. If
your mailer deals in "!" notation, try sending to {someplace} teddie! expo. Ics.mit.edu'xstuff.
For other mailers, you're on your own.
The server has four commands. Each command must be the first word on a line.
help The command help or send help causes the server to send you the help file. No
other commands are honored in a message that asks for help (the server figures that
you had better read the help message before you do anything else).
index If your message contains a line whose first word is index, then the server will send
you the top-level index of the contents of the archive. If there are other words on
that line that match the name of subdirectories, then the indexes for those subdirec
tories are sent instead of the top-level index. For example, you can say:
index
on
index fixes
You can then send back another message to the xstuff server, using a send command
(see below) to ask it to send you the files whose name you learned from that list.
index fixes and send index fixes mean the same thing: you can use send instead of
index for getting an index.
If your message has an index or a send index command, then all other send com
mands will be ignored. This means that you cannot get an index and data in the
same request This is so that index requests can be given high priority.
send If your message contains a line whose first word is send, then the xstuff server will
send you the item(s) named on the rest of the line. To name an item, you give its
directory and its name. For example:
send fixes 1-10
Once you have named a category, you can put as many names as you like on the
rest of the line. They will all be taken from that category. For example:
send fixes 1-10 11-20 21-30
Each send command can reference only one directory. If you would like to get one
fix and one of something else, you must use two send commands.
You may put as many send commands as you like into one message to the server,
but the more you ask for, the longer it will take to receive. See the Fairness Section
below, for an explanation. Actually, it's not strictly true that you can put as many
Appendix G: Sources of Additional Information 48?
send commands as you want into one message. If the server must use UUCP mail to
send your files, then it cannot send more than 100K bytes in one message. If you
ask for more than it can send, then it will send as much as it can and ignore the rest
path The path command exists to help in case you do not get responses from the server
when you mail to it
Sometimes the server is unable to return mail over the incoming path. There are
dozens of reasons why this might happen, and if you are a true wizard, you already
know what those reasons are. If you are an apprentice wizard, you might not know
all the reasons, but you might know a way to circumvent them.
If you put in a path command, then everything that the server mails to you will be
mailed to that address, rather than to the return address on your mail. The server
host expo.lcs.mit.edu does not have a direct UUCP connection to anywhere; you
must go through mit-eddie (the UUCP name of eddie.mit.edu) or somewhere else.
G. 1.1.1 Notes
The xstuff server acknowledges every request by return mail. If you don't get a message
back in a day or two you should assume that something is going wrong, and perhaps try a
path command.
The xstuff server does not respond to requests from users named root, system, daemon, or
mailer. This is to prevent mail loops. If your name is "Bruce Root" or "Jane Daemon", and
you can document this, I will happily rewrite the server to remove this restriction. Yes, I
know about Norman Mailer and Waverley Root. Norman doesn't use netmail and Waverley
is dead.
G.1.1.2 Fairness
The xstuff server contains many safeguards to ensure that it is not monopolized by people
asking for large amounts of data. The mailer is set up so that it will send no more than a fixed
amount of data each day. If the work queue contains more requests than the day's quota, then
the unsent files will not be processed until the next day. Whenever the mailer is run to send
its day's quota, it sends the requests out shortest-first
If you have a request waiting in the work queue and you send in another request, the new
request is added to the old one (thereby increasing its size) rather than being filed anew. This
prevents you from being able to send in a large number of small requests as a way of beating
the system.
The reason for all of these quotas and limitations is that the delivery resources are finite, and
there are many people who would like to make use of the archive.
488 X Toolkit Intrinsics Programming Manual
G.2 Netnews
The Usenet network news is probably the most valuable source of information about X. The
current list of public news groups that discuss X is as follows:
News Group
xll-3D
x-ada
xfont
ximage
xnonfb
xpc
xpert
xserial
xtensions
xvideo
Description
People interested in X and 3-D graphics
Xandada
People interested in fonts
People interested in image processing and X
Server implementors for non-frame buffers
People interested in implementing X on PCs
General discussion of X
Serial line X servers
Technical discussion of changes to X
Discussion of video extensions for X
The developers of X post notices of fixes to the software to comp.windowjc, and this is where
users and developers around the world ask and answer questions.
G.3 Training and Consulting
Numerous independent vendors provide courses on X programming. Several sources that we
are aware of include:
• Integrated Computer Solutions, 163 Harvard Street, Cambridge, MA 02139; (617)
547-0510. Courses on Xlib, Motif, strategic overviews of X. Also provides consulting
services and manages an X user's group.
• Hands-On Learning, 27 Cambridge Street, Burlington, MA 01803; (617) 272-0088.
Courses on Xlib and Xt.
• X tutorials are now a regular feature of UNIX conventions such as the UNIX EXPO,
Usenix, Uniforum, the annual X conference at MIT, and Xhibition, the conference organ
ized by ICS. Also contact commercial server vendors for information on courses they
offer.
Training companies wishing to be listed here should send us information on the courses they
offer.
Appendix G: Sources of Additional Information
G.3.1 Phone Support
X programming is a very new field, and since everyone who knows enough to help you is
overworked, you are likely to hear "you're on your own" if you try to call for help. There are
currently no support lines, because X was developed by a university, not a system manufac
turer or software house. When X becomes widely supported as a commercial product, the sit
uation will change as vendors offer support.
ICS provides phone support for a fee. See Section G.3 for their telephone number.
G.4 The X Consortium
The X Consortium can be reached at:
MIT X Consortium
545 Technology Square Rm. 217
Cambridge, MA 02 139
The consortium's phone number is (617) 253-8861; its current members are shown below.
ACER Counterpoint, Inc.
AT&T
Adobe Systems
Advanced Graphics Engineering
Apollo Computer, Inc.
Apple Computer, Inc.
Ardent Computer
BULLMTS
CETIA
CalComp
Canterbury University, England
Carnegie Mellon University
Codonics, Inc.
Control Data Corporation
Cray Research, Inc.
Data General
Digital Equipment Corp.
Eastman Kodak Company
Evans & Sutherland
Fujitsu America, Inc.
GfxBase
Hewlett-Packard Company
IBM Corporation
INESC*
Integrated Computer Solutions, Inc.
Integrated Solutions, Inc.
Matrox International
Megatek Corp.
Mitsubishi Electric Corporation
NCR Corporation
NEC Corporation
NTT Corporation
Network Computing Devices, Inc.
Nova Graphics International
O'Reilly & Associates, Inc.
OMRON Tateisi Electronics
Open Software Foundation
PCS Computer Systeme GmbH
Prime Computer, Inc.
Reuters
Samsung Software America
Sequent Computer Systems Inc.
Siemens AG
Silicon Graphics Computer Systems
Societe de Gestion et d'Informatique Publicis
Software Productivity Consortium
Solboume Computer Inc.
Sony Corporation
Stanford University
Stellar Computer Inc.
Sun Microsystems, Inc.
Tatung Science and Technology
* Institute de Engenharia de Sistemas e Computadorcs
490
X Toolkit Intrinsics Programming Manual
Interactive Development Environments Tektronix, Inc.
Interactive Systems Corp. Texas Instruments
Jupiter Systems UNICAD, Inc.
Key Systems Engineering Corp. Unisys Corp.
Landmark Graphics Corp. University of Lowell
Locus Computing Corp. Visual Technology, Inc.
MIPS Computer Systems Wang Laboratories
MITRE Corp. X/Open Company Ltd.
Most of these companies are preparing products based on X. It should not be long before
many different products are available that support X.
G.5 Finding Out for Yourself
X is unusual in that the source code is in the public domain. It should be possible for most X
programmers to get a copy of the X source code from the sources listed above. Once you
understand how the code is organized, you can look up certain details about how X works as
long as you have a good knowledge of C and a little persistence. In "Star Wars," the saying
was "Use the Force, Luke." In X, it is "Use the Source, Luke."
Xlib and the server are two distinct chunks of code. Each contains code for sending and
receiving information to and from the other over the network using protocol requests, replies,
events, and errors. The source tree as supplied on the X distribution tape places the Xlib
source in the directory baselliblX, where base is the top of the entire source tree. Their server
source is placed in base/server.
The procedure for finding out something about an Xlib routine is normally to search for the
routine in the Xlib code, and then figure out what it does. Sometimes the answer can be
found there. Many of the routines, however, simply place their arguments in a protocol
request and send it to the server. Then you will have to look in the server code for the
answer. To find the correct place in the server code, you will need the symbol for the proto
col request, which is the first argument in the GetReq call.
The server code is much more involved than Xlib itself. The device-dependent portions are
in basel server I ddx and the device-independent portions are in base/ server /dix. The device-
independent code should be your first stop, because it is here that protocol requests from Xlib
arrive and are dispatched to the appropriate code. Search for the protocol request symbol
you found in Xlib. It will appear in several source files. Start with the occurrence in dis-
patch.c, and try to figure out what the code does. This will require following leads to other
routines.
If you don't find a routine in basel server I dix, then it must be in the device-dependent code.
basel server I ddx has one directory in it for each brand of hardware to which a sample server
has been ported. It also contains the directories /mi, Icfb, Imfb, and Isnf, which contain rou
tines used in writing the sample server device-dependent code. Note that servers may
include code ostensibly for other machines. For example, the Sun sample server appears to
use code in several of the directories for other servers such as dec and hp.
Appendix G: Sources of Additional Information
Glossary
X uses many common terms in unique ways. A good example is "children."
While most, if not all, of these terms are defined where they are first used in
this manual, you will undoubtedly find it easier to refresh your memory by
looking for them here.
Glossary
This glossary is an expanded version of the glossary from Volume One, Xlib Programming
Manual (which in turn is based on the glossary in the Xlib-C Language X Interface, by Jim
Gettys, Ron Newman, and Bob Scheifler). As such, it contains definitions of many Xlib terms
not actually used in this book, but which you might come across in other reading, or in com
ments in code. In some cases, these Xlib terms may be used in the definitions of the Xt terms
given in this glossary. Any term used in a definition, for which another entry exists in the
glossary, is generally shown in italics.
accelerator
An accelerator is a translation that maps events in one widget to actions in an
other. The name is based on the most frequent use for this feature, namely to pro
vide keyboard shortcuts to invoke application or widget functions that would other
wise have only a pointer-driven interface.
accept_focus method
The accept Jocus method of a child is invoked when a parent offers the keyboard
focus to a child by calling XtCallAcceptFocus. This method is part of the
Core widget class.
access control list
X maintains lists of hosts that are allowed access to each server controlling a dis
play. By default, only the local host may use the display, plus any hosts specified
in the access control list for that display. This access control list can be changed
by clients on the local host Some server implementations may implement other
authorization mechanisms in addition to or instead of this one. The list can cur
rently be found in /etc/Xff. hosts where # is the number of the display, usually 0
(zero). The access control list is also known as the host access list.
action
An action is a function bound by a translation, to be invoked in response to a user
event
actions table
An actions table is an array of function pointers and corresponding strings by
which actions can be referenced in a translation table. The use of actions requires
a widget to define both an actions table and a translation table.
Glossary
active grab
A grab is active when the pointer or keyboard is actually owned by a single grab
bing client. See also graft.
ancestor
If window W is an inferior of window A, then A is an ancestor of W. The parent
window, the parent's parent window, and so on are all ancestors of the given win
dow. The root window is the ancestor of all windows on a given screen.
application context
An application context specifies a connection to a server. When an application
program has connections to multiple servers, the application context coordinates
events and their dispatching, so all connections get processed.
argument list
An argument list is used in a call to create a widget in order to "hardcode" the val
ue of widget resources, and also in calls to xt Set Values or xtGetValues. It
consists of an array of Arg structures, each consisting of a resource name and the
value to which it should be set
Athena widget
MIT distributes a set of widgets developed by MIT's Project Athena in the Athena
Widget library, Xaw. The include files for Athena widgets reside in
lusrlincludelXll under Release 3 and usr/include/Xll/Xaw under Release 4.
atom
An atom is a unique numeric ID corresponding to a string name. Atoms are used to
identify properties, types, and selections in order to avoid the overhead of passing
arbitrary-length strings over the network. See also property.
background
Windows may have a background, consisting of either a solid color or a tile pat
tern. If a window has a background, it will be repainted automatically by the
server whenever there is an Expose event on the window. If a window does not
have a background, it will be transparent. By default, a window has a background.
See also foreground.
backing store
When a server maintains, the contents of a window, the off-screen saved pixels are
known as a backing store. This feature is not available on all servers. Even when
available, the server will not maintain a backing store, unless told to do so with a
window attribute. Use the DoesBackingStores Xlib macro to determine if
this feature is supported.
496 X Toolkit Intrinsics Programming Manual
bit gravity
When a window is resized, the contents of the window are not necessarily discard
ed. It is possible to request the server (though no guarantees are made) to relocate
the previous contents to some region of the resized window. This attraction of win
dow contents for some location of a window is known as bit gravity. For example,
an application that draws a graph might request that the contents be moved into the
lower-left corner, so that the origin of the graph will still appear in the lower-left
corner. See also window gravity.
bit plane
On a color or gray scale display, each pixel has more than one bit defined. Data in
display memory can be thought of either as pixels (multiple bits per pixel) or as bit
planes (one bit plane for each usable bit in the pixel). The bit plane is an array of
bits the size of the screen.
bitmap
A bitmap is a pixmap with a depth of one bit. There is no bitmap type in XI 1. In
stead, use a pixmap of depth 1. See also pixmap.
border
A window can have a border that is zero or more pixels wide. If a window has a
border, the border can have a solid color or a tile pattern, and it will be repainted
automatically by the server whenever its color or pattern is changed or an Expose
event occurs on the window.
button grabbing
A pointer grab that becomes active only when a specified set of keys and/or buttons
are held down in a particular window is referred to as a button grab.
byte order
The order in which bytes of data are stored in memory is hardware-dependent. For
pixmaps and bitmaps, byte order is defined by the server, and clients with different
native byte ordering must swap bytes as necessary. For all other parts of the proto
col, the byte order is defined by the client, and the server swaps bytes as necessary.
callback
A callback is an application function registered with a widget by the application
using either of the calls XtAddCallback or XtAddCallbacks or through an
argument list. A widget declares one or more callback lists as resources; applica
tions add functions to these lists in order to link widgets to applications code.
change_managed method
When a parent should change its managed widgets, the change jnanaged method is
invoked, at which time a parent reorganizes its children. The change_managed
method is part of the Composite widget class.
Glossary 497
child, children
1) A widget created by xtCreateWidget is a child of the widget specified as
its parent. The parent controls the layout of its children.
2) The children of a window are its first-level subwindows. All of these windows
were created with the same window as parent A client creates its top-level win
dow as a child of the root window.
class
1) (X Toolkit) A widget's class determines what methods will be called for it and
what instance variables it has. For widget users, a widget's class is declared in the
.h file for the widget.
2) (Xlib) There are two uses of the term class in X: window class and visual class.
The window class specifies whether a window is inputOnly or Input-
Output. The visual class specifies the color model that is used by a window. See
the classes DirectColor, Grayscale, Pseudocolor, StaticColor,
StaticGray, and TrueColor. Both window class and visual class are set per
manently when a window is created.
class_initialize method
This method — part of the Core widget — is invoked when a widget class is initial
ized. That is, it is called when the first instance of a particular class is created.
client
An application program connects to the window system server by an interprocess
communication (IPC) path, such as a TCP connection or a shared memory buffer.
This program is referred to as a client of the window system server. More precise
ly, the client is the IPC path itself; a program with multiple paths open to one or
more servers is viewed by the protocol as multiple clients. X Resources are avail
able only as long as the connection remains intact, not as long as a program re
mains running. Normally the connection and the program terminate concurrently,
but the client's resources may live on if XChangeCloseDownMode has been
called.
clipping region
In many graphics routines, a bitmap or list of rectangles can be specified to restrict
output to a particular region of the window. The image defined by the bitmap or
rectangles is called a clipping region, or clip mask. Output to child windows is
automatically clipped to the borders of the parent unless subwindow_mode of
the GC is Include Inferiors. Therefore the borders of the parent can be
thought of as a clipping region.
colorcell
An entry in a colormap is known as a colorcell. An entry contains three values
specifying red, green, and blue intensities. These values are always 16-bit un
signed numbers, with zero being minimum intensity. The values are truncated or
scaled by the server to match the display hardware. See also colormap.
498 X Toolkit Intrinsics Programming Manual
colormap
A colormap consists of a set of colorcells. A pixel value indexes into the colormap
to produce intensities of Red, Green, and Blue to be displayed. Depending on
hardware limitations, one or more colormaps may be installed at one time, such
that windows associated with those maps display with true colors. Regardless of
the number of installable colormaps, any number of virtual colormaps can be creat
ed. When needed, a virtual colormap can be installed and the existing installed
colormap might have to be uninstalled. The colormap on most systems is a limited
resource that should be conserved by allocating read-only colorcells whenever pos
sible, and by selecting RGB values from the predefined color database. Read-only
cells may be shared between clients. See also colorcell, DirectColor, Gray-
Scale, Pseudocolor, StaticColor, StaticGray, and TrueColor.
Composite widget
A Composite widget is designed to manage the geometry of children; that is, a
Composite widget instance can be passed in the parent argument to xtCreate-
Widget.
connection
The communication path between the server and the client is known as a
connection. A client usually (but not necessarily) has only one connection to the
server over which requests and events are sent.
Constraint widget
The Constraint widget is a subclass of Composite. A Constraint widget has more
information about each child than a Composite widget
constraints
A Constraint widget provides a list of resources, or constraints, for its children.
The constraints give the Constraint widget information about how each child
should be layed out
containment
A window contains the pointer if the window is viewable and if the hotspot of the
cursor is within a visible region of the window or a visible region of one of its infe
riors. The border of the window is included as part of the window for containment.
The pointer is in a window if the window contains the pointer but no inferior con
tains the pointer.
coordinate system
The coordinate system has x horizontal and y vertical, with the origin (0, 0) at the
upper-left Coordinates are discrete, and in terms of pixels. Each window and pix-
map has its own coordinate system. For a window, the origin is inside the border, if
there is one. The position of a child window is measured from the origin of the par
ent to the outside corner of the child (not the child's origin).
Core widget
The Core widget is the basic class in the Toolkit All widgets that can be displayed
are subclasses of Core.
Glossary
cursor
A cursor is the visible shape of the pointer on a screen. It consists of a hotspot, a
shape bitmap, a mask bitmap, and a pair of pixel values. The cursor defined for a
window controls the visible appearance of the pointer when the pointer is in that
window.
delete_child method
The delete_child method is invoked on a parent after its child is deleted. This
method is part of the Composite widget and is usually inherited.
depth
The depth of a window or pixmap is the number of bits per pixel.
dereference
To access the contents of a pointer, you must dereference it
descendants
See inferiors.
destroy method
The destroy method is invoked when a widget has been destroyed. This method is
part of the Core widget and is used to deallocate memory and GCs.
device
Keyboards, mice, tablets, track-balls, button boxes, etc. are all collectively known
as input devices.
DirectCoIor
DirectColor is a visual class in which a pixel value is decomposed into three sepa
rate subfields for colormap indexing. One subfield indexes an array to produce red
intensity values; the second subfield indexes a second array to produce blue inten
sity values; and the third subfield indexes a third array to produce green intensity
values. The RGB (red, green, and blue) values in the colormap entry can be
changed dynamically. This visual class is normally found on high-performance
color workstations.
display
A display is a set of one or more screens that are driven by a single X server. The
Xlib Display structure contains all information about the particular display and
its screens as well as the state that Xlib needs to communicate with the display over
a particular connection. In Xlib, a pointer to a Display Structure is returned by
XOpenDisplay. In most Xt applications, the Display is part of the applica
tion context, and need not be referenced directly. If necessary, a display can be
opened directly with a call to xtOpenDisplay, and a pointer to the currently
open display can be returned by the xt Display macro.
drawable
Both windows and pixmaps may be used as destinations in graphics operations.
These are collectively known as drawables.
500 X Toolkit Intrinsics Programming Manual
encapsulation
Encapsulation is a key concept in object-oriented programming. Objects are de
fined in such a way that their internals are hidden from the programs that use them;
the only way to access an object should be through its published interfaces.
event
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 press
ing a keyboard key or clicking a mouse button generates an event; a window being
moved on the screen also generates events — possibly in other applications as well
if the movement changes the visible portions of their windows. It is the server's
job to distribute events to the various windows on the screen.
event compression
Event compression is an Xt feature that allows some events to be ignored or
repackaged before they are given to a widget This happens on the client side, rath
er than in the server.
event handler
An event handler is a function that is called by Xt when a particular event is re
ceived. Event handlers have the same purpose as translations and actions — to call
a function in response to an event — but event handlers have lower overhead and
are not user-configurable.
event mask
Events are requested relative to a window or widget The set of event types a client
requests relative to a window is described using an event mask, a bitwise OR of de
fined symbols specifying which events are desired.
The event_mask is a window attribute, which can be set in Xlib with
XSelect Input, and is also specified in calls that grab the pointer or keyboard.
The do_not_propagate_mask attribute is also an event mask, and it speci
fies which events should not be propagated to ancestor windows. In Xt, you never
need to set a window's event_mask or do_not_propogate_mask directly.
The translation manager automatically selects the required events.
event propagation
Device-related events propagate from the source window to ancestor windows un
til a window that has selected that type of event is reached, or until the event is dis
carded explicitly in a do_not_propagate_mask attribute.
event source
The smallest window containing the pointer is the source of a device-related event
expose method
When Expose events are received, the Intrinsics invoke the expose method. A
widget should perform its redisplay activities in this method. The expose meth
od is part of the Core widget class.
Glossary
exposure
Window exposure occurs when a window is first mapped, or when another window
that obscures it is unmapped, resized, or moved. Servers do not guarantee to pre
serve the contents of windows when windows are obscured or reconfigured. Ex
pose events are sent to clients to inform them when contents of regions of win
dows have been lost and need to be regenerated.
extension
Named extensions to the core protocol can be defined to extend the system. Exten
sion to output requests, resources, and event types are all possible, and expected.
Extensions can perform at the same level as the core Xlib.
font
A font is an array of characters or other bitmap shapes such as cursors. The proto
col does no translation or interpretation of character sets. The client simply indi
cates values used to index the font array. A font contains additional metric infor
mation to determine intercharacter and interline spacing.
foreground
The pixel value that will actually be used for drawing pictures or text is referred to
as the foreground. The foreground is specified as a member of a graphics context.
See also background.
frozen events
Clients can freeze event processing while they change the screen, by grabbing the
keyboard or pointer with a certain mode. These events are queued in the server
(not in Xlib) until an XAllowEvents call with a counteracting mode is given.
GC
The term GC is used as a shorthand for graphics context. See graphics context.
geometry management
A Composite parent controls its children through geometry management, thereby
manipulating the size and placement of widgets within a window on the display.
get_values_hook method
The get_yalues_hook method is invoked by the Intrinsics when someone calls xt-
Getvalues. This method is part of the Core widget class. Its role is to get the
resource values of a subpart using xtGetSubvalues.
glyph
A glyph is an image, usually of a character in a font, but also possibly of a cursor
shape or some other shape.
grab
Keyboard keys, the keyboard, pointer buttons, the pointer, and the server can be
grabbed for exclusive use by a client, usually for a short time period. In general,
these facilities help implement various styles of user interfaces. Pop-up widgets
generally make a passive grab. Server grabs are generally used only by window
managers.
502 X Toolkit Intrinsics Programming Manual
graphics context
Various information for interpreting graphics primitives is stored in a graphics con
text (GC), such as foreground pixel, background pixel, line width, clipping region,
etc. Everything drawn to a window or pixmap is modified by the GC used in the
drawing request
graphics primitive
A graphics primitive is an Xlib call that sends a protocol request to the server, in
structing the server to draw a particular shape at a particular position. The graphics
context specified with the primitive specifies how the server interprets the primi
tive.
gravity
See bit gravity and window gravity.
GrayScale
Grayscale is a visual class in which the red, green, and blue values in any given
colormap entry are equal, thus producing shades of gray. The gray values can be
changed dynamically. Grayscale can be viewed as a degenerate case of
Pseudocolor.
hint
Certain properties, such as the preferred size of a window, are referred to as hints,
since the window manager makes no guarantee that it will honor them.
host access list
See access control list.
hotspot
A cursor has an associated hotspot that defines the point in the cursor which corre
sponds to the coordinates reported for the pointer.
identifier
Each server resource has an identifier or ID, a unique value that clients use to name
the resource. Any client can use a resource if it knows the resource ID.
inferiors
The inferiors of a window are all of the subwindows nested below it the children,
the children's children, etc. The term descendants is a synonym.
inheritance (single vs. multiple)
Inheritance is the ability to obtain methods from a superclass. Multiple inheri
tance, which is not supported by Xt, would allow a class to obtain methods from
multiple unrelated superclasses.
initialize method
The initialize method is invoked when a widget is created. It initializes instance
variables and checks resource values. This method is part of the Core widget class.
Glossary
initialize_hook method
The initialize _hook method is called just after the initialize method, and is respon
sible for initializing subpart instance variables and checking subpart resource val
ues. This method is part of the Core widget class.
input focus
See keyboard focus.
InputOnly window
A window that cannot be used for graphics requests is called an InputOnly window.
InputOnly windows are invisible and can be used to control such things as cur
sors, input event distribution, and grabbing. InputOnly windows cannot have
inputOutput windows as inferiors.
InputOutput window
The normal kind of window that is used for both input and output is called an
InputOutput window. It usually has a background. InputOutput windows can
have both InputOutput and InputOnly windows as inferiors.
input manager
Control over keyboard input may be provided by an input manager client. This job
is more often done by the window manager.
insert child method
A widget's insert child method is invoked when someone specifies it as a parent in
an xtCreateWidget call. This method is part of the Composite widget class.
This method is usually inherited.
instance
An instance is a particular widget that has a class. An instance ID is returned by
XtCreateWidget.
instantiate
When you instantiate a class, you create an instance of it
Intrinsics
The X Toolkit defines functions and datatypes called Intrinsics.
key grabbing
A keyboard grab that occurs only when a certain key or key combination is pressed
is called a key grab. This is analogous to button grabbing. Both are forms of pas
sive grabs.
keyboard focus
The keyboard focus is the window that receives main keyboard input. By default
the focus is the root window, which has the effect of sending input to the window
that is being pointed to by the mouse. It is possible to attach the keyboard input to
a specific window with XSetlnputFocus. Events are then sent to the window
independent of the pointer position.
504 X Toolkit Intrinsics Programming Manual
keyboard grabbing
All keyboard input is sent to a specific window (or client, depending on
owner_e vents) when the keyboard is grabbed. This is analogous to mouse
grabbing. This is very much like a temporary keyboard focus window.
keycode
A keycode is a code in the range 8-255 inclusive that represents a physical or logi
cal key on the keyboard. The mapping between keys and keycodes cannot be
changed, and varies between servers. A list of keysyms is associated with each
keycode. Programs should use keysyms instead of keycodes to interpret key
events.
keysym
A keysym is a #def ine'd symbol which is a portable representation of the sym
bol on the cap of a key. Each key may have several keysyms, corresponding to the
key when various modifier keys are pressed. You should interpret key events ac
cording to the keysym returned by XLookupString or XLookupKeysym,
since this translates server-dependent keycodes into portable keysyms.
listener
A listener style window manager sets the keyboard focus to a particular window
when that window is clicked on with a pointer button. This is the window manager
style used with the Apple Macintosh™. This style is also referred to as click-to-
type.
loose binding
A loose binding refers to the use of an asterisk (*) wildcard in a resource specifica
tion to indicate that the specification applies to zero or more hierarchy levels of
widget instances or classes.
mapping
A window is said to be mapped if an XMapWindow or XMapRaised call has
been performed on it Unmapped windows are never viewable. Mapping makes a
window eligible for display. The window will actually be displayed if the follow
ing conditions are also met*
1) All its ancestors are mapped.
2) It is not obscured by siblings.
3) The window manager has processed the request, if for a top-level window.
message
In object-oriented programming, a message is used to invoke an object's methods.
In Xt, you can think of the Intrinsics functions used to create, destroy, and set re
source values as sending messages to widget classes.
method
A method is a function internal to widget class that the Intrinsics invoke under
specified conditions. Methods are provided as pointers to functions in widget class
records.
Glossary 50S
modal pop up
A modal pop up is a pop-up widget that grabs the pointer when a mouse button is
pressed in a particular window.
modeless pop up
A modeless pop up is a pop-up widget that doesn't grab the pointer on a mouse but
ton.
modifier keys
Shift, Control, Meta, Super, Hyper, Alt, Compose, Apple, Caps Lock, Shift Lock,
and similar keys are called modifier keys.
monochrome
A monochrome screen has only two colors: black and white. Monochrome is a
special case of the StaticGray visual class, in which there are only two color-
map entries.
non-maskable event
A non-maskable event is an event that is not selected by the application or widget
via an event mask, but is instead sent automatically by the X server. The non
maskable events are MappingNotify, ClientMessage, Selection-
Clear, SelectionNotify, and SelectionRequest.
object
In object-oriented programming, an object is a self-contained program unit con
taining both data and procedures.
object-oriented programming
Object-oriented programming is a way of defining classes and creating instances
so that objects respond to messages with methods. One of its major benefits is the
encapsulation of code.
obscure
Window A obscures window B if A is higher in the global stacking order, and the
rectangle defined by the outside edges of A intersects the rectangle defined by the
outside edges of B. See occlude.
occlude
Window A occludes window B if both are mapped, if A is higher in the global
stacking order, and if the rectangle defined by the outside edges of A intersects the
rectangle defined by the outside edges of B. The (fine) distinction between the
terms obscures and occludes is that for obscures, the windows have to be mapped,
while for occludes they don't. Also note that window borders are included in the
calculation. Note that input Only windows never obscure other windows but
can occlude other windows.
padding
Some bytes are inserted in the data stream to maintain alignment of the protocol re
quests on natural boundaries. This padding increases ease of portability to some
machine architectures.
506 X Toolkit Intrinsics Programming Manual
parent
A parent is a Composite widget instance specified as the parent argument in xt-
CreateWidget. Parents control a child's layout
parent window
Each new window is created with reference to another previously-created window.
The new window is referred to as the child, and the reference window as the par
ent. If C is a child of P, then P is the parent of C. Only the portion of the child that
overlaps the parent is viewable.
passive grab
A passive grab is a grab that will become active only when a specific key or button
is actually pressed in a particular window.
pixel value
A pixel value is an N-bit value, where N is the number of bit planes used in a par
ticular window or pixmap. For a window, a pixel value indexes a colormap to de
rive an actual color to be displayed. For a pixmap, a pixel value will be interpreted
as a color in the same way when it has been copied into a window.
pixmap
A pixmap is a three-dimensional array of bits. A pixmap is normally thought of as
a two-dimensional array of pixels, where each pixel can be a value from 0 to
(2N -1), where N is the depth (z-axis) of the pixmap. A pixmap can also be thought
of as a stack of N bitmaps. A pixmap may have only one plane. Such a pixmap is
often referred to as a bitmap, even though there is no bitmap type in XI 1.
plane
When a pixmap or window is thought of as a stack of bitmaps, each bitmap is
called a plane.
plane mask
Graphics operations can be restricted to affect only a subset of bit planes in a draw-
able. A. plane mask is a bit mask describing which planes are to be modified.
pointer
The pointer is the pointing device currently attached to the cursor, and tracked on
the screens. This may be a mouse, tablet, track-ball, or joystick.
pointer grabbing
A client can actively grab control of the pointer, causing button and motion events
to be sent to that client rather than to the client the pointer indicates.
pointing device
A pointing device is typically a mouse or tablet, or some other device with effec
tive two-dimensional motion, that usually has buttons. There is only one visible
cursor defined by the core protocol, and it tracks whatever pointing device is cur
rently attached as the pointer.
Glossary 507
pop up
A pop up is a widget outside the normal parental hierarchy of geometry manage
ment It is a child window of the root window that is popped up temporarily to
give the user a piece of information, or to get some information from the user.
post-order traversal
When a tree structure is subject to post-order traversal, its root is visited last; for
example, a function might process the left descendant, the right descendant, and
then the root
pre-order traversal
When a tree structure is subject to pre-order traversal, its root is visited first; for
example, a function might process the root, and then the left and right descendant
private header file
A private header file contains the internal class definitions of a widget For ex
ample, the Label widget's internal class definitions are contained in the private
header file LabelP.h. This file is included only in the widget .c file of this class and
any subclasses, never in the application.
property
Windows may have associated properties, each consisting of a name, a type, a data
format, and some data. The protocol places no interpretation on properties; they
are intended as a general-purpose data storage and intercommunication mechanism
for clients. There is, however, a list of predefined properties and property types so
that clients might share information such as resize hints, program names, and icon
formats with a window manager via properties. In order to avoid passing arbitrary-
length property-name strings, each property name is associated with a correspond
ing integer value known as an atom. See also atom.
PseudoColor
PseudoColor is a visual class in which a pixel value indexes the colormap entry to
produce independent red, green, and blue values. That is, the colormap is viewed
as an array of triples (RGB values). The RGB values can be changed dynamically.
public header file
A public header file contains the declarations (e.g., class widget pointer) necessary
to use a widget For example, labelwidgetClass declarations are contained
in the public header file label.h. This header file is included in the widget .c file
and in the application source file.
quark
A quark is an integer ID that identifies a string. In the context of Xt, this string is
usually a name, class, or type string for the resource manager. Like atoms and re
source IDs, quarks eliminate the need to pass strings of arbitrary length over the
network. The quark type is XrmQuark, and the types XrmName, XrmClass,
and XrmRepresentation are also defined to be XrmQuark.
505 X Toolkit Intrinsics Programming Manual
query geometry method
Parents call Xt Query Geometry to invoke the child's query geometry method to
find out a child's preferred geometry. This method is part of the Core widget class.
raise
Changing the stacking order of a window so as to occlude all sibling windows is to
raise that window.
real estate
The window management style characterized by the input being sent to whichever
window the pointer is in is called real-estate-driven. This is the most common
style of input management used in X.
realize method
The realize method creates a window on the display and is part of the Core widget
class.
rectangle
A rectangle specified by [x,y,w,h] has an (infinitely thin) outline path with cor
ners at [x,y], [x+w,y], [x+w,y+h], and [x,y+h]. When a rectangle is filled,
the lower-right edges are not drawn. For example, if w=h=0, nothing would be
drawn when drawing the rectangle, but a single pixel when filling it. For w=h=l, a
single pixel would be drawn when drawing the rectangle, four pixels when filling
it
redirect
Window managers (or other clients) may wish to enforce window layout policy in
various ways. When a client attempts to change the size or position of a window,
or to map one, the operation may be redirected to the window manager, rather than
actually being performed. Then the window manager (or other client that redirect
ed the input) is expected to decide whether to allow, modify, or deny the requested
operation before making the call itself. See also window manager.
reparenting
The window manager often reparents the top-level windows of each application in
order to add a tide bar and perhaps resize boxes. In other words, a window with a
title bar is inserted between the root window and each top-level window. See also
save-set.
reply
Information requested from the server by a client is sent back to the client in a
reply. Both events and replies are multiplexed on the same connection with the re
quests. Requests that require replies are known as round-trip requests, and, if pos
sible, should be avoided since they introduce network delays. Most requests do not
generate replies. Some requests generate multiple replies. Xt caches frequently-
used data on the client side of the connection in order to minimize the need for
round-trip requests. See Volume Zero, X Protocol Reference Manual, for a de
tailed discussion of the X protocol.
Glossary
509
representation type
A symbolic constant beginning with XtR, which is defined in <Xll/StringDefs.h>
or an application or widget header file, and which is used to define the data type of
a resource. Xt automatically converts between resource settings, which are strings,
and various representation types.
request
A command to the server is called a request. It is a single block of data sent over
the connection to the server. See Volume Zero, X Protocol Reference Manual, for
a detailed discussion of the X protocol.
resize method
The resize method of a widget is called when the widget's parent has changed its
size. This method is part of the Core widget class. In composite widgets, this
method calculates a new layout for the children. In simple widgets, this method re
calculates instance variables so that the expose method can redraw the widget
properly.
resource
1) A widget or application variable whose value can be set by the user or applica
tion programmer via the Resource Manager.
2) In the X Protocol and server documentation, windows, pixmaps, cursors, fonts,
graphics contexts, and colormaps are known as resources. They all have unique
identifiers (IDs) associated with them for naming purposes.
resource database
The resource database is the collection of possible places where resource specifi
cations can be made. The most important of these are the application-defaults file,
where the programmer specifies resource defaults, the RESOURCE_MANAGER server
property, which the user can set with xrdb, and the Xdefaults file in the user's
home directory, where he or she specifies local resource preferences.
Resource Manager
The Resource Manager is a part of Xlib that merges a database consisting of sever
al ASCII files, a server property, and values hardcoded by the application, and de
termines a unique value for each resource of each widget It resolves conflicts be
tween multiple settings for the same resource according to its internal precedence
rules, and provides the widget or application with the resulting value.
resource setting
A resource setting is the actual value of a resource variable.
570 X Toolkit Intrinsics Programming Manual
resource specification
A resource specification describes a "pathname" to a widget resource, using widg
et class and/or instance names, resource class or instance names, and optional wild
cards. For example, the resource specification:
xbox. box. quit .label: Quit
specifies that the label resource of the quit widget, which is contained in the box
widget in the xbox application, should be set to "Quit." The specification:
* Command. background: blue
which uses wildcards and widget classes, specifies that the background (color) re
source of all Command widgets in any application should be set to "blue." It is up
to the Resource Manager to resolve differences between resource specifications,
which may have varying levels of specificity in the various locations that make up
the resource database.
RGB values
See color cell.
root
The root of a window, pixmap, or graphics context (GC) is the same as the root
window of whatever drawable was specified in the call to create the window, pix
map, or GC. These resources can be used only on the screen indicated by this win
dow. See root window.
root window
Each screen has a root window covering it It cannot be reconfigured or unmapped,
but otherwise acts as a full-fledged window. A root window has no parent
round-trip request
A request to the server that generates a reply is known as a round-trip request. See
reply.
save-set
The save-set of a client is a list of other clients' windows which, if they are infer
iors of one of the client's windows at connection close, should not be destroyed,
and which should be reparented and remapped if the client is unmapped. Save-sets
are typically used by window managers to avoid lost windows if the manager
should terminate abnormally. See reparenting for more background information.
scan line
A scan line is a list of pixel or bit values viewed as a horizontal row (all values
having the same y coordinate) of an image, with the values ordered by increasing x
coordinate values.
scan line order
An image represented in scan line order contains scan lines ordered by increasing y
coordinate values.
Glossary 511
screen
A server may provide several independent screens, which may or may not have
physically independent monitors. For instance, it is possible to treat a color moni
tor as if it were two screens, one color and the other black and white or to have two
separate color and monochrome screens controlled by one server. There is only a
single keyboard and pointer shared among the screens. A Screen structure con
tains the information about each screen and the list is a member of the Display
structure.
scrollbar
A scrollbar is an area on a window that allows a user to view different portions of a
window's information by scrolling, or moving.
selection
Selections are a means of communication between clients using properties and
events. From the user's perspective, a selection is an item of data which can be
highlighted in one instance of an application and pasted into another instance of
the same or a different application. The client that highlights the data is the owner,
and the client into which the data is pasted is the requestor. Properties are used to
store the selection data and the type of the data, while events are used to synchro
nize the transaction and to allow the requestor to indicate the type it prefers for the
data and to allow the owner to convert the data to the indicated type if possible.
server
The server provides the basic windowing mechanism. It handles IPC connections
from clients, demultiplexes graphics requests onto the screens, and multiplexes in
put back to the appropriate clients. It controls a single keyboard and pointer and
one or more screens that make up a single display.
server grabbing
The server can be grabbed by a single client for exclusive use. This prevents pro
cessing of any requests from other client connections until the grab is complete.
This is typically a transient state for such tasks as rubber-banding, or to execute re
quests indivisibly.
set_values method
The Intrinsics invoke a widget's set_values method when one of the widget's re
source values is changed. This method should return TRUE or FALSE to indicate
whether the widget's expose method should be invoked.
set_values_almost method
The set_values_almost method is invoked when a parent rejects a widget's geome
try request, but the parent sends back a compromise. This method is part of the
Core widget class.
set_values_hook method
A widget can provide a set_values_hook method to allow the application to set re
sources of subparts.
X Toolkit Intrinsics Programming Manual
sibling
Children of the same parent window are known as sibling windows.
spring-loaded pop up
When a button press triggers a pop up, the pop up is called a spring-loaded pop up.
stacking order
Sibling windows may stack on top of each other, obscuring lower windows. This is
similar to papers on a desk. The relationship between sibling windows is known as
the stacking order. The first window in the stacking order is the window on top.
StaticColor
The StaticColor visual class represents a multiplane color screen with a predefined
and read-only hardware colormap. It can be viewed as a degenerate case of
Pseudocolor. See PseudoColor.
StaticGray
The StaticGray visual class represents a multiplane monochrome screen with a
predefined and read-only hardware colormap. It can be viewed as a degenerate
case of Grayscale, in which the gray values are predefined and read-only. Typi
cally, the values are linearly increasing ramps. See Grayscale.
stipple
A stipple is a single plane pixmap that is used to tile a region. Bits set to 1 in the
stipple are drawn with a foreground pixel value; bits set to 0, with a background
pixel value. The stipple and both pixel values are members of the GC.
status
Many Xlib functions return a status of TRUE or FALSE. If the function does not
succeed, its return arguments are not disturbed.
subclass
A widget subclass has its own features plus many of the features of its superclasses.
For example, since Composite is a subclass of Core, Composite has all the fields in
Core plus its own unique fields. A subclass can inherit or replace most superclass
features.
superclass
One widget is a superclass of a second widget when the second widget includes the
first, or the Core widget is a superclass of the Composite widget because the Com
posite widget's definition depends on, or includes, the Core widget
tight binding
A tight binding refers to the use of a dot (.) in a resource specification to indicate
that the widget class or instance on the right side of the dot is a child of the widget
whose class or instance name is on the left side of it
tile
A pixmap can be replicated in two dimensions to tile a region. The pixmap itself is
also known as a tile.
Glossary 513
time
A time value in X is expressed in milliseconds, typically since the last server reset.
Time values wrap around (after about 49.7 days). One time value, represented by
the constant CurrentTime, is used by clients to represent the current server
time.
top-level window
A child of the root window is referred to as a top-level window.
translation
A translation maps an event or event sequence into an action name. Once a trans
lation is installed in a widget, the named action function will be invoked when the
specified event seqeunce occurs in the widget Translations are specified as ASCII
strings.
translation table
A translation table lists one or more translations.
TrueColor
The TrueColor visual class represents a high-performance multiplane display with
predefined and read-only RGB values in its hardware colormap. It can be viewed
as a degenerate case of DirectColor, in which the subfields in the pixel value
directly encode the corresponding RGB values. Typically, the values are linearly
increasing ramps. See DirectColor.
type property
A type property is used to identify the interpretation of property data. Types are
completely uninterpreted by the server; they are solely for the benefit of clients.
viewable
A window is viewable if it and all of its ancestors are mapped. This does not imply
that any portion of the window is actually visible, since it may be obscured by oth
er windows.
visible
A region of a window is visible if someone looking at the screen can actually see it;
that is, the window is viewable and the region is not obscured by any other win
dow.
visual
The specifications for color handling for a window, including visual class, depth,
RGB/pixel, etc., are collectively referred to as a visual, and are stored in a structure
of type visual.
visual class
Visual class refers to DirectColor, Grayscale, Pseudocolor,
StaticColor, StaticGray, or TrueColor. It is a definition of the color-
map type but not its depth.
514 X Toolkit Intrinsics Programming Manual
widget
The basic object in a toolkit, a widget includes both code and data, and can there
fore serve as an input or output object.
window gravity
When windows are resized, subwindows may be repositioned automatically by the
server, relative to an edge, corner, or center of the window. This attraction of a
subwindow to some part of its parent is known as window gravity. Window gravity
is a window attribute. See also bit gravity.
window manager
The user manipulates windows on the screen using a window manager client. The
window manager has authority over the arrangement of windows on the screen, and
the user interface for selecting which window receives input. See also redirect.
XYPixmap
The data for an image is said to be in XYPixmap format if it is organized as a set of
bitmaps representing individual bit planes. This applies only to the server's inter
nal data format for images. It does not affect normal programming with pixmaps.
ZPixmap
The data for an image is said to be in ZPixmap format if it is organized as a set of
pixel values in scan line order. This applies only to the server's internal data for
mat for images. It does not affect normal programming with pixmaps.
zoomed window
Some applications have not only a normal size for their top-level window and an
icon, but also a zoomed window size. This could be used in a painting program
(similar to the MacPaint™ fat bits). The zoomed window size preferences can be
specified in the window manager hints.
Glossary 515
Master Index
77?e Master Index combines Volumes Four and Five index entries, making it
easy to look up the appropriate references to a topic in either volume. PM
refers to the X Toolkit Intrinsics Programming Manual. RM refers to the X
Toolkit Intrinsics Reference Manual.
Index
The Master Index combines Volumes Four and Five index entries, making it easy to look up
the appropriate references to a topic in either volume. PM refers to the X Toolkit Intrinsics
Programming Manual. RM refers to the X Toolkit Intrinsics Reference Manual.
The alphabetical sequence of the index is highlighted by the bolding of primary entries.
# directive (see translations)
! (see modifiers)
- options (see options)
accelerators, about PM:53, 150, 189, 205-211,
253, 495
(see also display _accelerator)
(see also XtlnstallAccelerators)
(see also XtlnstallAllAccelerators)
compiling accelerator table PM:210; RM:201
defining default table in code PM:210
display_accelerator method PM:21 1 ; RM:320
event propagation PM:207
for gadgets PM:371
for menus PM:367,371
installing PM:205; RM:166-168; in multiple
widgets PM:209
not usable in gadgets PM:373
parsing (see compiling)
translations; conflicts with PM:209; transla
tion table limitations PM:206
accept_focus method, about PM:154, 389, 391,
495
AcceptFocusProc RM:328
access control list PM:495
actions PM:30, 495
(see also XtAddActions, XtAppAddActions)
actions, about PM:27, 39; RM:7, 428
action proc; format PM:46
actions table, PM:495; adding PM:43-45;
RM:42 -43, 60-61; declaring/registering
with Resource Manager RM:60-61;
example PM:45; format PM:45; XtAc-
tionProc RM:270-272
adding; from application PM:43; in widget
itself PM: 184-1 86
arguments to PM:113
contrasted with callbacks PM:46, 1 12
defined in widget implementation file
PM: 145-147
gadget parent; example PM:380-381
in gadgets PM:373
naming conventions PM:42
passing arguments to PM:113
registering (see adding)
using event data PM:222; example
RM:27 1-272
widget instance pointer PM:185
widget/application conflicts PM:146
(see also XtAddActions, XtAppAddActions)
aliasing font names PM:443
AlmostProc RM:328
Alt key (see modifiers)
ancestor PM:496
anonymous ftp PM:34
application contexts, about PM:97-99,
393-396, 496
Index
adding display RM:135-136; XtOpenDisplay
PM:98,396;RM:195-196
creating RM:115-116
destroying and closing displays RM:127
explicit PM:98
main loop for multiple PM:394
multiple PM:394
(see also XtCreateApplicationContext)
(see also XtDestroyApplicationContext)
(see also XtWidgetToApplicationContext)
application, application resources PM:80; data
structure PM:81; retrieving values PM:85
application-defaults file, about PM:32, 36,
245; directory PM:36; naming conven
tions PM:32, 36
applicationShellWidgetClass PM:270;
RM:346-353
Arg structure PM:92
argc PM:33,91,272
ArgList (see argument lists)
ArgsProc RM:327
ARGSUSED PM:42
arguments, argument lists; about PM:92, 496;
constructing/modifying dynamically
RM:232-233; creating PM:92; creating
dynamically PM:93; creating with
XtSetArg PM:93-94; example PM:92-93;
merging ArgList RM:186; XtMergeAr-
gLists RM:186
argument styles PM:90
command line RM:13
to actions PM:113, 124
to type converters PM:259-260
argv PM:33,91,272
array (see also XtNumber)
allocating RM:105
elements, determining number RM:192
(see also XtCalloc)
aspect ratio PM:274
Athena widgets, about PM:17, 496
Box PM:66; RM:357-358
Command PM:19, 40-43, 47, 65; RM:359-362
Dialog PM:71, 75, 340-341; RM:363-364
Form PM:68-69, 325-340; RM:365-367
Grip PM:66; RM:368-369
inheritance among PM:18
Label PM: 19, 36, 240; RM:370-372
List RM:373-377
MenuButton PM:367
Scroll PM:15, 39, 42, 66, 109; RM:378-382
Simple PM:19
SimpleMenu PM:349, 367-371, 378-381
Template RM:383-390
Text PM:75, 150. 264, 280; RM:391-402
Viewport PM:107, 310, 314; RM:403-404
Vpaned PM:66
VPaned PM:310
Vpaned RM:405-408
atoms, about PM:288, 496
obtaining; example PM:29 1,292
predefined PM:291
standard PM:299
augmenting translations PM:48
B
background PM:53, 496
background processing PM:23 1 ; RM:323-324
pixmap PM:53
window attribute PM:156
backing store PM:257, 496
window attribute PM:156
binding, tight vs. loose (resources) PM:244
bit gravity PM:496
bit plane PM:497
bit_gravity window attribute PM:156
bitmap PM:279,497
bitmap files PM:104
BitmapEdit widget, about PM:66, 104, 177,
314,461
BitmapEditClassRec, example PM:138-139
BitmapEditRec, example PM:139
bitwise RM:50,95
Boolean values PM:253
border PM:497
border crossing events RM:454-459
border width PM:306
border window attribute PM:156
bounding box PM:171;RM:295
Box widget PM:21, 61-71,206-211,351-358
examples PM:61-66
geometry management RM:357-358
resources RM:357-358
BulletinBoard widget PM:409
ButtonPress events PM:196, 353; RM:439-441
UuttonRelea.se events PM:196, 353;
RM:439-441
buttons (see also command buttons)
grabbing PM:497
mapping RM:477
byte order PM:497
520
X Toolkit Intrinsics Programming Manual
caching, old size PM:179
standard atoms PM:299
type conversions PM:260
Xmu; initializing PM:300
callbacks, about PM:26, 30, 39, 497; RM:6,
330, 429
adding PM:40, 42; more than one at a time
PM:80; to callback list RM:46-47; to call
back resource RM:44-45
arguments to PM:42
callback list, about PM:79, RM:6; deleting
method RM:219; deleting method list
RM:220; determining status RM:160;
executive methods RM:104; popping
down widget RM:102-103; popping up
widget RM:98-101; XtCaUbackExclusive
RM:98-99; XtCaUbackNone RM:100;
XtCallbackNonexclusive RM:101;
XtCallbackPopdown RM: 102-103; XtCall-
Callbacks RM:104; XtHasCallbacks
RM:160; XtRemoveCallback RM:219;
XtRemoveCallbacks RM:220
contrasted with actions PM:46
format PM:42
naming conventions PM:42
passing data PM:77-79
pop-up functions PM:79
procedure RM279-280
(see also XtAddCallback, XtCallbackProc)
(see also XtTimerCallbackProc)
Caption widget, about PM:409
cascading pop ups, about PM:345-347,
362-367
example PM:363-365
case converter PM:200
registering RM:216
(see also XtRegisterCaseConverter)
chained methods (see inheritance)
change_managed method PM:306-308, 319,
497; RM:340
in constraint widgets PM:338-339
CirculateNotify events RM:442
CirculateRcqucst events RM:443
class, about PM:18,498
class name; defined in Core class part PM:150
class part PM:137; combining into class
record PM:138; lack of new fields
PM:138
class record PM:136; allocating storage
PM:140; BitmapEdit widget PM:138-139;
contents PM:136
class_initialize method PM:153, 258, 381,
498;RM:331
class jpart_init method PM:153, 331; RM:331
hierarchy (see widget classes); Athena widgets
PM:153; gadgets PM:375
structures PM:136-162
subclass; about RM:14
client, about PM:6, 498
ClientMessage events RM:444-445
client-server model PM:6
clipping region PM:498
color PM:53, 56, 120, 156-158, 253-254, 276
co lor names PM:433
colorcell, about PM:436, 498; read-only
PM:438; read/write PM:438; shared
PM:437
colormap, about PM:53, 436, 498; installing
PM:276; window attribute PM:156
ColormapNotify events RM:446
determining available PM:436
displaying PM:436
false PM:277
hexadecimal specification PM:434
RGB model PM:435
specifying PM:433
command buttons PM:404, 406, 417;
RM:359-362
command line options (see options)
compiling PM:34
Command widget PM:206-210, 353-359, 362,
366, 404-406, 417; RM:359-362
creating RM:362
destroying RM:362
resources RM:359-361
compiling Xt PM:34
composite widgets,
as parent and child PM:320
change_managed method RM:340
class, about PM:16, 21, 137; XtNinsertPosi-
tion resource PM:324
composite widget class; about PM:61
delete_child method RM:340
general purpose PM:409, 421
geometry_manager method RM:340-341
insert_child method RM:339-340
insert_position method RM:342
importance PM:408
initial size PM:309
inserting children PM:323
menus and control areas PM:418
ordering method; XtOrderProc RM:310
reasons for writing PM:305
resources (see resources)
Index
521
subclass; XtlsComposite RM:169
using within other widgets PM:306
compound widgets PM:340, 341
com prcss_exposu res event filter PM:172
compression filters (see event filters)
conditional compilation PM:36
ConfigureNotify events RM:447-448
ConfigureRequest events RM:449-450
connection PM:499
constraint widgets, about PM: 67, 305, 499;
RM: 16, 343-345
class, about PM:22, 137; refiguring child
locations PM:333-335
constraint class part PM:329
constraint management PM:325-340
constraint methods; change_managed
PM:338; set.values PM:338
constraint_destroy method RM:345
constraint_initialize method RM:345
destroy method PM:329
geometry _manager method PM:332
initialize method PM:329
part structure PM:327
resize method PM:336
resources PM:327, RM:343-345; example
PM:68, 69
set_values method RM:343
(see also XtlsConstraint)
containment PM:499
conventions, action function names PM:42
application-defaults file PM:32, 36
callback function names PM:42
font naming PM:439
Xtlnherit constants PM:156
function typedef naming PM:148
gadget internals PM:375
instance variables order PM:140
keysym naming PM:195
public function names PM:1 14, 449
resource; class PM:144; names PM:144;
representation types PM:144; resource
names PM:240
widget PM: 449-450; internals PM:136;
source file names PM:136; structure decla
rations PM:140, 162
converters PM:25 1-264
color name to pixel value PM:120, 253, 276
Convert.h PM:260
filename to pixmap PM:257
fontname to font PM:253
fontname to font struct PM:253
function pointer to callback list PM:258
int to Boolean PM:254
int to Dimension PM:254
int to float PM:254
int to font PM:254
int to pixel PM:254
int to pixmap PM:254
int to Position PM:254
int to short PM:254
int to unsigned char PM:254
inttoXColor PM:254
invoking directiy PM:261
Pixel to XColor PM:254
registering RM:48, 62-64; case converter
RM:216
string to accelerator table PM:253
string to boolean PM:253
string to cursor PM:253, 257
string to Dimension PM:253
string to Display PM:253
string to file descriptor PM:253
string to float PM:253
string to int PM:253
string to orientation mode PM:257
string to Position PM:253
string to short PM:253
string to translation table PM:253
string -to -justify mode PM:257
widget name to widget ID PM:257
widgets (R2 to 3) PM:453
writing a converter PM:262-264
XColor to Pixel PM:254
(see also XtConvert, XtDirectConvert)
coordinate system PM:3, 499
Core
Core class part fields
accept_focus method, PM:154, 389, 391, 495;
callback_private PM:151; class_initialize
method PM:153, 258, 381, 498; RM:331;
class_inited PM:150; class_part_init
method PM:153,331;RM:331;
class_name PM:150; compress_enterleave
PM:150; compress_exposure PM:150;
compress_motion PM:150; destroy method
PM:154, 165, 183, 500; RM:332; dis-
play_accelerator field PM:150; extension
PM:151; get_values_hook PM:150; ini-
tiaUze_hook PM: 150; initialize method
RM:328-329, 330-331; query_geometry
methodPM:154, 165, 180-182,306,321,
508; RM:336-337; reaUze method realize
method PM:153, 274, 310, 315, 509;
RM:331-332;set_values_hook PM:150;
superclass PM:149; tm_table PM:150;
version PM:151; visible_interest PM:150;
522
X Toolkit Intrinsics Programming Manual
widget_size PM:150; xnn_clas PM:150;
resize method PM:154, 165, 177-180,306,
309, 316, 336-337, 380, 510; RM:333;
set_values method PM:154, 165-166,
174-176, 311-312, 315, 512; RM:319,
334-335, 343
Core class part initializing; example
PM: 148-149
Core class structure; compress_exposures field
PM:172,RM:297; in gadgets PM:375
Core widget class (see also XtExposeProc);
XtN (see resources)
Core widget class PM:17, 19, 52, 137, 499;
RM:327-337; class pointer PM:119;
class_initialize method RM:331;
class_part_initialize method RM:331;
compress_enterleave field PM:234; com-
press_exposure field PM:234; com-
press_motion field PM:234; destroy
method RM:332; display _accelerator
method RM:336; drawing into from appli
cation PM:117, 118, 119; expose method
PM:171-172; RM:296, 332-333; get_val-
ues_hood method RM:335; hidden superc
lasses PM:155; initialize method
RM:328-329, 330-331; initialize_hook
method RM:336; instance default size
PM:119; methods RM:330; query _geome-
try method RM:336-337; reaUze method
RM:331-332; resize method RM:333;
resources PM:52; set_values method
RM:334-335; set_values_almost method
RM:335; set_values_hood method
RM:335; superclasses PM:374; visi-
ble_interest field PM:230; widgetClass
class pointer PM:119
CoreClassPart structure PM:139
CorePart structure PM:139
instance record; height field PM:308; width
field PM:308
instance; setting size PM:119
counter incrementing inside XtSetArg PM:51
CreateNotify events RM:45 1-452
Ctrl key (see modifiers)
cursor PM: 157, 253,499
cursor window attribute PM:157
cut and paste (see selections)
D
data types RM:423
database (see also XtDatabase); obtaining for
display RM:126
DECNet PM:280
decoration PM:3 1,279
default size PM:180
delete_child method PM:306, 323-324, 500;
RM:340
depth PM:53, 169, 500
dereference PM:500
descendants PM:500
destroy method PM:154, 165, 183, 500;
RM:332
DestroyNotify events RM:453
details in translations (see translations)
device PM:500
dialog boxes PM:371
cascading PM:371
grabs in PM:371
without grabs PM:371
Dialog widget RM:363-364
adding children RM:364
creating RM:364
destroying RM:364
removing children RM:364
resources RM:363-364
DirectColor PM:500
directories, font PM:438
display (see also XtDisplaylnitialize)
about PM:6, 500
adding; XtOpenDisplay RM:195-196
closing RM:108
connecting to multiple PM:396
depth PM:436
DISPLAY environment variable PM:53
lists PM:171;RM:295
pointer, returning for widget RM:134
display_accelerator method, (see also
XtStringProc); PM:211; RM:320, 336
initializing RM: 135-136
(see also XtCloseDisplay)
distributed processing, about PM:7
DoesBackingStore Xlib macro PM:156
DoesSaveUnders Xlib macro PM:156
double-clicks PM:43,201
downward chaining PM:152
drawing, about PM: 119-120, 140, 150-152,
165, 170-174
after Expose event PM:153
bitmap cells PM:161
coordinate system PM:3
Index
523
due to set_values method changes PM:175
in expose method PM:166
into Core widget PM:117-119
window attributes PM:156-157
drop-down menu (see menus)
elements (see array)
encapsulation PM:29, 500
enter/leave compression PM:234
EnterNotify events PM: 195-196, 234, 353;
RM:454-459
EnterWlndow events PM:216
environment variables, DISPLAY PM:53
XAPPLRESDIR PM:245
XENVIRONMENT PM:245
errors, error database; obtaining RM:74, 75-77,
144; XtAppGetErrorDatabase RM:74,
145; XtAppGetErrorDatabaseText
RM:75-77, 144
error handling PM:91,93; and application
contexts PM:387; calling error resource
database PM:386; caUing fatal error han
dler RM:71-73, 85-86, 137-139, 234; .XF2
listing RM:491
string conversion error message RM:248
events, event loop (see main loop)
events (see also exposure)
(see also XtDispatchEvent)
(see also XtMainLoop, XtNextEvent)
about PM:10, 191,501;RM:7
accessing specific data RM:437
as argument of action PM:46
border crossing RM:454-459
ButtonPress RM:439-441
ButtonRelease RM:439-441
cancelling source RM:224
CirculateNotify RM:442
CirculateRequest RM:443
CUentMessage RM:444-445
ColormapNotify RM:446
ConfigureNotify RM:447-448
ConfigureRequest RM:449-450
CreateNotify RM:45 1-452
DestroyNotify RM:453
dispatching handlers RM:133
EnterNotify PM:234; RM:454-459
EnterWindow PM:216
event compression PM:501
event data; using in an action PM:222
event filters PM: 150, 234
event handlers, about PM:28, 30, 215-220,
501;RM:7; adding PM:216; dispatching
RM:133; for nonmaskable events
PM:219-220; procedure RM:293-294,
304-305; raw PM:220; reasons to use
PM:216; registering RM:49-50; register
ing raw RM:56-57; removing
RM:221-222; removing raw RM:225-226;
XtAddEventHandler RM:49-50; XtAdd-
RawEventHandler RM:56-57;
XtEventHandler RM:293-294; Xdn-
putCallbackProc RM:304-305; XtRemove-
EventHandler RM:221-222; XtRemove-
RawEventHandler RM:225-226
event masks, about PM:216, 501; RM:424;
retrieving RM:95-96; table PM:216;
XtBuildEventMask RM:95-96
event members; common RM:438
event processing RM:84; XtAppProcessEvent
RM:84
event propagation PM:501
event queue PM:234; peeking PM:234
event sequences; sharing initial events
PM:204; sharing noninitial events PM:204
event source PM:501
event structure PM:221
event-driven programming, about PM:10-11
event_mask window attribute PM:157
expose PM:10
Expose PM:23, 153, 235; RM:460-461
Focusln PM:216; RM:462-467
FocusOut PM:216;RM:462-467
frozen event PM:502
GraphicsExpose PM:193, 220; RM:468-469
GravityNotify RM:470
in action routines PM:124
in gadgets PM:373
input events; XtRemovelnput RM:224
KeymapNotify RM:471
KeyPress RM:472-474
KeyRelease RM:472-474
LeaveNotify PM:234; RM:454-459
LeaveWindow PM:216
list of types and structure names PM:223
MapNotify RM:475-476
MappingNotify RM:477-478
MapRequest RM:479
mocking up from action PM:171;RM:295
MotionNotify PM:216, 234; RM:480-482
next event; returning RM:191
NoExpose PM:193;RM:468-469
nonmaskable PM: 1 9 1 , 207, 2 1 8
processing RM:176
524
X TooM Intrinsics Programming Manual
processing one event; XtProcessEvent
RM:209
propagation PM:207
PropertyNotify RM:483
ReparentNotify RM:484
ResizeRequest RM:485
returning next event RM:80
selecting PM:207
SelectionClear PM:280, 289; RM:486
SelectionNotify PM:280, 290, 295; RM:487
SelectionRequest PM:280, 282, 290-291;
RM:488
structures RM:438
translation table abbreviations PM: 192- 193
UnmapNotify RM:475-476
using inside actions or event handlers PM:221;
RM:271
VisibiUtyNotify RM:489-490
XEvent; example PM:221; RM:271
(see also XtAppNextEvent, XtAppPending)
examples, actions; actions table PM:45; adding
actions PM:43-45; in gadget parent
PM:380-381; using event data in PM:222;
widget actions PM: 184- 185
adding; accelerators PM:206; event handler
PM:218-219; RM:294; resource list to class
structure PM:145; scrollbars to appUcation
PM: 109, 111; work procedure
PM:23 1-232
appUcation resource data structure PM:81
BitmapEditClassRec PM: 138-139, 138
BitmapEditRec PM:139
calculating scrollbar thumb size PM: 1 13-1 16
cascading pop-up menu PM:363, 365
constraint resources PM:68-69
constraint widget change_managed method
PM:338-339
constraint widget; refiguring child locations
PM:333-335
converting; default value of resource
PM:254-255; selection PM:293-294; stan
dard selections PM:300-301; RM:284-285
creating; argument Ust PM:92; argument lists
withXtSetArg PM:93, 94; GCs from ini
tialize method PM:169-170; iconpixmap
PM:278-279
creating pop up; work procedure RM:323
creating; widget hierarchy PM:61-63
declaring; resource Ust PM:240; widget class
record pointer PM:155
destroy method PM:183
drawing into Core widget PM:1 18-1 19
explicitly invoking converter PM:261
expose method PM:171-172; RM:296; in gad
get parent PM:378-379
gadget class structure PM:376
gadget instance structure PM:377
geometry_manager method in constraint
widget PM:332-333
get_values_hook method PM:265; RM:277
hardcoding resources PM:92
highUghting selection PM:284-288
initialize method PM:166-168; in constraint
widget PM:330
initiaUzing; Core class part PM: 148-149;
Xmu atom caching PM:300
installing accelerators in multiple widgets
PM:209
interactions between resources PM:55
laying out child widgets PM:3 17-3 19
main loop (custom) PM:233
menu using SimpleMenu widget PM:368-370
nonmaskable event handlers PM:219-220
obtaining; atom PM:29 1-292; source code
availabiUty PM:34
options table PM:88-89
passing arguments to converter PM:259
passing data PM:77-79
pasting selection PM:295-296
placing; drop-down menu PM:360, 361;
pop-up menu PM:354, 357
pop ups; work procedure to create PM:232
pop-up menu (spring-loaded); using Box
widget PM:354-358
pubUc function to get widget data PM: 105
query_geometry method PM:182; in compos
ite widget PM:316-317; in constraint
widget PM:339
reading; from file PM:224-226; from pipe
PM:226-227
registering resource converter PM:258
removing timeouts PM:229-230
resize method PM:177, 179; in composite
widget PM:316; in constraint widget
PM:336-337; in gadget parent PM:380
resource definition in widget PM: 143 -145
resource list PM:82-83
resource value; getting PM:51
retrieving; appUcation resources PM:85-86;
resource default at run-time PM:256
setting; resources for widget hierarchy PM:64;
resources with XtSetValues PM:50; win
dow attributes in realize method PM:157;
XtNinput PM:276
set_values method PM: 174-175; in composite
widget PM:316
Index
525
timeouts PM:228-229
translation table PM:47
using; argument lists PM:92-93; event data in
an action PM:222; RM:27 1-272; popups
PM:71-74; timeouts PM:229
writing type converter PM:262-263
xbitmapl PM:104-107
xbitmap2 PM: 107-1 16
xbitmapS PM:1 16-122
xbitmap4 PM: 123-132
XEvent RM:271
XEvent casting PM:221
xfarewell.c PM:43-45
xgoodbye.c PM:40
xheUo.c PM:31-32
XrmOptionDescRec PM:88-89
(see also XtResourceDefaultProc)
expo.lcs.mit.edu PM:34
Expose events PM:10, 23, 114, 122, 124, 150,
153, 165, 172, 230, 235, 353; RM:51, 297,
460-461
expose method PM:29, 153, 165-166, 170-174,
220, 501; RM:296-297, 332-333
in gadget parent PM:378-379
in gadgets PM:373, 378
(see also XtExposeProc)
exposure PM:501
(see also Expose events)
(see also XtAddExposureToRegion)
compression PM:172, 235; RM:297
exposure (see Expose events)
extensions, about PM:12, 502
fatal error handling (see errors)
fatal error (see errors)
file input, registering file RM:65-66
files, file events (see event handlers)
file input PM:224-226; registering file
RM:54-55; source masks PM:224; XtAd-
dlnput RM:54-55; XtAppAddlnput
RM:65-66
filenames; character limit PM:136
using names in resources PM:253
floating point numbers PM:253
Focusln events PM:195-196,216,390;
RM:462-467
FocusOut events PM:195-196,216,390;
RM:462-467
font conventions (in this book), bolding
PM:xxviii; RM:viii
italics PM:xxviii; RM:viii
typewriter font PM:xxviii; RM:viii
fonts PM:502
aliasing PM:442
creating databases (mkfontdir) PM:444
directories PM:438
display (xfd) PM:438
families PM:438,441
fonts.dir files PM:444
naming convention PM:439
printer PM:438
screen PM:438
specifying PM:433; as resources PM:253
using file name as alias PM:443
wildcarding PM:441
foreground PM:502
Form widget, about PM:20, 67-70, 325-340,
409,421;RM:365-367
adding children RM:367
child resources RM:366
creating RM:367
deleting children RM:367
destroying RM:367
example PM:421
layout method PM:329
resources RM:365-366 (see also resources)
freeing storage block (see storage block)
ftp PM:34
function typedefs, overlapping use PM:148
G
gadgets, about PM:155, 345
accelerators PM:371; not usable PM:373
actions in PM:373
class hierarchy PM:374-375
class structure PM:376
composite parent PM:373, 378-381
Core class structure PM:375
drawbacks PM:373
event handling in PM:373
expose method PM:378
implementation file PM:377
instance structure PM:377
internals PM:375-378
private header file PM:376-377
public header file PM:378
query_geometry method PM:378
reason for PM:372
set_values_almost method PM:378
Sme PM:367-378
SmeBSB PM:367-378
526
X Toolkit Intrinsics Programming Manual
SmeLine PM:367-378
superclass PM:377
unused Core fields in PM:377-378
games PM:227
GC (see graphics contexts)
geometry management, about PM:33, 65-66,
177, 180-182, 273, 305-341, 502; RM:14,
338-342,431
(see also XtDestroyWidget)
(see also XtGeometry Almost)
(see also XtGeometry Done return value)
(see also XtGeometryNo return value)
(see also XtGeometryResult enum)
(see also XtGeometry Yes return value)
(see also XtlnheritDeleteChild constant)
(see also XtlnheritGeometryManager constant)
(see also XtlnheritlnsertChild constant)
(see also XtlnheritSetValuesAlmost constant)
(see also XtMakeGeometryRequest)
(see also XtMakeResizeRequest)
(see also XtMapWidget, XtMoveWidget)
(see also XtNinsertPosition composite
resource)
(see also XtNmappedWhenManaged Core
resource)
(see also XtQueryGeometry)
(see also XtResize Widget)
(see also XtUnmanageChild, XtUn-
manageChildren)
(see also XtUnmap Widget)
(see also XtWidgetGeometry structure)
almost right PM:323
border width PM:306
Box widget RM:357-358
change_managed method PM:306, 308, 319
changes PM:456; RM: 177-179
changing; XtMakeGeometryRequest
RM:177-179
compound widgets PM:340-341
constraint class part PM:329
constraint management PM:325
constraints on children RM:365-367
delaying recalculation PM:340
delete_child method PM:306, 323-324
geometry handler; procedure RM:299-301
geometry manager RM:341
geometry_manager method PM:306, 311,
320-322; RM:340-341; in constraint widget
PM:332-336
height PM:308
initial geometry negotiation PM:308, 310
initial size PM:308
initialize method PM:315
inserting children PM:323; insert_child
method PM:306, 323-324
minimal useful size PM:317
querying RM:210-212; preferred geometry
PM-.320; query_geometry method PM:306,
321; XtQueryGeometry RM:210-212;
XtQueryOnly constant PM:322
realize method PM:310,315
resizing PM:305, 311; by application
PM:312; by user PM:311; by widget
request PM:311-312; resize method
PM:306, 309
scope PM:306
scroUable widget RM:403-404
set_values method PM:3 1 1 -3 12, 3 15
set_values_almost method PM:312, 322, 323
size preferences PM:320
stacking order PM:306, 341
trickle-down PM:320
unmanaging widget PM:319
what if requests PM:322
widget for vertical tiles RM:405-408
width PM:308
get values_hook method PM: 154, 265-266,
" 502; RM: 158, 275-278, 335
(see also XtArgsProc)
global variables PM:75, 77
glyph PM:502
grabs PM:351, 495, 502; RM:431
(see also XtAddGrab)
(see also XtRemoveGrab)
active vs. passive PM:352
adding or removing explicitly PM:372
exclusive vs. nonexclusive PM:352, 365
grab modes PM:365
in dialog boxes PM:371
keyboard PM:351
passive PM:507
pointer PM:351
reasons for in menus PM:353
graphics contexts PM:119, 140, 157,502
(see also XtDestroyGC)
(see also XtGetGC)
(see also XtReleaseGC)
caching PM:166, 168
changing PM:168, 176
creating PM: 166-170
deallocating RM:217
destroying RM:128
exclusive or logical function PM:287
freeing PM:176, 183
freeing (R2) RM:128
hardcoding values in PM:170
Index
527
obtaining RM:146-147
read-only PM:168
reasons for PM:119
setting with resources PM:170
graphics (see also drawing)
GraphicsExpose events PM:193, 220; RM:51,
468-469
graphics primitive PM:503
gravity PM:503
GravityNotify events RM:470
Grayscale PM:503
Grip widget class PM:19; RM:368-369
resources RM:368
H
hardcoding, resources PM:38, 91,92
translations PM:48
header files, not included twice PM:139
private PM:508
public PM:508
height PM:308
checking in initialize method PM:166
hello world in Xt PM:31
hexadecimal color specification PM:434
hints PM:270-279, 503
icon position PM:273
position PM:55
size PM:273
size increment PM:273
hook RM: 158, 244
host access list PM:503
hotspot, in cursor PM:503
Hyper key (see modifiers)
ICCCM PM:1 1,269, 288, 29 1,298-302
icon, pop-ups PM:272
setting; name PM:278; pixmap PM:269,
277-278
starting application as PM:273
identifier PM:503
ifndef statement, to prevent include files from
being read in twice PM:139
implementation file (see widget)
include files PM:30, 50, 53, 136, 139
in widget implementation PM : 1 4 1
inferiors PM:503
inheritance, about PM:18, 49, 54, 148-158
adding features to superclass PM:157
among Athena Widgets PM:18
among Motif widgets PM:399
among Open Look widgets PM:399
in widget class and instance record
PM:137-138
of AT&T PM:405
of chained methods PM:152
of conflicting methods PM:157
of Core resources PM:52, 54
of self-contained methods PM:151-152
of superclass method PM: 155
resources PM: 143 -145
single vs. multiple PM:503
specifying NULL for chained methods
PM:152-153
styles PM:151-152
using Xtlnherit constants PM : 1 5 1
widget not using resource value PM:56
initial size PM:308
initialize method PM:153, 165-170, 315, 503;
RM:328-331
(see also XtlnitProc)
(see also XtProc)
calling XInterriAtom from PM:291
in constraint widget PM:330
initialize_hook method PM: 153, 265, 503;
RM:336
input queue, determining events RM:83, 205
(see also XtAppNextEvent)
(see also XtAppPeekEvent)
(see also XtAppPending)
(see also XtPeekEvent)
examining head RM:81-82, 204
input, from file PM:224-226
from pipe PM:226-227
input events method RM:293-294
input focus PM:504
input manager PM:504
input source masks PM:224
InputOnly window PM:504
InputOutput window PM:504
InputOurput window RM:460
insert_child method PM:306, 323-324, 504;
RM:339-340
insert_position method RM:339, 342
instance, about PM:18, 504
instance record PM:136; adding variables to
PM:139; allocating storage PM:140; Bit-
mapEdit widget PM:139; contents
PM:136
instance structure PM:166
part structure; constraints in PM:327
structures PM:135-162
528
X Toolkit Intrinsics Programming Manual
Inter-Client Communication Conventions
Manual (see ICCCM)
Intrlnsics, about PM:8, 504; RM:2
functions and macros; MenuPopdown
PM:352; MenuPopup PM:352
Intrinsic.h PM:30, 141
IntrinsicP.h PM:141
selection timeout RM:87
JumpProc RM:381
key events (see events or translations)
key translation, registering RM:238
(see also XtKeyProc)
(see also XtSetKeyTranslator)
keyboard focus, about PM:274, 389, 391, 504
(see also XtAcceptFocusProc)
(see also XtNinput resource)
(see also XtSetKeyboardFocus)
accept/reject method RM:269
redirecting input RM:236-237
setting PM:275
styles PM:275
window RM:462
keyboard grabbing (see grabs)
keyboard, mapping RM:477
shortcuts (see accelerators)
keycodes, about PM:194, 391, 505
translating; keycode-to-keysym RM:252-255;
XtTranslateKey RM:252-253; XtTransla-
teKeycode RM:254-255
KeymapNotify events RM:471
KeyPress events PM:194, 196,391;
RM:472-474
Key Release events PM:194, 196; RM:472-474
keysyms, about PM:194, 391,505
(see also XtCaseProc)
(see also XtConvertCase)
converting case PM:200; RM:28 1-282
determining case RM: 114
key generated PM:198
keysymdef.h PM:194, 197
naming conventions PM:195
Label widget class, about PM:177;
RM:370-372
creating RM:372
destroying RM:372
resources RM:370-372
laying out child widgets, example PM:317,
319
layout Form method PM:329
LeaveNotify events PM: 195 -196, 234, 353;
RM-.454-459
LeaveWindow events PM:216
lint PM:42
List widget class, about PM:19, RM:373-377
creating RM:375
destroying RM:375
UstWidgetClass RM:373-377
resources RM:373-375
loose bindings PM:244, 505
M
macros PM:388-389
mam loop PM:30, 34
(see also XtAppMainLoop)
(see also XtMainLoop)
customizing; example PM:233
internals PM:233
mapping, about PM:33, 53, 505
(see also widget, mapping)
button RM:477
keyboard RM:477
MapNotify events RM:475-476
MappingNotify events PM:193; RM:477-478
MapRequest events RM:479
pop-up shell; XtPopup RM:207-208
unmapping pop-up shell; XtPopdown
RM:206
widgets; XtMapWidget RM:185
mechanism without policy PM:10, 269
memory allocation PM:392
for widget instance record PM: 150
MenuPopdown PM:352; RM:39
MenuPopup PM:352, 357; RM:40-41
argument to PM:358
menus, about PM:345-38 1,408
accelerators in PM:367, 371
cascading PM:347, 362
drop-down PM:347, 359
grabbing pointer PM:353
panes in PM:349
Index
529
placing pop-up PM:357
pointer grabbing PM:351
popping down PM:35 1,359, 367; MenuPop-
down RM:39
popping up PM:352, 358; MenuPopup
RM:40-41
popping up with callbacks PM:360
puUdown PM:347
SimpleMenu widget, example PM:368, 370
spring-loaded PM:347
messages, about PM:29, 505
OOP vs. Xt PM:29
Meta key (see modifiers)
methods, about PM:153-154, 505
accept_focus PM:154, 389, 391
and instance structure PM:136
change_managed PM:306-308, 319; RM:340
class_initialize PM:153, 258, 381; RM:331
class_part_initialize PM:153; RM:331
constraint widgets; destroying PM:329;
geometry_manager PM:332; initializing
PM:329; resizing PM:336
declarations in widget implementation file
PM:147-148
delete.child PM:306, 323-324; RM:340
destroy PM:154, 165, 183
display_accelerators PM:211
drawing; due to changes in set_values
PM:175; in expose PM:166
expose PM:29, 153, 165-166, 170-174,220;
RM:296
Form layout PM:329
gadget; expose PM:378; query_geometry
PM:378; set_values_almost PM:378
geometry_manager PM:306, 311, 320-322;
RM:340
get_values_hook PM:154, 265-266;
RM:275-277; example PM:265; example
of RM:275, 277
in OOP PM:29
inheritance; adding to superclass PM:157; of
superclass PM:155
initialize PM:153, 165-170, 315
initializejiook PM:153, 265
insert.child PM:306, 323-324; RM:339
layout Form PM:329
not known to Xt PM:329
query_geometry PM:154, 165, 180-182,306,
321
realize PM:153, 274, 310, 315; RM:331
reconciliation PM:157
resize PM:154, 165, 177-180, 306, 309
resources, and set_values PM: 174- 176
set_values PM:154, 165-166, 174-176,
311-315
set_values_almost PM:154, 312, 322-323
set_values_hook PM:154, 265-266; RM:275
minimal useful size PM:317
mkfontdir PM:444
Mod n key (see modifiers)
modal cascade (see menus, cascading)
modal pop ups (see pop ups)
modifiers, ! PM:200
adding PM:198
and event sequences PM:202
case-specifics PM:200
colon PM:200-201
displaying list PM:198
for button events PM:202
keys, about PM: 196 -20 1,506; Alt key
PM:197; Ctrl key PM:197; Hyper key
PM:197; key modifier RM:500-506; Meta
key PM:197; Mod n key PM:197; Super
key PM: 197
matching exactly PM:200
negating PM:199
None PM:200
tilde PM:199
monochrome PM:506
Motif PM:349, 399, 402
motion compression PM:234
MotionNotify events PM:196, 202, 216, 234,
353; RM:480-482
multiple toplevel shells PM:395
N
naming conventions (see also conventions)
widgets PM:449
newlines, in translations PM:190
NoExpose events PM:193;RM:468-469
nonfatal error (see errors)
nonmaskable events PM:191, 207, 218-220,
506
example of handlers PM:219-220
notify modes (see translations)
object, about PM:28, 506
Object class PM:374
object-oriented programming PM:28-29
530
X Toolkit Intrinsics Programming Manual
object-oriented programming, about PM:506
obscure PM:506
occlude PM:506
OOP (see object-oriented programming)
optimization PM: 124, 179,394
options -xrm PM:86, 88
options, abbreviating PM:87
argument styles PM:90
command line PM:86; styles PM:90
custom PM:246
defining your own PM:88
handling errors in PM:91
options table; example PM:88-89; xbitmap
PM:106
standard PM:86, 87; RM: 13-14
OR operator RM:50, 95, 221, 225
overriding, override redirect PM:272
override_redirect window attribute PM:157
OverrideShell widget class PM:272;
RM:346-353
standard options PM:91
translations PM:48-49
padding PM:506
parent PM:506
parent window PM:507
parsing, command-line arguments PM:88-91
translations PM:48
part (vs. record) PM:137
pipe input PM:226-227
pixel values PM:120, 507
pixmap, about PM:53, 171, 257, 507; RM:295
freeing PM:183
icon PM:277
updating in widget PM: 116
placing, drop-down menu; example
PM:360-361
pop-up menu; example PM:354, 357
plane PM:507
(see also bit plane)
plane mask PM:507
pointer PM:507
events (see events or translations)
grabbing (see also grabs), PM:507
pointing device PM:507
pop ups, about PM:17, 70, 507; RM:8
cascading pop ups; about PM:345
creating in work procedure PM:232; RM:323
creating just before popping up PM:76
from callback function PM:75
linking group PM:272
modal PM:348, 505
modeless PM:348, 506
moving to desired position PM:75
OverrideSheU PM:272
sensitivity PM:372
spring-loaded PM:348, 513; RM:8
using PM:71-74
when application is iconified PM:272
pop-up menus PM:345
(spring-loaded) using Box widget PM:354-358
pop-up shell, (see also XtCreatePopupShell)
creating RM: 119-121
mapping RM:207-208
unmapping RM:206
portability PM:92, 224, 376,391-394
position, about PM:55, 253
hints PM:273
relative to root window PM:279
setting with resources PM:55
PRIMARY selection PM:281
printer fonts (see fonts)
private header file (see widget)
private instance variables PM:140
process input RM:79
(see also XtAppMainLoop)
program structure PM:30
properties, about PM:280, 508
and atoms PM:288
PropertyNotify events RM:483
protocol, about PM:5
PseudoColor PM:508
public, functions, about PM:104, 158; naming
conventions PM:114; reasons to use
PM:106
header file (see widget)
instance variables (see resources)
routines PM:340
pull down menu (see menus)
quarks PM:262,508
query_geometry method, about PM:154, 165,
180-182, 306, 321, 508; RM:336-337
in composite widget PM:316-317
in constraint widget PM:339
in gadgets PM:378
querying preferred geometry PM:320
Index
531
R
R4 PM:96
initialize_hook and set_values_hook obsoles
cence RM:277
raise PM:509
raw event handlers PM:220; RM:56-57
real estate PM:509
realization, about PM:33, 172, 176; RM:296
realize method PM:153, 274, 310, 315, 509;
RM:33 1-332
RealizeProc RM:327
rectangle PM:509
RectObj class PM:155, 374, 377
redirect PM:509
redrawing PM:23
reference pages, list RM:411,416
regions PM:172,379; RM:51, 297
registering/declaring actions (see actions)
registering, callbacks RM:44-45; list
RM:46-47
converters PM:257-260; RM:48, 62-64, 216
event handlers PM:21 8-220; RM:49-50
fatal error condition procedure PM:385-388;
RM:85-86, 234
file RM:54-55, 65-66
nonfatal error condition procedure
PM:385-388; RM:88-89, 235, 246-247
raw event handlers RM:56-57
work procedures PM:231-233; RM:59, 68
Release 4, (R4) PM:36, 345-346, 372
removing, callbacks RM:218-220
grabs RM:223
input RM:224
raw event handlers RM:225-226
timeouts RM:227; example PM:229-230
work procedures PM:232
reparenting, about PM:279, 361,509
ReparentNotify events RM:484
reply PM:509; RM:341
representation type PM:81-83, 239, 241, 509
request PM:510
resize method PM:154, 165, 177-180, 306, 309,
316, 336-337, 380, 510; RM:333
Resize Request events RM:485
resizing, about PM:65, 305, 311
caching old size PM:179
parent widget RM:333
reasons PM:322
resource conversion RM:131
resource list, copying (see also XtGetSub-
values, XtSetSubvalues)
copying from ArgList RM:242-243
copying to argument list RM: 156-157
resource list, retrieving (see also
XtGetResourceList)
(see also XtGetApplicationResources)
resource list, updating (see also
XtGetSubResources)
default values; retrieving RM: 148-149
updating RM:141-143; by name or class
RM:154-155
resources RM:338-339
resources (see also resource list)
about PM:22-23, 32, 36, 49, 52-54, 239-242,
510;RM:6-8
adv antages of hardcoding PM : 3 8
and set_values method PM: 174-176
application PM:80
changing value PM:174
checking v alidity PM : 1 66
class PM:83
classes and instances PM:37
comment character in files PM:244
constraint widget PM:68; RM:343-345
copying; from ArgList to widget
RM:244-245; from widget to argument list
RM: 158-159; XtGetValues RM: 158-159;
XtSetValues RM:244-245
declaring resource list; example PM:240
default address; interpreting PM:242
default value; converting PM:254-255; set
ting PM:83, 255
defined by Core PM:52
defined in widget implementation file
PM: 143-145
defining characteristics PM:83-84
defining in widget PM: 143 -145
Form widget PM:68, 326
format; of definitions PM:243-244
getting from application PM:50
getting resource value; example PM:51
in instance record PM:140
inheritance of PM:49, 143-145
interactions between PM:54-57; example
PM:55
loading; from .Xdefaults PM:55; withxrdb
PM:55
looking up values PM:243-251
loose bindings PM:244
name PM:83
naming conventions PM:240
precedence rules PM:249-251
registering resource converter; example
PM:258
representation types PM:81, 83, 241
532
X Toolkit Intrinsics Programming Manual
resource conversion PM:83; converters in
Xmu PM:253; method RM:314-315; (see
also XtConverter, XtDirectConvert,
XtResourceDefaultProc)
resource database PM:510; obtaining for dis
play RM:126
resource database (see also XtDatabase)
resource database sources PM:245
resource file format RM:497
resource list; example PM: 82-83; format
PM:83-84
Resource Manager PM:510 (see also actions)
RESOURCE_MANAGER property PM:245
resource name RM: 1 1
resource setting PM:510
resource types RM:11
retrieving; application resources PM:85-86;
resource default at run-time PM:256
setting; for multiple widgets PM:63-64; for
widget hierarchy PM:64; for widget hierar
chy PM:64; in application PM:50; with
XtSetValues PM:50; XtNinput PM:276
size PM:242
sources priority PM:246
specifications PM:249-251; errors in PM:37;
format PM:37-38; merging of duplicate
PM:245-246; wildcards in PM:243
symbolic constants PM:38, 50
tight bindings PM:244
type conversion PM:38, 251-264
type converter, XtConvert RM:1 1 1-1 13
types table PM:241
use of classes PM:241
XtN constants PM:158
XtNaccelerators (Core) PM:52
XtNallowShellResize (SheU) PM:272
XtNancestorSensitive (Core) PM:52
XtNargc (SheU) PM:27 1-272
XtNargv (Shell) PM:27 1-272
XtNbackground (Core) PM:52
XtNbackgroundPixmap (Core) PM:52
XtNbaseHeight(SheU) PM:272-273
XtNbasewidth (SheU) PM:272
XtNbaseWidth (SheU) PM:273
XtNborderColor(Core) PM:52
XtNborderPixmap (Core) PM:52
XtNborderWidth (Core) PM:52
XtNcolormap (Core) PM:52
XtNcreatePopupChUdProc (SheU) PM:271
XtNdefaultDistance (Form) PM:325
XtNdepth (Core) PM:52
XtNdestroyCaUback (Core) PM:42, 52
XtNgeometry (SheU) PM:27 1-274
XtNheight (Core) PM:52
XtNheightlnc (SheU) PM:272-273
XtNhorizDistance (constraint) PM:325
XtNiconic (SheU) PM:27 1-273
XtNiconMask (SheU) PM:272
XtNiconName (Shell) PM:272, 278
XtNiconPixmap (SheU) PM:272, 278
XtNiconWindow (SheU) PM:272
XtNiconX (SheU) PM:27 1-273
XtNiconY (SheU) PM:27 1-273
XtNinitialState (SheU) PM:272
XtNinput (SheU) PM:272, 275-276
XtNinsertPosition (composite) PM:324
XtNmappedWhenManaged (Core) PM:52,
319
XtNmaxAspectX (SheU) PM:272-273
XtNmaxAspectY (SheU) PM:272-273
XtNmaxHeight (SheU) PM:272-273
XtNmaxWidth (SheU) PM:272-273
XtNminAspectX (SheU) PM:272-273
XtNminAspectY (SheU) PM:272-273
XtNminHeight (Shell) PM:272-273
XtNminWidth (SheU) PM:272-273
XtNoverrideRedirect (SheU) PM:27 1-272
XtNpixmap (Core) PM:116
XtNpopdownCaUback (Shell) PM:360
XtNpopupCaUback (SheU) PM:360-361
XtNsaveUnder(SheU) PM:272
XtNscreen (Core) PM:52
XtNsensitive (Core) PM:52
XtNtide(SheU) PM:27 1,278
XtNtransient (SheU) PM:27 1-272
XtNtranslations (Core) PM:47, 49, 52, 112
XtNvertDistance (constraint) PM:325
XtNwaitForWm (SheU) PM:272-272
XtNwidth (Core) PM:52
XtNwidthlnc (SheU) PM:272-273
XtNwindowGroup (SheU) PM:27 1-272
XtNwmTimeout (SheU) PM:27 1-272
XtNx (Core) PM:52
XtNy (Core) PM:52
RGB, color model PM:435-436
root PM:511
root window PM:53, 511
round trip request PM:30, 260, 511
rubber-band outline PM:177,287
Index
533
s
save-set PM:511
save_under window attribute PM:156
saving under PM:156
scan line PM:511
order PM:511
screen, screen fonts (see fonts)
about PM:6,511
scrollbars, about PM:15, 409, 422, 512
adding to application PM:109; example
PM:109
adding to xbitmap PM:108
and Expose events PM:114
calculating thumb size PM:113-116; example
PM:113-116
controlling scrolling area RM:378-382
creating PM:112
Scroll widget PM:19
ScroUbar widget PM:108-111; RM:378-382;
creating RM:380; destroying RM:380;
resources RM:378-380
scroUbarWidgetClass RM:378-382
setting thumb values RM:381
selections PM:269, 280-302, 5 12
SelectionClear events RM:486
SelectionNotify events RM:487
SelectionRequest events RM:488
and CurrenlTime PM:289
asserting ownership PM:288-289
converting; selection PM:293-294; standard
selections PM:299-301; RM:284-285
deleting PM:301
disowning PM:302
handling large selections PM:301; RM:285
highlighting selected data PM:284, 287-288
highlighting selection; example PM:284,
287-288
losing selection PM:289-297
pasting data PM:292
pasting selection PM:295-297; example
PM:295-296
querying for desired target PM:298-302
requesting selection PM:289-290
selections, selection data RM:132, 198-199
method RM:316-317; obtaining RM:151;
obtaining in multiple formats RM:152-153
(see also XtConvertSelectionProc)
(see also XtDisownSelection, XtSelection-
CallbackProc)
(see also XtGetSelection Value, XtGetSelec-
tionValues)
(see also XtOwnSelection)
selections, selection method
(see XtLoseSelectionProc, XtSelection-
DoneProc)
selections, selection timeout (see timeouts)
SelectionClear events PM:280, 289
SelectionNotify events PM:280, 290, 295
SelectionRequest events PM:193, 280, 282,
290-291
setting timeout PM:302
target types PM:290-292
XA_CLIPBOARD PM:288,301-302
XA_MULTIPLE PM:301;RM:285
XA_PRIMARY PM:281,288
XA_SECONDARY PM:288
XA_TARGETS PM:29 1,298
self-contained methods (see inheritance)
sensitivity PM:54,75,92
checking state; XtlsSensitive RM:173
in pop-up callbacks PM:372
setting state; XtSetSensitive RM:241
server, about PM:6, 512
server code; guide to PM:491
server grabbing PM:512
server resources; freeing PM:183
set_values method PM:154, 165- 166, 174-176,
311-312, 315, 512; RM:319, 334-335, 343
(see also XtSetArgsFunc, XtSetValues, XtSet-
ValuesFunc)
change to PM:456
in composite widget PM:316
redrawing due to changes in PM:175
set_values_almost method PM:154, 312,
~ 322-323, 512; RM:273-274, 335
in gadgets PM:378
set_values_hook method PM:154, 265-266,
512;RM:275-276,335
Shell RM:346-353
environment variables (see environment vari
ables)
Shell, default value PM:458; RM:351-352
Shell types; ApplicationShell RM:346; Over-
rideShell RM:346; Shell RM:347;
TopLevelShell RM:346; TransientShell
RM:346; VendorShell RM:347; WMShell
RM-.347
Shell widget class, about PM:17, 21, 32, 55,
61, 66, 269; RM:346-353; reason for invisi
bility PM:63; resources PM: 271, 272-277,
279; types RM:346-347; XtlsShell
RM:174; XtNbasewidth PM:272
sibling PM:512
534
X Toolkit Intrinsics Programming Manual
single-line Input Held PM:280
sink, in Athena Text widget PM:264
size PM:305
hints PM:273
preferences PM:320
sizeof PM:150
Sme gadgets PM:367-378
SmeBSB gadgets PM:367-378
SmeLine gadget PM:367-378
software architecture, about PM:8
source code, obtaining; example PM:34
source files for widget PM:135
source, in Athena Text widget PM:264
spring-loaded pop up (see pop ups)
stacking order PM:306, 341,513
StaticColor PM:513
StaticGray PM:513
status PM:513
stdio.h PM:141
stipple PM:513
storage, storage block
allocating RM:181; for data type RM:189;
XtNew RM:189
freeing RM:140; (see also XtFree)
resizing RM:215
(see also XtMalloc)
string, copying; XtNewString RM:190
StringDefs.h PM:83
StringDefs.h header file PM:30, 50, 141;
RM:507
string, error message; XtStringConversionWarn-
ing RM:248
StrhigToWidget resource converter PM:69
structure (see also XtOffset)
determining field's byte offset RM: 193-194
of Xt applications PM:30
subclass, about PM:19, 513
submenus (menus, cascading)
subparts PM:150, 154,264-266
subresources PM: 150, 154,264-266
Super key (see modifiers)
superclass, about PM:19, 149, 513
syntax functions PM:91
TCP/IP PM:280
templateWidgetClass RM:383-390
Text widget, about PM:19, 414, 424;
RM:39 1-402
creating RM:397
default bindings RM:395-396
edit modes RM:392
resources RM:392-394
tight bindings PM:244, 513
tiling, about PM:53,513
time PM:513
timeouts, about PM:227
adding PM:227
and visibility interest PM:230
callback method RM:321
example PM:228-229
invoking procedure after timeout RM:67
removing PM:229-230
selection timeout; setting RM:240; value
RM:78, 87, 150
(see also XtAddTimeout, XtAppAddTimeOut)
(see also XtAppSetSelectionTimeout, XtGet-
SelectionTimeout)
(see also XtRemoveTimeOut, XtSetSelection-
Timeout)
(see also XtTimerCallbackProc)
toolkits, initializing internals RM:250
initializing toolkit and display RM: 1 6 1 - 1 65
(see also Xtlnitialize, XtToolkitlmtialize)
top-level widget (see Shell widget)
top-level window PM:514
topLevelShell widget class PM:270;
RM:346-353
training in Xlib PM:489
TransientShell widget class PM:70, 74, 270;
RM:346-353
Translation Manager (see actions)
translations, # augment directive PM:48
! modifier symbol PM:200
# override directive PM:48
# replace directive PM:48
(see also accelerators)
(see also actions)
(see also XtOverrideTranslations)
about PM:27, 39, 43, 47, 53, 514; RM:7
augmenting PM:48
colon modifier symbol PM:200-201
compiling; table RM:202-203; when widget
class initialized PM:147; XtParseTransla-
tionTable RM:202-203
defining; default in Core class part PM:150;
in source PM:49
details in PM: 194-196
differences between directives PM:191
directives PM:191
double-clicks PM:201
event abbreviations PM:192-193
event sequences PM:201-203
hardcoding PM:48
Index
535
in widget implementation file PM: 145 -147
inheritance PM:146
interactions between PM:203-207
keyboard events PM:194-195
merging PM: 112, 203
merging widget translations RM:93-94
merging/overwriting RM:197
modifiers PM:196-201, 198
modifiers and event sequences PM:202
Motion events PM:202
new lines in PM:190
*Notify details PM:195
order PM:203-204
overriding PM:48-49
parsing PM:48
removing RM:256
replacing PM:48, 49
resource converters PM:253
syntax PM:190
tilde modifier symbol PM:199
translation table PM:514; RM:499; example
PM:47; syntax PM:457
(see also XtAugmentTranslations)
(see also XtUninstallTranslations)
traversal, post-order PM:508
pre-order PM:508
TrueColor PM:514
type converters (see also resources)
about PM:93
caching PM:260
explicitly invoking PM:261; example
PM:261
format PM:262-264
passing arguments to PM:259
registering PM:257-260
type property PM:514
typedefs PM:140
types converters, passing arguments to;
example PM:259
L
unman aging widget PM:319
UnmapNotify events RM:475-476
upward chaining PM:152
uunet PM:34
uwm PM:346
varargs PM:95, 427
variables, resource PM:446
VcndorShcll widget class PM:275
viewable PM:514
Viewport widget, creating RM:404
Viewport, Viewport widget; destroying
RM:404; inserting child RM:404; remov
ing child RM:404; resources RM:403-404
ViewportWidgetClass RM:403-404
virtual colormaps PM:276
virtual crossing RM:456
visibility interest PM: 150, 230-231
VisibilityNotify events PM: 150, 193;
RM:489-490
visible PM:514
visual PM:514
class PM:514
VPaned, VPaned widget; about RM:405-408;
adding pane RM:406; change height set
tings RM:407; child resources RM:406;
deleting pane RM:406; destroying
RM:408; disabling auto -reconfiguring
RM:407; disabling pane resizing RM:407;
disabling resources RM:405-406; enabling
auto-reconfiguring RM:407; enabling pane
resizing RM:407
VPanedWidgetClass RM:405-408
W
warnings (see error handling)
calling high-level RM:9 1-92, 261-262
handler, (see XtAppWarningMsg, XtWarning,
XtWamingMsg)
listing RM:491
widget
about PM:8,15,514;RM:2
actions; example PM: 184-1 85
adding to parent list PM:17; RM:182-184;
XtManageChild RM:182; XtManageChil-
dren RM: 183-184
application context PM:97-98; getting
RM:263; XtWidgetToApplicationContext
RM:263
as data type PM:33
BitmapEdit PM:66, 103-132, 177. 314, 461
Box widget PM:21,351;RM:357-358;
example PM:61
call accept_focus method RM:97
callback list (see callbacks)
536
X Toolkit Intrinsics Programming Manual
child widget; about RM:15; creating/manag
ing PM:61,307;RM:118; layout of
PM:317
class; composite widget subclass PM:16;
determining subclass RM:175; name
defined PM:150; obtaining RM:107; veri
fying RM:106; widgetClass class pointer
PM:119; XtCheckSubclass RM:106;
XtClass RM:107; XtlsComposite
RM:169; XtlsConstraint RM:170; Xtls-
Shell RM:174; XtlsSubclass RM:175
Command widget PM:19, 38-39, 40-42, 75,
104; RM:359-362
composite widget, about PM:21, 305; RM:14,
169, 338-342; management PM:306; rea
sons for writing PM:305; writing PM:312
compound PM:340-341
constraint widget, about PM:22, 305; RM:16,
170, 343-345; management PM:325; writ
ing PM:325
converting (2 to 3) PM:453
Core widget PM:17, 116; RM:383
creating PM:30, 80; RM: 122-123; additional
top-level widget RM:69-70, 117; child
widget RM:14; custom widget
RM:383-390, 384; working window
RM:124-125
declaring widget class record pointer, example
PM:155
default size PM:180
defining conventions PM: 136, 244; summary
PM:162
destroying PM:26, 79, 183; RM:129-130;
XtDestroyWidget RM: 129-130
Dialog widget PM:20, 75, 340; RM:363-364
display pointer RM:134
displaying non-editable string RM:370-372
dragging PM:20; attachment point
RM:368-369
Exclusive and Nonexclusive PM:407
Form widget PM:20, 104, 326, 421;
RM:365-367
framework of code PM:135-162
geometry (see geometry management)
getting data; example PM:105
getting widget data via public function
PM:105
Grip widget PM:19; RM:368-369
implementation file PM:135, 141-158; actions
table PM: 145-147; declaration of methods
PM:147-148; resources PM:143-145;
translation table PM: 145-147
installing accelerators (see accelerators)
instance structure PM:166
internals PM:135-162
Label widget PM:28, 116, 177,258;
RM:370-372
lifecycle RM:4
List widget PM:19;RM:373-377
macros for getting widget information PM:388
management (see also XtManageChild,
XtManageChildren)
PM:61, 180-182; RM:171; row-column
geometry RM:373-377; XtlsManaged
RM:171
mapping PM:53; changing map_when_man-
aged field RM:239; windows PM:33;
XtMapWidget RM:185; XtSetMap-
pedWhenManaged RM:29
merging translations RM:93-94
methods (see XtCreate Widget)
modal widget; redirecting input RM:52-53,
223; XtAddGrab RM:52-53; XtRemo-
veGrab RM:223
moving/resizing PM:53; RM: 109-1 10;
XtConfigureWidget RM: 109-1 10; XtMo-
veWidget RM:187
naming conventions PM:449
necessary include files PM:136
parent widget PM:111; returning RM:200;
XtParent RM:200
popping down; Menupopdown RM:39
popping up PM:75-76; Menupopup
RM:40-41
private header file PM: 135, 136-140
procedure RM:322
public header file PM:135, 158-160
realizing PM:176; RM:172, 213-214; method
RM:312-313; XtlsRealized RM:172;
XtRealizeProc RM:312-313; XtReal-
izeWidget RM:213-214
record size PM:150
removing PM:17; XtUnmanageChildren
RM:258; XtUnmanageChild RM:257
resizing PM:65, 177-180, 306-314; RM:333;
by application PM:312; by parent
PM:311; per core dimensions RM:230;
reasons for PM:322; resize method
PM:336; XtMakeResizeRequest RM:180;
XtResizeWidget RM:229; XtResizeWin-
dow RM:230
retrieving event mask RM:95-96; XtBuild-
EventMask RM:95-96
returning screen pointer, XtScreen RM:231
Scroll widget PM:257
Scrollbar widget PM:19, 66, 108; RM:378-382
Index
537
ScrollBox widget PM:314
scrolling viewing area in another widget
RM:378-382
sensitivity PM:54, 235
sets; about PM:8, 17, 18; Motif PM:18; spe
cial defaults PM:275
Shell widget, about PM:17, 21, 61, 104, 269;
RM:174
source file PM:135; RM:387
subclass; XtlsSubclass RM:175
superclass; inheritance PM:54; obtaining
RM:249; XtlsSuperclass RM:249; XtSu-
perclass RM:249
techniques for writing PM:160
Text widget PM:19, 75, 264, 414, 424;
RM:39 1-402
text-editing widget RM:39 1-402
translating; coordinates RM:251; name to
instance RM:188; window and display
pointer RM:265; XtNameTo Widget
RM:188; XtTranslateCoords RM:251;
XtWindowToWidget RM:265
unmapping; XtUnmapWidget RM:259
Viewport PM:21, 108; RM:403-404
VPaned widget PM:20, 66; RM:405-408
WidgetProc RM:327
WidgetToApplicationContext macro PM:394
WidgetWrap PM:96
Window widget RM:385
window; destroying RM:260; returning
RM:264; XtUnrealizeWidget RM:260;
XtWindow RM:264
windowless (see gadgets)
widget classes, about PM:17
applicationShell (Intrinsics) PM:270
Box (Athena) PM:66
Command (Athena) PM:19, 40-43, 47, 65
composite (Intrinsics) PM:16, 61, 137
constraint (Intrinsics) PM:137
Core (Intrinsics) PM:17, 52, 137; RM:327-337
Dialog (Athena) PM:71,75
Form (Athena) PM:68-69
Grip (Athena) PM:66
inheritance among (Athena) PM:18
initialize method; XtlnitProc RM:302-303;
XtProc RM:311
Label (Athena) PM:19,36,240
OverrideShell (Intrinsics) PM:270, 272
ScroU (Athena) PM:15, 39, 42, 66
Shell (Intrinsics) PM:17, 32, 55, 61, 66, 269
Simple (Athena) PM:19
Text (Athena) PM:75, 264
topLevelShell (Intrinsics) PM:270
TransientSheU (Intrinsics) PM:70, 74, 270
VendorShell (Intrinsics) PM:275
VPaned (Athena) PM:66
WidgetWrap PM:429
width PM:308
checking in initialize method PM:166
wildcards, in font names PM:441
in resource specifications PM:37, 243
window (see also XtCreate Window)
creating widget's working window
RM: 124-125
geometry PM:445
InputOutput RM:460
keyboard focus RM:462
background PM:156
backing_store PM:156
bit_gravity PM:156
border PM:156
colormap PM:156
cursor PM:157
event_mask PM:157
override_redirect PM:157
save_under PM:156
setting in realize method PM:157
window gravity PM:515
window manager, about PM:11, 31, 65-66,
269-279, 305, 5 15; RM:352
and decoration PM:279
and icons PM:277-279
click-to-type PM:274
colormaps PM:276, 277
focusing styles PM:196
hints PM:1 1,270-279
input models PM:274
interacting with PM:270-279
keyboard focus PM:274-276
listener PM:505
pointer-focus PM:274
real-estate-driven PM:274
reparenting PM:279, 361
screen layout PM:273-274
WindowObj class PM:155,375
work procedures, about PM:23 1-233, RM:59
(see also XtAddWorkProc, XtAppAddWork-
Proc)
(see also XtAppRemoveWorkProc,
XtWorkProc)
creating pop up in, example RM:323
registering RM:68
removing PM:232; RM:228
538
X Toolkit Intrinsics Programming Manual
X Consortium address PM:490
X protocol PM:5, 280
X source software PM:485
X Toolkit (see toolkits)
X, about PM:3
XA_CLIPBOARD (see selections)
XA_MULTIPLE property (see selections)
XA_MULTIPLE property (see selections)
XAPPLRESDIR environment variable
PM:245
XA_PRIMARY property (see selections)
XA_PRIMARY (see selections)
XA_SECONDARY (see selections)
XA_TARGETS atom (see selections)
Xatom.h PM:288,290
Xaw; PM:36
x bitmap application; PM:461
xbitmapl; example PM:104-107
xbitmap2; example PM:107-116
xbitmapS; example PM:1 16-122
xbitmap4; example PM: 123-132
XChangeGC Xlib function PM:168
XChangeKeyboardMapping RM:477
XClearArea Xlib function PM:175
xclipboard PM:300-302
XConfigureWindow PM:341,RM:449-450,
485
XConvertSelection RM:487
XCopyArea Xlib function PM:122, 174, 193;
RM:297
XCopv Colormap AndFree Xlib function
PM:277
XCopyPlane Xlib function PM:122, 174, 193;
RM:297
XCreateGC Xlib function PM: 120, 166
XCreate Window Xlib function PM:158
Xdefaults Hie PM:55,245
xedit PM:280
XENVIRONMENT environment variable
PM:245
xev PM:198
XEvent union RM:437
xfarewelLc, example PM:43-45
xfd (font displayer) PM:441
XFlush Xlib function PM:394
XGCValues structure PM:168
XGetlconSizes Xlib function PM:279
XGetModifierMapping RM:478
XGetMotionEvents RM:481
XGetPointerMapping RM:478
XGetStandardCoIormap Xlib function
PM:277
xgoodbye.c, example PM:40
XGrabButton Xlib function PM:353
XGrabKey Xlib function PM:353
XGrabPointer Xlib function PM:352
xhello.c, example PM:31-32
XInternAtom Xlib function PM:290-291
Xlib PM:36, 170, 172, 176
Xlib Interface RM:17
xload PM:275
XLookupString Xlib function PM:391
XLowerWindow Xlib function PM:341
XMapRaised RM:479
XMapWindow RM:479
xmh PM:68,280
xmodmap PM:198
XMoveResizeWindow RM:485
Xmu PM:36, 259, 299
XmuConvertStandardSelection PM:300-301 ;
RM:285
XmuConvertStandardSelection Xmu function
PM:299
XmuInternAtom PM:299
Xmu Intern Atom Xmu function PM:299
Xmu, resource converters in PM:253
XNextEvent Xlib function PM:31 1
XParseGeometry Xlib function PM:274
XQueryPointer RM:481
XRaiseWindow Xlib function PM:341
xrdb PM:55, 243, 245
XRecflnRegion Xlib function PM:172;
RM:297
XRefreshKeyboardMapping RM:478
XResizeWindow RM:485
XRestackWindows Xlib function PM:341
XrmOptionDescRec RM:163
example PM:88-89
format PM:89
structure PM:88
XrmoptionlsArg argument style PM:90
XrmOptionKind enum values PM:90
XrmoptionNoArg argument style PM:90;
RM:165
XrmoptionResArg argument style PM:90
XrmoptionSepArg argument style PM:90
XrmoptionSkipArg argument style PM:90
XrmoptionSkipLine argument style PM :90
XrmoptionStickyArg argument style PM:90
XrmStringToQuark Xlib function PM:262
Index
539
XSelectlnput Xlib function PM:207, 216
XSendEvent RM:444, 487-488
XSetErrorHandler Xlib function PM:385
XSetlnputFocus RM:463
XSetlnputFocus Xlib function PM:390;
RM:463
XSettOErrorHandler Xlib function PM:385
XSetPointerMapping RM:477
XSync Xlib function PM:394
Xt Intrinsics (see Intrinsics)
XtAcceptFocusProc RM:269
XtActionProc PM:46; RM:270-272
XtAddActions PM:45, 47, 145, 381, 393;
RM:42-43
XtAddCallback PM:42, 253; RM:44-45
arguments PM:42
XtAddCallbacks PM:80; RM:46-47
XtAddConverter PM:259,393; RM:48
arguments PM:258
XtAddEventHandler PM:215-216; RM:49-50
arguments PM:218
whentocaU PM:218
XtAddExposureToRegion RM:51
XtAddGrab PM:372; RM:52-53
XtAddlnput PM:224, 226, 393; RM:54-55
XtAddRawEventHandler PM:220; RM:56-57
XtAddress address mode constant PM:260
XtAddressMode enum PM:260
XtAddTimeOut PM:227; RM:58
XtAddWorkProc PM:231;RM:59
XtAlmostProc RM:273-274, 335
XtAppAddActions PM:98, 393; RM:60-61
XtAppAddConverter PM:393; RM:62-64
XtAppAddlnput PM:393; RM:65-66
XtAppAddTimeOut RM:67
XtAppAddWorkProc RM:68
XtAppContext PM:97
XtAppCreateShell PM:30, 98, 270, 393, 395;
RM:69-70
XtAppError PM:386,393; RM:71
XtAppErrorMsg PM:393; RM:72-73
XtAppGetErrorDatabase PM:393; RM:74
XtAppGetErrorDatabaseText PM:393;
RM:75-77
XtAppGetSelectionTimeout PM:393
XtAppInitiallze PM:97, 243
XtAppMainLoop PM:98, 393; RM:79
XtAppNextEvent PM:393-394; RM:80
XtAppPeekEvent PM:393-394; RM:81-82
XtAppPending PM:393-394; RM:83
XtAppProcessEvent PM:393-394; RM:84
XtAppSelectionTimeout RM:78
XtAppSetErrorHandler PM:393; RM:85
XtAppSetErrorMsgHandler PM:393; RM:86
XtAppSetSelectionTimeout PM:393; RM:87
XtAppSetWarningHandler PM:393; RM:88
XtAppSetWarningMsgHandler PM:393;
RM:89
XtAppTimeOut PM:393
XtAppWarning PM:386, 393; RM:90
XtAppWarningMsg PM:393; RM:91-92
XtAppWorkProc PM:393
XtArgsFunc RM:275-276, 335
XtArgsProc RM:277-278, 335-336, 339
XtArgVal PM:92
XtAsciiSinkCreate RM:401
XtAsciiSinkDestroy RM:401
XtAugmenfTranslations PM:48, 113;
RM:93-94
reasons to use PM:112
XtBaseOffset address mode constant PM:260
XtBuildEventMask RM:95-96
XtCallAcceptFocus PM:154, 390-391; RM:97
XtCallbackExclusive PM:79, 352; RM:98-99
XtCallbackList RM:279
XtCallbackNone PM:79,352; RM:100
XtCallbackNonexclusive PM:79, 352; RM:101
XtCalibackPopdown PM:352; RM: 102-103
XtCallbackProc RM:279-280
XtCallbackRec RM:279
format PM:80
XtCallCallbacks PM:39; RM:104
XtCalloc PM:183,392;RM:105
XtCaseProc RM:28 1-282
XtCaseProc function prototype PM:392
XtCheckSubclass RM:106
XtClass RM:107
XtCIoseDisplay RM:108
XtConfigureWidget PM:52; RM: 109-1 10, 334,
341
XtConvert PM:93,261;RM:111-113
XtConvertArgRec PM:259
XtConvertCase PM:392;RM:114
XtConverter RM:286-289
XtConvertSelectionProc PM:282, 289;
RM:283-285
XtCreateApplicationContext PM:30, 97-99;
RM:115-116
XtCreateApplicationSheU PM:393, 395;
RM:117
XtCreateManagedWidget PM:30, 33, 64, 94,
140, 243; RM:14, 118,340
540
X Toolkit Intrinsics Programming Manual
XtCreatePopupShell PM:74, 270, 348;
RM:119-121
XtCreateWidget PM:30, 63, 140, 165, 243;
RM:122-123,339,344
hardcoding resources with PM:92
XtCreateWindow PM:158;RM:124-125
XtCWQueryOnly mask PM:322; RM:340-341
XtDatabase RM:126
XtDefaultBackground PM:277
XtDefaultBackground constant PM:253, 264
XtDefaultFont constant PM:253
XtDefaultForeground constant PM:253, 264,
277
XtDestroyAppIicationContext RM:127
XtDestroyGC PM:176;RM:128
XtDestroy Widget PM:165, 324; RM: 129-130,
339, 345
XtDirectConvert PM:261;RM:131
XtDiskSourceCreate RM:401
XtDiskSourceDestroy RM:401
XtDisownSelection PM:302; RM:132
XtDispatchEvent PM:233;RM:133
XtDisplay RM:134
XtDisplay macro PM:261
XtDisplaylnitialize PM:30;RM:135-136
xterm PM:274,346
XtError PM:386, 387,393; RM:137
XtErrorHandler RM:290
XtErrorMsg PM:386, 387, 393; RM: 138-139
XtErrorMsgHandler RM:29 1-292
xtetris PM:227, 228-229
XtEventHandler RM:293-294
XtExposeProc PM:147; RM:295-298, 332
XtFree PM: 183, 297, 392; RM: 140
XtGeometryAlmost PM:321; RM:335,341
XtGeometry Almost return value PM:182
XtGeometryDone RM:340
XtGeometryDone return value PM:321
XtGeometryHandler RM:299-301, 336
XtGeometryMask RM: 178, 211,273,300
XtGeometryNo PM:182;RM:341
XtGeometryNo return value PM:321
XtGeometryResult PM:320-321; RM:178, 180,
211,300
XtGeometryResult enum PM:182
XtGeometryYes PM:182;RM:340
XtGeometryYes return value PM:321
XtGctApplicationRcsourccs PM:80, 243, 260;
RM:141-143
XtGetErrorDatabase PM:387, 393; RM:144
XtGetErrorDatabaseText PM:387, 393;
RM:145
XtGetGC PM:120, 166, 168, 176; RM:146-147
when not to use PM:169
XtGetResourceList PM:145; RM:148-149
XtGetSelectionTimeout PM:302, 393; RM:150
XtGetSelectionValue PM:282, 289-291, 299;
RM:151
XtGetSelection Values PM:302; RM: 152-153
XtGetSubresources PM:260, 266;
RM:154-155, 156-157
XtGetSubvalues PM:266;RM: 156-157
XtGetValues PM:23, 50-51, 75, 136, 361;
RM: 158-159, 345
bugfix PM:458
XtGrabNone grab mode PM:371
XtHasCallbacks PM:388; RM:160
X tlMAIternatelnput constant PM:234
Xtlmmcdiate address mode constant PM:260
XtlMTimer constant PM:234
XtfMXEvent constant PM:234
Xttnherit constants PM:151
XtlnheritDeleteChild constant PM:324
XtlnheritGeometryManager constant
PM:321
XflnheritlnsertChild RM:339
XtlnheritlnscrtChild constant PM:324
XtlnheritRealize constant PM:155
XttnheritSetValuesAlmost RM:335
XtlnherltSetValuesAlmost constant PM:323
Xttnitialize PM:30, 32, 74, 87, 170, 243, 246;
RM:161-165
arguments PM:32, 33
passing options table to PM:90
XtlnitProc RM:302-303, 330, 345
XtlnputCallbackProc RM:304-305
XflnstallAccelerators PM:205; RM: 166- 167
XtlnstallAllAccelerators PM:205, 209;
RM:168
XtlnternAtom Xlib function PM:288
XtlsComposite PM:388; RM:169
XtlsConstraint RM:170
XtlsManaged PM:388;RM:171
XtlsRcalizcd PM: 172, 388; RM: 172, 296
XtlsSensitive PM:388; RM:173
XflsShell RM:174
XtlsSubclass PM:388;RM:175
XtKeyProc RM:306-308
XtKeyProc function prototype PM:392
XtLoseSelectionProc PM:289; RM:309
Index
541
XtMainLoop PM:30, 34, 141, 230, 311, 393;
RM:176
and multiple application contexts PM:394
XtMake Geometry Request PM:311-312, 320;
RM: 177-179, 340
XtMakeReslzeRequest PM:322; RM:180
XtMalloc PM: 1 83, 392; RM: 1 8 1
XtManageChild PM:33; RM:182
XtManageChildren PM:30, 33; RM:183-184
XtMapWidget PM:319; RM:185
XtMergeArgLists PM:95;RM:186
XtMoveWidget PM:52, 308, 319; RM:187, 341
XtNameToWidget PM:388
XtNbasewidth (SheU) PM:272
XtNew PM:266,392;RM:189,275
XtNewString PM:392; RM:190
XtNextEvent PM:233,393; RM:191
XtNsensitive resource PM:75
XtNumber RM:192
XtOffset RM: 193-194
XtOffset macro PM:83,242
XtOpenDisplay PM:98, 396; RM: 195-196
XtOrderProc RM:310, 342
XtOverrideTransIations PM:49, 112-113;
RM:197
reasons to use PM:112
XtOwnSelection PM:281, 288-289;
RM:198-199
XtPanedAllowResIze RM:407
XtPanedSetMinMax RM:407
XtPanedSetReflgureMode RM:407
XtParent RM:200
XtParseAcceleratorTable PM:210; RM:201
XtParseTranslationTable PM:48, 113, 147,
210; RM:202-203
XtPeekEvent PM:234, 393; RM:204
XtPending PM:234, 393; RM:205
XtPointer PM:376
XtPointer data type PM:256
XtPopdown PM:7 1,352, 357; RM:206, 352
XtPopup PM:71, 352, 365; RM:207-208, 347,
352
XtPopupSpringLoaded (R4) PM:353
XtProc RM:31 1,327
XtProcessEvent PM:234, 393; RM:209
XtQueryGeometry PM:308,310, 312;
RM:210-212
XtR Accelerator Table representation type
PM:253
XTransIateCoordinates Xlib function PM:361
XtRBackingStore representation type
PM:257
XtRBool representation type PM:253
XtRBoolean representation type PM:253
XtRCallhack representation type PM:258
XtRCallProc representation type PM:242,
255
XtRCursor representation type PM:253, 257
XtRDimension representation type PM:253
XtRDisplay representation type PM:253
XtRealizeProc RM:312-313,331
XtRealizeWidget PM:30, 33, 153, 308,
310-311, 319; RM:213-214
XtRealloc PM:392; RM:215
XtRegisterCaseCon verier PM:392; RM:216
XtReleaseGC PM:176; RM:217
XtRemoveAccelerators PM:206
Xt Remove Actions PM:145
XtRemoveAUActions PM:145
XtRemoveAllCalibacks RM:218
XtRemoveCallback PM:80, 360; RM:219
XtRemoveCallbacks PM:80; RM:220
XtRemoveEventHandler PM:183,220;
RM:221-222
XtRemoveGrab PM:372; RM:223
XtRemovelnput PM:226; RM:224
XtRemoveRawEventHandler PM:220;
RM:225-226
XtRemoveTimeOut PM:183, 229; RM:227
XtRemoveWorkProc PM:231, 232; RM:228,
323
XtResizeWidget PM:308, 319; RM:229, 341
XtResizeWindow RM:230
XtResource PM:239
XtResourceDefaultProc RM:314-315
example PM:256
XtResourceQuark address mode constant
PM:260
XtResourceString address mode constant
PM:260
XtRFile representation type PM:253
XtRFIoat representation type PM:253
XtR Font representation type PM:253
XtRFontStruct representation type PM:253
XtRFunction representation type PM:258
XtRImmediate representation type PM:242,
255
XtRInt representation type PM:253
XtRJustify representation type PM:257
XtROrientation representation type PM:257
XtRPixel representation type PM:253
XtRPixmap representation type PM:257
542
X Toolkit Intrinsics Programming Manual
XtRPosition representation type PM:253
XtRShort representation type PM:253
XtRTranslation Table representation type
PM:253
XtRUnsignedChar representation type
PM:253
XtRWidget representation type PM:257
XtScreen RM:231
XtScroUbarSetThumb RM:381
XtSelectionCallbackProc PM:282;
RM:316-317
XtSeiectionDoneProc PM;282; RM:318
XtSetArg PM:50, 51, 93, 119; RM:232-233
XtSetErrorHandler PM:387, 393; RM:234
XtSetErrorMsgHandler PM:387, 393;
RM:235
XtSetKeyboardFocus PM:391; RM:236-237
XtSetKeyTranslator RM:238
XtSetMappedWhenManaged RM:239
XtSetSelectionTimeout PM:302, 393; RM:240
XtSetSensitive PM:75,371;RM:241
XtSetSubvalues PM:266; RM:242-243, 275
XtSetValues PM:23, 49-51, 136, 140, 154, 157,
165-166, 174-176, 319, 338; RM:244-245,
334-335, 345
XtSetValuesFunc RM:319,334
XtSetValuesFunc function prototype PM:175
XtSetWarningHandler PM:387, 393; RM:246
XtSetWarningMsgHandler PM:387, 393;
RM:247
XtStringConversionWarning PM:263, 387;
RM:248
XtStringProc RM:320,336
XtStringSourceCreate RM:401
XtStringSourceDestroy RM:402
XtSupcrclass RM:249
XtTextBlock RM:399
XtTextChangeOptions RM:400
XtTextDisableRedisplay RM:399
XtTextDisplay RM:400
XtTextEnableRedisplay RM:399
XtTextGettnsertionPoint RM:400
XtTextGetOptions RM:400
XtTextGetSelectionPos RM:398
XtTextGetSource RM:401
XtTexflnvalidate RM:399
XtTextReplace RM:398
XtTextSetlnsertionPoint RM:400
XtTextSetLastPos RM:400
XtTextSetSelection RM:397
XtTextSetSource RM:401
XtTextTopPosition RM:400
XtTextUnsetSelection RM:398
XtTimeOut PM:393
XtTimerCallbackProc RM:321
XtToolkitlnitialize PM:30, 98, 243; RM:250
XtTranslateCoords PM:75, 360-361; RM:251
XtTranslateKey PM:392; RM:252-253
XtTranslateKeycode PM:392; RM:254-255
XtUninstallTranslations RM:256
XtUnmanageChild PM:319;RM:257
XtUnmanageChildren PM:319; RM:258
XtUnmapWidget PM:319;RM:259
XtUnrealizeWidget RM:260
XtVaCreateArgsList PM:428
XtVaGetApplicationResources PM:260
XtVaGetSubresources PM:260
XtVersion constant PM:151
XtVersionDontCheck constant PM:151
XtWarning PM:386-387, 393; RM:261
XtWarningMsg PM:386-387, 393; RM:262
XtWidgetGeometry PM:320-323
XtWidgetGeometry structure PM: 180- 182
XtWidgetProc PM: 148; RM:322, 332-345
XtWidgetToApplicationContext RM:263
XtWindow PM:176,378;RM:264
XtWindowToWidget PM:389; RM:265
XtWorkProc PM:393; RM:323-324
XUnGrabPointer Xlib function PM:352
XView PM:10
XYPixmap PM:515
zoomed window PM:515
ZPixmap PM:515
Index
543
NUTSHELL
O'Reilly & Associates, Inc.
Creators and Publishers of Nutshell Handbooks
Nutshell Handbooks
Learning the UNIX Operating System
DOS Meets UNIX
Learning the \'i Editor
UNIX in a Nutshell, System V
UNIX in a Nutshell. Berkeley
Handbooks on Communications:
!%@:: A Directory of Electronic-
Mail Addressing and Networks
Using UUCP ami Usenet
Managing UUCP and Usenet
Handbooks on Programming:
Using C on the UNIX System
Checking C Programs with lint
Understanding and Using COFF
Programming with curses
termcap and terminfo
Managing Projects with make
The X Window System series
Vol. 0 X Protocol Reference Manual
Vol. 1 Xlih Programming Manual
Vol. 2 Xlih Reference Manual
Vol. 3 X Window System User's Guide
Vol. 4 X Toolkit Intrinsics
Programming Manual
Vol. 5 X Toolkit Intrinsics Reference
Manual
Vol. 7 XView Programming Manual
For HyperCard on Macintosh:
UNIX in a Nutshell for HyperCard
(includes 1.8MB of HyperCard
stack ware. User' s Guide, and a copy of
Learning the UNIX Operating Svstem)
Other UNIX books:
UNIX Text Processing
Send me more information on:
Q Retail sales
I I Licensing
Q Review copies for instructors
I I Magazine press kits for new books
I I Education policy
I I Bookstore locations
LJ Overseas distributors
I — I Additional copy of Nutshell News
LJ Upcoming books on the subject:
LJ Writing a Nutshell Handbook
NUTSHELL
O'Reilly & Associates, Inc.
Creators and Publishers of Nutshell Handbooks
Nutshell Handbooks
Learning the UNIX Operating System
DOS Meets UNIX
Learning the vi Editor
UNIX in a Nutshell, System V
UNIX in a Nutshell. Berkeley
Handbooks on Communications:
!%@.v A Directory of Electronic
Mail Addressing and Networks
Using UUCP and Usenet
Managing UUCP and Usenet
Handbooks on Programming:
Using C on the UNIX System
Checking C Programs with lint
Understanding and Using COFF
Programming with curses
termcap and terminfo
Manavinv Projects with make
The X Window System series
Vol. 0 X Protocol Reference Manual
Vol. I Xlih Programming Manual
Vol. 2 Xlih Reference Manual
Vol. 3 A" Window System User's Guide
Vol. 4 X Toolkit Intrinsics
Programming Manual
Vol. 5 X Toolkit Intrinsics Reference
Manual
Vol. 7 XView Programming Manual
For HyperCard on Macintosh:
UNIX in a Nutshell for HyperCard
(includes 1.8MB of HyperCard
stackware, User's Guide, and a copy of
Learning the UNIX Operating Svstem)
Other UNIX books:
UNIX Te .\t Processing
Send me more information on:
LJ Retail sales
I I Licensing
I | Review copies for instructors
I I Magazine press kits for new books
I I Education policy
I I Bookstore locations
LJ Overseas distributors
I — I Additional copy of Nutshell News
I I Upcoming books on the subject:
LJ Writing a Nutshell Handbook
Please send me the information
I have asked for on the reverse
side of this card.
Name _
Company
Address
City
State. ZIP
(Fill out or tape
business card here)
Nutshell Handbooks
O'Reilly & Associates, Inc.
632 Petaluma Avenue
HANDBOOKS' SebaStOpol CA 95472
Name
Please send me the information
I have asked for on the reverse
side of this card.
Company
Address -
City
State, ZIP
(Fill out or tape
business card here)
Nutshell Handbooks
O'Reilly & Associates, Inc.
632 Petaluma Avenue
HANDBOOKS' SebaStOpol CA 95472
Overseas Distributors
Effective January 1, 1990, customers outside the U.S. and Canada will be able to order
Nutshell Handbooks and the X Window System Series through distributors near them. These
overseas locations offer international customers faster order processing, more local bookstores
and local distributors, an increased representation at trade shows worldwide, as well as the high
level, quality service our customers have always received.
AUSTRALIA & NEW ZEALAND
(orders and inquiries)
Addison-Wesley Publishers. Pty. Ltd.
6 Byfield Street
North Ryde, N.S.W. 21 13
AUSTRALIA
Telephone: 61-2-888-2733
FAX: 61-2-888-9404
UNITED KINGDOM & AFRICA
(orders and inquiries)
Addison-Wesley Publishers. Ltd.
Finchampstead Road
Wokingham. Berkshire RG 1 1 2NZ
ENGLAND
Telephone: 44-734-794-000
FAX: 44-734-794-035
EUROPE & THE MIDDLE EAST
(orders and inquiries)
Addison-Wesley Publishers B.V.
De Lairessestraat 90
1071 PJ Amsterdam
THE NETHERLANDS
Telephone: 31-20-764-044
FAX: 31-20-664-5334
ASIA inquiries (excluding Japan)
Addison-Wesley Singapore Pte. Ltd.
15 Beach Road #05-09/10
Beach Centre
Singapore 0718
SINGAPORE
Telephone: 65-339-7503
FAX: 65-339-9709
ASIA orders (excluding Japan)
Addison-Wesley Publishing Co., Inc.
International Order Department
Route 128
Reading, Massachusetts 01867 U.S.A.
Telephone: 1-617-944-3700
FAX: 1-617-942-2829
JAPAN
(orders and inquiries)
Toppan Company. Ltd.
Ochanomizu Square B, 1-6
Kanda Surugadai
Chiyoda-ku. Tokyo 101
JAPAN
Telephone: 81-3-295-3461
FAX: 81-3-293-5963
X Toolkit Intrinsics Programming Manual
Volume Four, X Toolkit Intrinsics Programming Manual, is a complete pro
grammer's guide to the X Toolkit (Xt). Xt is a library of C language routines
designed to facilitate the design of user interfaces, with reusable components
called widgets. This 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, such as OSF/Motif or
AT&T's OPEN LOOK widget set. It includes chapters on:
• Introduction to the X Window System
• Building applications with widgets
• A bitmap editor constructed with widgets
• Inside a widget
• Basic widget methods
• Events, translations and accelerators
• Event handlers, timeouts and work procedures
• Resource management and type conversion
• Interclient communication
• Geometry management
• Menus, gadgets and cascaded pop ups
• Miscellaneous Toolkit programming techniques
• Comparison of Athena, OSF/Motif and AT&T's OPEN LOOK
widgets
as well as a glossary, a master index and many useful appendices.
This book is designed to be used with Volume Five, X Toolkit Intrinsics
Reference Manual, which provides reference pages for each of the Xt functions
and the widget classes defined by Xt.
566 pages Volume 4 alone ISBN: 0-937 175-34-X Set with Volume 4 ISBN: 0-937175-33-1
O'Reilly & Associates, Inc.