Skip to main content

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

See other formats


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.