0% found this document useful (0 votes)
20 views

photon_prog_guide

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

photon_prog_guide

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 646

Photon microGUI

Programmer’s Guide

For Photon 1.14

 2005, QNX Software Systems


 1995 – 2005, QNX Software Systems. All rights reserved.

Published under license by:

QNX Software Systems Co.


175 Terence Matthews Crescent
Kanata, Ontario
K2M 1W8
Canada
Voice: +1 613 591-0931
Fax: +1 613 591-3579
Email: [email protected]
Web: http://www.qnx.com/

Publishing history
November 1995 First edition
December 1996 Second edition
April 1998 Third edition

Electronic edition published 2005.

Technical support options


To obtain technical support for any QNX product, visit the Technical Support section in the Support area on our website
(www.qnx.com). You’ll find a wide range of support options, including our free web-based QNX Developer’s Network.

QNX, Photon microGUI, and Neutrino are registered trademarks of QNX Software Systems in certain jurisdictions. All other trademarks and registered
trademarks belong to their respective owners.
Contents

About This Guide xxv


Typographical conventions xxvii
Note to Windows users xxviii
What you’ll find in this guide xxix

1 Introduction 1
Overview of the Photon architecture 3
Photon Application Builder — PhAB 5
Widget concepts 8
Widget life cycle 12
Widget geometry 13
Programming paradigm 17
Text-mode application 17
Non-PhAB application 18
PhAB application 19
Photon libraries 20
Building applications with PhAB — an overview 22
Step 1: Create modules 22
Step 2: Add widgets 23
Step 3: Attach callbacks 24
Step 4: Generate code 24
Step 5: Run your application 25
Step 6: Repeat any previous step 25
Writing applications without PhAB 25

September 20, 2005 Contents iii


 2005, QNX Software Systems

2 Tutorials 27
Before you start... 29
Tutorial 1 — Hello World 32
Creating the application 32
Generating code 33
Want more info? 34
Tutorial 2 — Editing Resources 35
Adding a button widget 35
Changing the border width 36
Changing the font 37
Changing the text alignment 38
Setting flags 38
Changing the fill color 39
Editing a pixmap 41
Editing multiline text 42
Editing a list of text items 43
Want more info? 45
Tutorial 3 — Creating Menus and Menubars 46
About link callbacks 46
About instance names 46
Creating a menubar 47
Creating the File menu module 48
Adding menu items 49
Creating the Help menu module 51
Attaching link callbacks 52
Setting up the code 54
Want more info? 55
Tutorial 4 — Creating Dialogs 56
What you’ll learn 56
About dialogs 56
More on instance names 56
Attaching a dialog module 57

iv Contents September 20, 2005


 2005, QNX Software Systems

Adding widgets to the dialog 58


Adding a callback to the Done button 60
Modifying a generated code function 61
Compiling and Running 63
Want more info? 63
Tutorial 5 — Creating Windows 64
What you’ll learn 64
Creating a window 64
Attaching callbacks 65
Adding widgets 66
Generating and modifying the code 68
Compiling and running 72
Want more info? 73

3 PhAB’s Environment 75
Menubar 77
Speedbar 78
Detaching the speedbar 78
Reattaching the speedbar 78
Hiding the speedbar 78
Widget bar 79
Modes (create vs select) 80
Customizing the widget bar 81
Control Panel 82
Resources mode 83
Callbacks mode 85
Module Tree mode 87
Module Links mode 88
Customizing your PhAB environment 89
General preferences 90
Color preferences 91
Dragging preferences 91
Help 91

September 20, 2005 Contents v


 2005, QNX Software Systems

Exiting PhAB 92

4 Working with Applications 93


Creating an application 95
Opening an application 95
Saving an application 97
Naming or renaming an application 97
Saving an existing application 98
Overwriting an existing application 98
Closing an application 99
Specifying application startup information 99
Specifying a global header file 100
Initialization function 101
Command-line options 101
Mainloop function 103
Including instance names 104
Startup windows 104

5 Working with Modules 107


Overview 109
Modules as containers 109
Module types 109
Changing module resources 110
Anatomy of a module 110
How modules are saved 112
Displaying modules at run time 112
Using the module selector 112
Creating a new module 113
Viewing a module 114
Opening a module 114
Deleting a module 115
Window modules 115
Resizing a window module 116

vi Contents September 20, 2005


 2005, QNX Software Systems

Dialog modules 116


Resizing a dialog module 117
Menu modules 117
Opening the menu editor 118
Specifying instance names 119
Creating hotkeys and shortcuts 119
Resizing a menu module 120
Creating command items 120
Creating submenu items 122
Creating separator items 122
Creating toggle items 123
Creating function items 124
Moving menu items 124
Using a menu module 125
Picture modules 126
Displaying a picture 126
Using pictures as widget databases 126
Resizing a picture module 127
Icon modules 127
Naming the icon module 128
Specifying sizes and instance names 128
Other modules 129
Resizing an “other” module 129
Iconifying modules 130
Rearranging icons 130
Importing PhAB modules from other applications 130
Importing QNX Windows picture files 131
Closing a module 132
Positioning a module 132
Opening the location dialog 132
Selecting a module 134
Finding lost modules and icons 134

September 20, 2005 Contents vii


 2005, QNX Software Systems

6 Creating Widgets in PhAB 137


Types of widgets 139
Instance names 140
Default instance name 140
When to assign a unique name 141
Instance names and translations 141
Duplicate names 142
Creating a widget 142
Creating several widgets 143
Canceling create mode 143
Selecting widgets 143
A single widget 144
Multiple widgets 145
Widgets within a group 146
Hidden widgets 147
Positioning widgets with a grid 147
Aligning widgets 149
To another widget 149
To a parent container 149
Common User Access (CUA) and handling focus 150
Changing focus with the keyboard 150
Controlling focus 151
Focus callbacks 151
Focus-handling functions 152
Ordering widgets 152
Dragging widgets 153
Setting a widget’s x and y coordinates 154
Transferring widgets between containers 154
Resizing widgets and modules 154
Moving and resizing widgets with the nudge tool 155
Clipboard 156
Cutting and copying 156

viii Contents September 20, 2005


 2005, QNX Software Systems

Pasting 157
Viewing the clipboard 158
Editing the clipboard 158
Duplicating widgets and containers 159
Deleting widgets 159
Importing graphic files 159

7 Editing Resources and Callbacks in


PhAB 161
Editing widget resources 163
Pixmap editor 164
Setting the pixmap’s size 165
Choosing colors 166
How to draw and erase 166
Drawing freehand 167
Drawing lines, rectangles, and circles 167
Filling an enclosed area 168
Selecting an area 168
Nudging an area 168
Using the Pixmap Tools window 169
Other pixmap controls 171
Color editor 172
Ensuring color consistency 173
Flag/option editor 173
Flag resources 174
Option list resources 174
Font editor 175
List editor 176
Editing existing list items 178
Deleting list items 178
Number editor 178
Text editor 179
Multiline text editor 180

September 20, 2005 Contents ix


 2005, QNX Software Systems

Function editor 182


Callbacks 183
Editing callbacks 185
Module callbacks 187
Prerealize setup function 189
Postrealize setup function 189
Setup functions are stored in stub files 189
Code callbacks 189
Callback functions are stored in stub files 190
Hotkey callbacks 190
Hotkeys — the basics 191
Specifying the hotkey label 192
Specifying the callback 192
Processing hotkeys 194
Disabling hotkeys 195
Raw-event callbacks 196

8 Geometry Management 199


Container widgets 201
Geometry negotiation 201
Resize policy 203
Absolute positioning 207
Aligning widgets using groups 208
Joining widgets into a group 208
Accessing widgets in a group 209
Aligning widgets horizontally or vertically 209
Aligning widgets in rows and columns 210
Using the Group flags 211
Splitting apart a group 213
Constraint management using anchors 213
Anchor resources 215
Enforcing position or size constraints without anchors 218

x Contents September 20, 2005


 2005, QNX Software Systems

9 Generating, Compiling, & Running Code 221


Using the Build & Run dialog 223
Generating application code 225
What PhAB generates 225
Version control 227
Function prototypes 228
How application files are organized 230
Multiplatform applications 231
Single-platform applications 232
Converting to multiplatforms 233
Editing source 233
Choosing an editor or browser 234
Creating a source module 234
Changing the file display 234
Compiling & linking 235
Choosing the libraries 235
Running make 235
Running the application 237
Debugging 237
Modifying the debugger command 238
Including non-PhAB files in your application 239
Multiplatform applications 239
Single-platform applications 240
Adding libraries 240

10 Working with Code 241


Variables and manifests 243
Widget variables and manifests 243
Using the global variable and widget manifest 244
Handling multiple instances of a window 245
Internal link manifests 247
Icon manifests 247
Global header file 248

September 20, 2005 Contents xi


 2005, QNX Software Systems

Function names and filenames 249


Multithreaded programs 251
Initialization function 251
Processing command-line options 252
Mainloop function 254
Module setup functions 255
Code-callback functions 257
Initializing menus 258
Enabling, disabling, or toggling menu items 258
Changing menu-item text 259
Generating menu items 260

11 Manipulating Resources in Application


Code 267
Argument lists 269
Setting resources 271
Argument lists for setting resources 271
Calling PtSetResources() 276
Getting resources 277
Not using pointers 277
Using pointers 279
Calling PtGetResources() 286

12 Creating Widgets in Application Code 287


Creating widgets 289
Ordering widgets 290
All in the widget family 291
Manipulating callbacks in your code 292
Adding callbacks 292
Callback invocation 294
Removing callbacks 295
Examining callbacks 296
Manipulating event handlers in your code 297

xii Contents September 20, 2005


 2005, QNX Software Systems

Adding event handlers 298


Removing event handlers 299
Event handler invocation 300

13 Accessing PhAB Modules from Code 301


Creating internal links 304
Using internal links in your code 305
Manifests 305
API 306
Example — displaying a menu 306
Using widget databases 308
Creating a database 309
Preattaching callbacks 310
Assigning unique instance names 310
Creating a dynamic database 310
Widget-database functions 311

14 International Language Support 315


Application design considerations 317
Size of text-based widgets 317
Justification 318
Font height 320
Hard-coded strings 321
Use of @ in instance names 322
Bilingual applications 323
Common strings 323
Generating a language database 324
Language editor 324
Starting the Language Editor within PhAB 325
Starting the Language Editor as a stand-alone application 326
Creating a new translation file 326
Editing an existing translation file 327
Translating the text 328

September 20, 2005 Contents xiii


 2005, QNX Software Systems

Hotkeys 329
Help resources 329
Running your application 330
Distributing your application 332

15 Context-Sensitive Help 335


Creating help text 337
Help files 337
Table-of-content files 340
Referring to help topics 341
Connecting help to widgets 343
Displaying help in the Helpviewer 343
Displaying help in a balloon 344
Help without the ? icon 344
Accessing help from your code 345

16 Interprocess Communication and Lengthy


Operations 347
Sending QNX messages 350
Receiving QNX messages 351
Adding an input handler 352
Removing an input handler 354
Message buffer size 354
Example — logging error messages 355
Example — replying to sin ver commands 358
Photon pulses 359
Photon application that receives a pulse 360
Photon application that delivers a pulse 369
Non-Photon application that delivers a pulse 373
Processing signals 373
Adding a signal-processing function 373
Removing a signal-processing function 375
Other I/O mechanisms 375

xiv Contents September 20, 2005


 2005, QNX Software Systems

Lengthy operations 376


Work procedures 377
Timers 383
Modal dialogs 383

17 Raw Drawing and Animation 393


PtRaw widget 395
Raw drawing function 396
Color 403
Arcs, ellipses, polygons, and rectangles 403
Rectangles 404
Rounded rectangles 405
Beveled boxes 406
Polygons 407
Arcs, circles, chords, and pies 409
Lines, pixels, and pixel arrays 411
Text 411
Bitmaps 412
Images 413
Palette-based images 414
Direct-color images 415
Gradient-color images 415
Creating images 415
Caching images 416
Transparency in images 416
Displaying images 417
Releasing images 418
Animation 419
Creating a series of snapshots 419
Cycling through the snapshots 421
Flickerless animation 422

18 Fonts 425

September 20, 2005 Contents xv


 2005, QNX Software Systems

Font names 427


Using PfQueryFonts() 428
FontDetails structure 429
Example 430

19 Printing 435
What’s in a print context? 438
Pp PC CONTROL control structure 444
Creating a print context 446
Modifying a print context 446
Calling PtPrintSelection() 447
Using the PtPrintSel widget 450
Calling PpPrintSetPC() 451
Starting printing 452
Drawing the desired widgets 455
Printing by damaging widgets 456
Printing by calling PpPrintWidget() 456
Printing a new page 457
Printing scrolling widgets 457
Suspending and resuming printing 461
Closing printing 461
Multiple print sessions 462
Freeing the print context 462
Example 463

20 Regions 467
Photon coordinate space 469
Region coordinates 470
Region origins 470
Initial dimensions and location 470
About child regions 473
Regions and event clipping 474
Placement and hierarchy 475

xvi Contents September 20, 2005


 2005, QNX Software Systems

Region hierarchy 475


Parent region 475
Brother regions 476
Default placement 477
Specific placement 480
Using regions 481
Opening a region 481
Placing regions 481
System information 483

21 Events 487
Pointer events 489
Emitting events 491
Targeting specific regions 493
Targeting specific widgets 494
Emitting key events 495
Event coordinates 496
Collecting events 496
Event compression 496
Dragging 496
Initiating dragging 497
Handling drag events 500

22 Window Management 505


Window-management flags 507
Window render flags 508
Window managed flags 508
Window notify flags 509
Notification callback 511
Example: verifying window closure 512
Getting and setting the window state 513
Managing multiple windows 515
Window-manager functions 515

September 20, 2005 Contents xvii


 2005, QNX Software Systems

Running a standalone application 516

23 Programming Photon without PhAB 517


Basic steps 519
Compiling and linking a non-PhAB application 520
Linking under QNX 4 520
Linking under QNX Neutrino 521
Sample application 521
What’s going on 522
Connecting application code to widgets 525
Callbacks 525
Event handling 526
Complete sample application 526

A Photon Architecture 529


Event space 531
Regions and events 532
Events 532
Initial rectangle set 532
Collected rectangle set 533
Regions 533
Sensitivity 535
Opacity 535
Attribute summary 536
Event logging 536
Event modification 536
Parent/child relationships 536
Photon coordinate space 537
Root region 537
Event types 538
How region owners are notified of events 538
Polling 538
Synchronous notification 539

xviii Contents September 20, 2005


 2005, QNX Software Systems

Asynchronous notification 539


Device region 539
Pointer focus 540
Keyboard focus 540
Drag events 541
Photon drivers 541
Input drivers 541
Output drivers 542
Photon window manager 544
Window frame regions 545
Focus region 545
Workspace region 545
Backdrop region 546

B Widgets at a Glance 547

C Unicode Multilingual Support 555


Wide and multibyte characters 557
Unicode 559
UTF-8 encoding 559
Other encodings 561
Keyboard drivers 562
Example: text widgets 562
Dead keys and compose sequences 563

Glossary 565

Index 587

September 20, 2005 Contents xix


List of Figures
Photon’s event space from the user’s perspective. 4
The Photon widget hierarchy. 10
Life cycle of a widget. 12
Anatomy of a PtBasic widget. 14
Widget position and dimensions. 15
Origin of a widget and the position of its children. 16
Structure of a text-mode application. 17
Structure of a Photon application written without PhAB. 19
Structure of a Photon application written with PhAB. 20
Overview of PhAB’s user interface. 30
PhAB’s menubar. 77
PhAB’s speedbar. 78
PhAB’s widget bar. 79
Customizing the widget bar. 81
Anatomy of PhAB’s control panel. 82
Resources mode for the control panel. 84
Callbacks mode for the control panel. 86
Module Tree mode for the control panel. 87
Module Links mode for the control panel. 88
Setting PhAB preferences. 89
Application Selector dialog. 96
Application Startup Information dialog. 100
Anatomy of a typical PhAB module. 111
Module Selector dialog. 113
Menu editor. 118
Styles of menu separators. 123

September 20, 2005 List of Figures xxi


 2005, QNX Software Systems

Location dialog. 133


Editing a widget’s instance name. 140
Grid Settings dialog. 148
Common buttons for resource editors. 163
Sample pixmap editor session. 165
Pixmap Tools window. 169
Color Editor. 172
Flag/Option Editor. 174
Font Editor. 175
List Editor. 177
Number Editor. 179
Text Editor. 179
Multiline Text Editor. 181
Function Editor. 182
Callback Editor. 186
Callback Editor fields for module-type link callbacks. 187
Hotkey field in the Callback Editor. 193
Event Mask field in the Callback Editor. 197
Example of anchoring. 214
Sample Build & Run session. 224
Directories for a PhAB application. 231
A sample search window. 246
Internal Module Links dialog. 304
Widget database used for PhAB’s interface. 309
PhAB Language Editor. 325
Language Selection dialog. 327
Filling a simple polygon. 408
Filling an overlapping polygon. 408
Dialog created by PtPrintSelection(). 447
A PtPrintSel widget. 450
Photon coordinate space. 469
Regions and event clipping. 474

xxii List of Figures September 20, 2005


 2005, QNX Software Systems

Hierarchy of regions for a typical Photon system. 475


A region’s rectangle set. 533
Exploded view of Photon’s regions. 534

September 20, 2005 List of Figures xxiii


About This Guide

September 20, 2005 About This Guide xxv


 2005, QNX Software Systems Typographical conventions

Typographical conventions
Throughout this manual, we use certain typographical conventions to
distinguish technical terms. In general, the conventions we use
conform to those found in IEEE POSIX publications. The following
table summarizes our conventions:

Reference Example
Code examples if( stream == NULL )
Command options -lR
Commands make
Environment variables PATH
File and pathnames /dev/null
Function names exit()
Keyboard chords Ctrl – Alt – Delete
Keyboard input something you type
Keyboard keys Enter
Program output login:
Programming constants NULL
Programming data types unsigned short
Programming literals 0xFF, "message string"
Variable names stdin
User-interface components Cancel

We format single-step instructions like this:

➤ To reload the current page, press Ctrl – R.

We use an arrow (→) in directions for accessing menu items, like this:

September 20, 2005 About This Guide xxvii


Typographical conventions  2005, QNX Software Systems

You’ll find the Other... menu item under


Perspective→Show View.

We use notes, cautions, and warnings to highlight important


messages:

☞ Notes point out something important or useful.

!
CAUTION: Cautions tell you about commands or procedures that
may have unwanted or undesirable side effects.

WARNING: Warnings tell you about commands or procedures


that could be dangerous to your files, your hardware, or even
yourself.

Note to Windows users


In our documentation, we use a forward slash (/) as a delimiter in all
pathnames, including those pointing to Windows files.
We also generally follow POSIX/UNIX filesystem conventions.

xxviii About This Guide September 20, 2005


 2005, QNX Software Systems What you’ll find in this guide

What you’ll find in this guide


The Photon Programmer’s Guide is intended for developers of Photon
applications. It includes the following:

¯ an introduction to Photon and the Photon Application Builder


(PhAB)

¯ a set of tutorials to get you started using PhAB

¯ a description of PhAB’s environment

¯ how to develop PhAB applications:


- working with an application as a whole
- working with an application’s modules
- creating widgets in PhAB
- editing a widget’s resources and callbacks in PhAB
- managing widget geometry
- generating, compiling, and running code
- writing code for a PhAB application
- manipulating widget resources in application code
- creating widgets in application code for a dynamic user
interface

¯ advanced programming techniques:


- accessing PhAB modules from your application’s code
- international language support
- context-sensitive help
- interprocess communication (IPC) and lengthy operations
- raw drawing and animation
- fonts
- printing
- working with regions
- handling events

September 20, 2005 About This Guide xxix


What you’ll find in this guide  2005, QNX Software Systems

- window management

¯ developing Photon applications without PhAB (for those who


insist on doing everything “by hand”)

¯ additional topics, each in an appendix:


- Photon architecture
- widgets at a glance
- Unicode multilingual support

¯ a glossary

xxx About This Guide September 20, 2005


Chapter 1
Introduction

In this chapter. . .
Overview of the Photon architecture 3
Photon Application Builder — PhAB 5
Widget concepts 8
Programming paradigm 17
Photon libraries 20
Building applications with PhAB — an overview 22
Writing applications without PhAB 25

September 20, 2005 Chapter 1 ¯ Introduction 1


 2005, QNX Software Systems Overview of the Photon architecture

By now, you’ve probably seen and tried various Photon applications


— the window manager, Helpviewer, Msgpad, and so on — and
you’re ready to develop your own. This chapter introduces you to the
basic terms and concepts that you’ll use when developing a Photon
application.

Overview of the Photon architecture


The Photon manager runs as a small server process, implementing
only a few fundamental primitives. It creates a three-dimensional
event space populated by regions and events. This microkernel can’t
draw anything or manage a mouse, keyboard, or pen.
External, optional processes — including the device drivers, and
window and other managers — implement the higher-level
functionality of the windowing system. They communicate by
emitting events through the Photon event space.
A Photon application consists of one or more flat, rectangular regions
that act as its “agents” in the event space. The application draws
inside the regions. Regions are stacked on top of each other in the
Photon event space. A region can have a parent region as well as
siblings.
The user sits outside the event space, looking in from the front. The
very back of the event space is a special region called the root region.

September 20, 2005 Chapter 1 ¯ Introduction 3


Overview of the Photon architecture  2005, QNX Software Systems

Event space

Root region
Application region

Child application region

Photon’s event space from the user’s perspective.

When you run the application, you interact with it, and it interacts
with other applications and Photon, in many ways:

¯ you press keys and mouse buttons

¯ the application performs graphical operations

¯ and so on

These interactions are called events, and they travel between regions
in the event space like photons or particles of light. For example:

¯ When you press a mouse button, the device driver emits an event
and sends it back through the event space (toward the root region).

4 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Photon Application Builder — PhAB

A region that’s interested in the event can catch it and process it,
for example, activating a push button.

¯ When your application wants to draw something, it emits an event


and sends it toward the front of the event space (toward the user).
A driver can catch the event and render the drawing on the screen.

Each region can determine which events it’s interested in by setting its
sensitivity and opacity:

¯ A region that’s sensitive to a type of event notifies the application


whenever such an event intersects it.

¯ A region that’s opaque to a type of event blocks it by clipping its


own area out of the event’s area.

For more information, see the Photon Architecture appendix.

Photon Application Builder — PhAB


Your Photon development system includes a very powerful
development tool called the Photon Application Builder (PhAB). It’s
a visual design tool that generates the underlying C and/or C++ code
to implement your application’s user interface. With PhAB you can
dramatically reduce the amount of programming required to build an
application. You can save time not only in writing the user interface
portion of your code, but also in debugging and testing. PhAB helps
you get your applications to market sooner and with more
professional results.
PhAB takes care of designing and creating windows, menus, dialogs,
icons, widgets (buttons, labels, and so on), and widget callbacks with
many extensions. PhAB lets you access and create PhAB modules
within your own code. It also provides a number of utility functions to
set up databases of widgets that you can reuse as many times as you
need, rather than create widgets from scratch.

September 20, 2005 Chapter 1 ¯ Introduction 5


Photon Application Builder — PhAB  2005, QNX Software Systems

Get immediate results


PhAB lets you bypass the trial-and-error process of creating a user
interface by hand. Instead of having to write code for every button,
window, and other widget, you just “point and click” to create the
widgets you want.
As soon as you create a widget, PhAB displays it on the screen, along
with all the resources that control how the widget looks and behaves.
Changing any widget resource is easy — just click on the resource,
choose a new value, and you’re done. It’s just as easy to move or
resize a widget — simply point to the widget and drag the mouse.

Concentrate on functionality
Like other Graphical User Interface (GUI) development environments,
PhAB lets you attach code functions to a widget’s callbacks so you
can implement your application’s main functionality. For example,
you can attach a code function to a button so that the function will be
invoked whenever the user clicks on the button. Unlike many other
GUI environments, however, PhAB doesn’t force you to write and
attach the code needed to “glue” the different parts of your interface
together. Instead, you can attach a widget’s callbacks directly to any
window, dialog, or menu. The only code you have to worry about is
the code specific to your application.

Create prototypes without writing code


Once you’ve completed any part of a user interface, you can have
PhAB generate all the C and/or C++ code required to bring the
interface to life. Which means you can create a complete prototype
without having to write a single line of code.
After you’ve generated and compiled the code, you can run the
prototype to see how the interface works. For example, if you linked a
button to a dialog, clicking on the button will now cause the dialog to
pop up. You immediately get a sense of how the interface will “feel”
to the user. In fact, PhAB makes the process of building and testing so
efficient that you can even sit down with your users and design
prototypes together.

6 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Photon Application Builder — PhAB

After you’ve finished a prototype, you can build it into your working
application. Or you can stop prototyping at any point, write some
callback functions, experiment with your application to see how it
works, and then return to prototyping. You’re always free to fine-tune
all aspects of your application until it looks and works just the way
you want.

Cut code size


Your application may need to use the same widgets in several parts of
its interface. With PhAB, you don’t have to set up these widgets every
time they’re needed. Instead, you define the widgets just once, place
them in a widget database, and then, using C functions provided by
PhAB, reuse the widgets as often as you want. By taking this
approach, you can reduce the code required to create a widget to a
single line.

Create consistent applications


With PhAB you rarely have to build an application from scratch. For
example, if you’ve already created windows and dialogs for an
existing application, you’re free to drop these into a new application.
You can also create a central database of widgets that you import into
all your applications to create a consistent look and feel.

Create all kinds of applications


With PhAB, you can speed up development without compromising
functionality. So you’re free to create all kinds of applications. For
example, we used PhAB to build almost all the applications that ship
with Photon, including the Helpviewer, Terminal application, Desktop
Manager, Msgpad, Snapshot, all games and demos — even PhAB
itself!
The best introduction to PhAB is using it, so start by working through
the tutorials. Within a very short time, you’ll be able to put together
very detailed prototypes. When you’re ready to start programming
your application, you can then read the sections pertaining to the
widgets you’re trying to use.

September 20, 2005 Chapter 1 ¯ Introduction 7


Widget concepts  2005, QNX Software Systems

We provide complete source code for all the demos and games built
with PhAB. You can load any of them into PhAB and review them for
ideas within your own applications. The Video Poker application is a
good example that uses most of PhAB’s features.

Widget concepts
When creating a new user interface (UI), it’s much simpler to
compose the interface from a set of standard components, such as
sliders, lists, menus, and buttons, than to implement each UI element
from scratch. Each standard component included in the UI is an
object called a widget.
Photon widgets implement a set of UI components that are more or
less consistent with other windowing systems that you may have seen.
The widget set is built on an object-oriented framework loosely based
on the X Toolkit Intrinsics library (Xt). If you’re already familiar with
Xt, you’ll see that many of the same concepts apply here.
A widget combines the data and operations required to implement a
particular UI element. Grouping data and operations into an object
like this is called encapsulation. A widget encapsulates the
knowledge of how to:
¯ draw itself
¯ respond to user events (e.g. pressing a pointer button)
¯ repair itself by redrawing when it’s damaged (for example, when a
window that obscures it closes)
In addition, there are some widgets called containers that hold other
widgets and manage their layout.
A widget also hides the details of how it performs these
responsibilities from the outside world. This principle, known as
information hiding, separates the widget’s internal implementation
from its public interface.
The public interface consists of all the attributes visible to other
objects as well as the operations other objects may perform on the

8 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Widget concepts

widget. The attributes in the widget’s public interface are called


resources.

☞ The advantage to you as a programmer is that you don’t have to know


the implementation details of a widget to use it — you just need to
know the public interface for the widget, how to create and destroy
the widget, and how to manipulate its resources.

Not every object is unique. Objects that perform the same function
and provide the same public interface belong to the same class.
Widgets that provide the same UI component belong to the same
widget class.
Several widget classes may have attributes and operations in common.
In such cases, these widget classes may be categorized as subclasses
of the same superclass or parent class. The attributes and operations
are encapsulated in the superclass; the subclasses inherit them from
the parent class. The subclasses themselves are said to be inherited
from the superclass.
The Photon library allows a widget class to be inherited from only
one widget class. This relationship is known as single inheritance.
The relationships between all of the widget classes can be drawn as a
tree known as the class hierarchy.

September 20, 2005 Chapter 1 ¯ Introduction 9


Widget concepts  2005, QNX Software Systems

PtWidget AwFileSelect
AwMessage
PtBasic PtBitmap
PtCalendar
PtClock
PtContainer PtCompound PtComboBox
PtDivider
PtGenList PtGenTree PtFileSel
PtTree
PtList
PtMenuButton
PtMultiText
PtNumeric PtNumericFloat
PtNumericInteger
PtDBContainer
PtFontSel
PtGroup PtMenu
PtMenuBar
PtMessage
PtHtml
PtPane PtBkgd
PtPrintSel
PtRegion
PtScrollArea
PtTerminal PtTty
PtUpDown
PtWindow PtIcon
PtGauge PtSlider
RtProgress
PtGraphic PtArc
PtBezier
PtEllipse
PtLine
PtPixel
PtPolygon
PtRect
PtGrid
PtLabel PtButton PtTab
PtMenuLabel
PtText
PtToggleButton PtOnOffButton
PtRaw
PtScrollbar
PtSeparator
RtMeter
RtTrend
PtTimer

The Photon widget hierarchy.

10 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Widget concepts

The nesting of widget instances in your application’s GUI produces


another widget hierarchy, called the widget family to distinguish it
from the widget class hierarchy.
The Photon widget library acts like a widget factory. It provides a set
of functions that allow the programmer to create a new widget of a
particular widget class and then manipulate that widget. Once
created, the widget has all the characteristics of the widget class.
Because of inheritance, it also has all the characteristics of the
superclasses of its widget class.
The new widget is an instance of the widget class. Creating a new
widget of a particular class is thus also called instantiating the widget.
This term isn’t entirely accurate, however, because you’re really
instantiating the widget class. This reflects a tendency found
throughout this guide to refer to both widgets and widget classes
simply as “widgets.”
The widget’s resources are used to configure its appearance or
behavior. You can edit resources in PhAB, and after the widget has
been created you can change many of them with a call to
PtSetResources(). Resources are used extensively to control the data
displayed by a widget and to customize how it’s displayed. For
example:

¯ the Pt ARG TEXT STRING resource for a PtLabel widget is the


string that it displays.

¯ the resources for a PtButton widget specify whether the button


displays a string and/or an image, its text, image, color, and what
happens when the user selects the button.

An important type of resource provided by widgets is the callback


list, which is a list of functions that will be called by the widget in
response to some significant user event. For example, a text field
widget calls the functions in one of its callback lists whenever the
user enters a new value and presses Enter. When you develop an
application, you can add callbacks to a widget’s callback list in order
to perform the appropriate action in response to a user event.

September 20, 2005 Chapter 1 ¯ Introduction 11


Widget concepts  2005, QNX Software Systems

Widget life cycle


A widget has an inherent life cycle, as shown below.

Create

Realize

Unrealize

Destroy

Life cycle of a widget.

1 When the widget is required, it’s created or instantiated; then


its attributes may be manipulated, or operations may be
performed on it.

2 After a widget has been created, it’s not immediately visible in


the UI. It must be realized. If you’re using PhAB, your widgets
are realized automatically; if you’re not using PhAB, you must
realize them using PtRealizeWidget().
Realizing a widget automatically realizes all its descendants.
Photon guarantees that all the descendants will be realized prior
to the widget itself, so the widget can calculate its initial size
based on the sizes of its children. You may choose to have the
application notified that the widget has been realized by
registering a callback on the Pt CB REALIZED callback list.

3 You can temporarily hide a widget from the UI by unrealizing it


using PtUnrealizeWidget(). As with realization, you can notify
the application using the Pt CB UNREALIZED callback
resource.

12 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Widget concepts

4 When the widget is no longer required, you can destroy it.


You can destroy a widget with the PtDestroyWidget() call. The
call doesn’t actually destroy the widget immediately — it’s
marked to be deleted by the toolkit at an appropriate time and
added to a list of widgets to be destroyed. These widgets are
normally destroyed within the main loop of the application,
after all the callbacks associated with an event have been
invoked.
You can choose to have the application notified when the
widget is actually destroyed by registering a function with the
destroy callback list (Pt CB DESTROYED) for the widget. This
is especially useful for cleaning up data structures associated
with the widget.

Widget geometry
You can think of a widget as a painting or mounted photograph. The
widget is held by a frame called a border. For a widget, the border is
the beveled edge that may be drawn around the outside.
The part of a widget that’s used for drawing is called the canvas. For
PtWidget, this is the area inside the widget’s borders. For PtBasic
and its descendants, the canvas is the area inside the widget’s border
and margins. Other widgets, such as PtLabel, define other margins.
The margins that form a matt and obscure any part of the canvas
extending beyond the cut-out area. This cut-out region is sometimes
referred to as the clipping area.

September 20, 2005 Chapter 1 ¯ Introduction 13


Widget concepts  2005, QNX Software Systems

Container widget Clipped child

Canvas (or clipping area)

Margin

Border

Anatomy of a PtBasic widget.

☞ The canvas and margins are shown in different colors in the above
diagram for the sake of clarity. In an actual widget, they’re the same
color.

A widget has several important attributes that define the geometry of


these elements. The dimension of the widget, Pt ARG DIM, is the
overall size of the margins. The border width,
Pt ARG BORDER WIDTH, is the width of the border:

14 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Widget concepts

Origin of parent
x

Margin
y width

POS (x, y)
Border
Margin height

DIM
(height)

Margin height

DIM (width)
Border

Widget position and dimensions.

The amount of border provided by the margins is determined by the


cumulative space on each side of the widget. PtBasic defines the
Pt ARG MARGIN WIDTH and Pt ARG MARGIN HEIGHT
resources, which determine the minimum width and height of the
margin.
Other widget classes define their own margin resources. These may
be added to the basic margin width or height to determine the total
size of the border. For example, the label widget provides separate
margins for the left, right, top, and bottom of the widget. These are
added to the basic margin width and height to determine the amount
of border to leave on each side of the canvas.
The origin of the widget (for the purposes of any drawing it performs
or positioning of any children) is the upper left corner of the canvas.
All coordinates specified for the widget will be relative to this
location. For example, if the widget is a container, the positions of all
the children are relative to this point:

September 20, 2005 Chapter 1 ¯ Introduction 15


Widget concepts  2005, QNX Software Systems

Container widget
POS (x, y)

Origin of container

POS (x, y)
Child widget

Origin of a widget and the position of its children.

For positioning children, containers are concerned with only the


outside edges of the widget’s border. These outside dimensions of the
widget are known as its extent. A widget’s extent is determined by
taking the dimensions of the widget and adding the border width to
each side.
The position of the widget is maintained by the Pt ARG POS
resource. This position is the point at the upper left corner of the
outside of the widget’s border. A container positions its children by
adjusting this resource.
Consequently, modifying the border width of the widget doesn’t
affect the widget position. If the border width is increased, the lower
right-hand corner of the widget extent and the internal area of the
widget (defined by its internal dimensions) are both shifted down and
to the right to accommodate the change.
The position and dimensions of the widget can be accessed or
modified simultaneously using the Pt ARG AREA resource provided
by the widget.

16 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Programming paradigm

Programming paradigm
Let’s compare how you write a text-mode application, a non-PhAB
(Photon) application, and a PhAB application.

Text-mode application
When you write a non-Photon (text-mode) application, you generally
concentrate on the main program, from which you do such things as:
¯ initialize the application
¯ set up signal handlers
¯ send and receive messages
¯ iterate
¯ call subroutines, as required
¯ communicate with the console
¯ and eventually exit.
Main program

Signal
handlers
Signals

Message
handler
Messages

Message
handler
functions Console
exit()

Structure of a text-mode application.

September 20, 2005 Chapter 1 ¯ Introduction 17


Programming paradigm  2005, QNX Software Systems

Non-PhAB application
A Photon application written without PhAB is similar to a text-mode
application, except that you also:

¯ instantiate, initialize, and realize the application’s widgets

¯ set the widget’s resources, including those for:


- size and position
- anchoring
- text
- callback lists
- etc.

¯ write callback routines to handle widget events. In these you may


need to:
- create windows and their widgets, set their resources, and
realize them
- create menus out of PtMenuButton widgets, set resources and
callbacks, and realize the menus
- destroy widgets
- etc.

¯ call PtMainLoop() in your main program to handle events.

Usually one of your callbacks exits the application. Writing an


application without PhAB means you’ll be working directly with the
widgets — a lot.

18 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Programming paradigm

Main program

Initialize application Signal


functions
Create top-level window
and icon
Message
Attach callbacks handler
Signals functions
Attach handlers

Messages Callbacks
PtMainLoop() - Create, realize,
destroy other
windows
Photon events - Handle interrupts
manually
- Create menus
- Create widgets
Graphics - Create dialogs
driver - Create widget
callbacks
- ...

exit()

Structure of a Photon application written without PhAB.

PhAB application
When you develop a PhAB application, the main program is provided
for you. Instead of worrying about the main program, you:

¯ provide a function that initializes the application

¯ set up signal handlers, which process the signals as they arrive and
call signal-processing functions that you write

¯ set up input functions for messages

¯ write callbacks to handle events from the widgets.

The main program loops forever, processing events as they occur.


Usually one of your callbacks ends the application. PhAB handles a

September 20, 2005 Chapter 1 ¯ Introduction 19


Photon libraries  2005, QNX Software Systems

lot of the details for you — you’ll concentrate on your application’s


functionality, not the widgets’.

Initialization
function

Signals Main program


(generated by PhAB) Signal
functions
Messages

Message
handler
Photon events functions

Graphics
driver Callbacks

exit()

Structure of a Photon application written with PhAB.

In addition, you don’t have to size and position widgets from your
code; you do it visually in PhAB. PhAB also looks after instantiating,
realizing, unrealizing, and destroying your widgets. PhAB even
provides a menu module to make creating menus easy. You can see
why we recommend using PhAB!

Photon libraries
The Photon application programming interface (API) is arranged into
a set of libraries, each distinguished by a two-character prefix:

¯ Ap — PhAB functions that work with modules, widget databases,


translation, and so on

20 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Photon libraries

¯ mbstr — multibyte-character string functions

¯ Pf — font services, including text metrics, and the generation of


bitmaps of character strings

¯ Pg — graphics functions that access a rich set of primitives in the


graphics drivers. These functions are used by the widget libraries
and can also be called directly when using the PtRaw widget (see
the chapter on Raw Drawing and Animation), or when building a
custom widget.

¯ Ph — Photon primitives that package up the draw requests and


forward them to the Photon microkernel for steering and clipping
until they arrive at the graphics driver ready to be rendered on
screen. Although not commonly used by application programmers,
these routines are heavily used by the graphics and widget
libraries.

¯ Pm — memory functions

¯ Pp — printing functions that set up and control printing

¯ Pt — widget functions for creating, realizing, and destroying


widgets, getting and setting resources, and so on. Besides using
the widgets in the Photon widget library, you can also use
third-party widgets or your own custom widgets.

¯ Px — extended functions that deal with help, loading images,


working with configuration files, and other useful routines. These
routines aren’t in the shared library; to use them, you’ll need to
link your application against phexlib3r.lib.

¯ Rt — functions for realtime widgets, such as RtTrend

¯ wc — wide-character string functions.

The functions and data structures in these libraries are described in


the Photon Library Reference.
You may want to link your applications with Photon’s shared library,
photon s.lib, which consists of the mbstr, Pf, Pg, Ph, Pm, Pp,

September 20, 2005 Chapter 1 ¯ Introduction 21


Building applications with PhAB — an overview  2005, QNX Software Systems

Pt, and wc routines. Using this shared library makes your application
much smaller. For more information, see the section “Choosing the
libraries” in the Generating, Compiling, & Running Code chapter.
If you need to determine the version number of the libraries, you can
use:

¯ Ph LIB VERSION (defined in <PhT.h>) when you compile or run


your application

¯ PhLibVersion() at runtime.

Both of these express the version number as:

major version * 100 + minor version

Building applications with PhAB — an


overview
Step 1: Create modules
To construct an application UI in PhAB, you start with primary
building blocks called modules. Modules look and work a lot like the
windows you see in most Photon applications.
You could design a UI with just one module. But for most
applications, you’ll probably use several modules and assign each a
different role. As a rule, each module groups together related
information and lets the user interact with that information in a
specific way. To help you handle the requirements of virtually any
application, PhAB provides several module types:

¯ window — normally used for the application’s major activities. A


typical application has one main window that opens when the
application starts up.

¯ dialog — allows the application to exchange information with the


user

22 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Building applications with PhAB — an overview

¯ menu — presents commands to the user


¯ icon — defines an icon for the application
¯ picture — can be used in different ways. For example, you can use
a picture to provide a convenient database of widgets or to change
the contents of an existing module
¯ others — predefined modules designed for specific purposes, such
as allowing the user to select files

For more information, see the Working with Modules chapter.

Step 2: Add widgets


Once you’ve created a module, you’re ready to place widgets into it.
To add a widget, just click on the appropriate icon in PhAB’s widget
bar, then click where you’d like the widget to go. PhAB lets you add
any widget that comes with the Photon development environment.
You can choose from widgets that:

¯ display or edit values — examples include labels, text, and


multiline text
¯ present choices — examples include lists, comboboxes, and groups
¯ display graphics — examples include bitmaps, images, lines,
rectangles, ellipses, and polygons
¯ display scrolling areas — examples include scrollbars and
scrollareas
¯ initiate actions — examples include buttons that contain text or
images

To customize how a widget looks and works, you set its attributes or
resources. PhAB’s Control Panel and resource editors make doing
this a snap. You just click on the resource you want to change, then
select or enter a new value.
For more information, see the Editing Resources and Callbacks in
PhAB chapter.

September 20, 2005 Chapter 1 ¯ Introduction 23


Building applications with PhAB — an overview  2005, QNX Software Systems

Step 3: Attach callbacks


You’ve created your modules and placed widgets into them. Now
you’re ready to define how the application will work. To do this, you
use callbacks.
Every Photon widget supports several callback types. To attach code
functions to a callback, you set a resource or use a provided
convenience function. The widget invokes the code function
whenever the callback’s conditions are met.
With PhAB, you’re free to concentrate on writing application-specific
code in your callbacks — you don’t have to create code to “glue”
interface components together. That’s because PhAB provides a new
level of callback called the link callback. Using link callbacks, you
can attach a widget’s callback resource directly to windows, dialogs,
menus, and many other things besides application code.
Link callbacks also let you add functionality that isn’t available when
you attach callbacks “by hand.” For example, if you link a dialog to a
button widget, you can specify where the dialog will appear. You can
also specify a setup function that will be automatically called before
the dialog is realized, after the dialog is realized, or both.
The extended functionality provided by link callbacks makes it much
easier to design a user interface. In fact, you can prototype an entire
application without having to write any code.
For more information, see the Editing Resources and Callbacks in
PhAB chapter.

Step 4: Generate code


You’ve created your application’s modules and created the link
callbacks to glue the various components together. Now you’re ready
to generate and compile code to turn your application design into a
working executable.
To do this, you open PhAB’s Build & Run dialog and just click on a
couple of buttons. That’s it. This dialog includes a file manager so

24 Chapter 1 ¯ Introduction September 20, 2005


 2005, QNX Software Systems Writing applications without PhAB

you can also edit source code and manipulate files — without having
to leave the PhAB environment.
For more information, see the Generating, Compiling, & Running
Code chapter.

Step 5: Run your application


After you’ve generated, compiled, and linked your application, you
can execute it right from the Build & Run dialog. Using this same
dialog, you can even launch your application under a debugger for
seamless debugging.
For more information, see the Generating, Compiling, & Running
Code chapter.

Step 6: Repeat any previous step


After you’ve generated and compiled your application, you’re free to
change the interface, attach callbacks, and regenerate the code as
often as you like.

Writing applications without PhAB


We recommend that you use PhAB to develop your application.
However, even if you don’t plan to use PhAB, you should read
through this guide completely (especially the Programming Photon
without PhAB chapter) in order to familiarize yourself with all the
Photon fundamentals before you can start creating applications. You
should then refer to the Widget Reference.

September 20, 2005 Chapter 1 ¯ Introduction 25


Chapter 2
Tutorials

In this chapter. . .
Before you start... 29
Tutorial 1 — Hello World 32
Tutorial 2 — Editing Resources 35
Tutorial 3 — Creating Menus and Menubars 46
Tutorial 4 — Creating Dialogs 56
Tutorial 5 — Creating Windows 64

September 20, 2005 Chapter 2 ¯ Tutorials 27


 2005, QNX Software Systems Before you start...

The best way to get to know PhAB is to use it. This chapter provides
hands-on sessions to give you a jump start on creating applications.
We’ll take a closer look at using PhAB in the chapters that follow.
The first two tutorials cover the basics: creating widgets, changing
how widgets look and behave, generating code, running your
application, and so on.
The remaining tutorials go beyond the basics to show you how to
create working menus, dialogs, and windows. When you’ve
completed these tutorials, you’ll be ready to start building almost any
Photon application.

Before you start...


Launch PhAB from the Desktop Manager by clicking on its icon:

Before you start the tutorials, take a moment to make yourself


familiar with PhAB’s user interface:

September 20, 2005 Chapter 2 ¯ Tutorials 29


Before you start...  2005, QNX Software Systems

Widget bar Menubar Speedbar

Work area Control Panel

Overview of PhAB’s user interface.

Widget bar Makes it easy to add widgets to your application.


Just click on the widget you want, then click where
you want it.
If you wish to identify any icon in the widget bar
by name, just pause the mouse pointer on that icon.

Menubar Import graphics, create windows and dialogs,


generate C and/or C++ code to implement your
entire user interface, and more.

Speedbar Save time with the speedbar — with a couple of


mouse clicks you can duplicate, move, align,
group or resize any number of widgets.

30 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Before you start...

Work area Provides a flexible area where you can work on


several application modules all at once.

Control Panel Lets you fully customize your application’s


widgets. You can choose text fonts, modify colors,
customize bitmaps, and attach callbacks that will
pop up dialogs or invoke C and/or C++ code
you’ve supplied.
If you close the Control Panel, you can redisplay it
by selecting Control Panel from the View menu.

September 20, 2005 Chapter 2 ¯ Tutorials 31


Tutorial 1 — Hello World  2005, QNX Software Systems

Tutorial 1 — Hello World


In this tutorial you learn how to use PhAB to create and compile a
simple application.

Creating the application


1 From the File menu, choose New to create a new application.
You’ll see the new application’s default base window and
PhAB’s Control Panel.

2 Go to the widget bar and click on the PtLabel widget icon:

3 Move the pointer into the application’s base window (the


pointer changes to a crosshair) and click anywhere near the
center of the window.
PhAB automatically does the following:
¯ creates a new PtLabel widget
¯ selects the widget so you can edit its resources
¯ places resize handles around the widget
¯ displays the widget’s resources in the Control Panel

4 Go to the Control Panel and click on the “Label Text” resource.


You’ll see PhAB’s multiline text editor, which displays the
current value (“Label”) for this resource.

5 Change the text to Hello World, then click on Done.


The widget now displays “Hello World”:

Hello World

6 You’re almost ready to generate code! But first, you must save
the application and give it a name.

32 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 1 — Hello World

From the File menu, choose Save As to open the Application


Selector dialog. Click on the Application Name field, type
tut1, then press Enter or click on Save Application.

7 Look at PhAB’s titlebar. It now indicates that the current


application is named tut1.

Generating code
Now that you’ve saved your application, you’re ready to generate,
compile, and execute it.

1 From the Application menu, choose Build & Run. You’ll see
the Build & Run dialog.

2 Click on the Generate button to start the code generation


process. You’ll see a progress dialog:
Generate Code - [tut1]

Code Generation Progress

100%

Messages
Generation Complete.

Done

Wait for the generation process to complete, then click on Done


to close the dialog.

3 Click on Make to compile the code. You’ll see the Make


Application dialog, which displays the files as they’re compiled.

4 Once the application has been compiled and linked, PhAB will
enable the dialog’s Done button. Click on Done to close the
dialog.

September 20, 2005 Chapter 2 ¯ Tutorials 33


Tutorial 1 — Hello World  2005, QNX Software Systems

5 Click on Run Application to run your new application. The


application will appear in its own window, with the text “Hello
World” in the center and the default title “My application” in
the title bar:
My Application

Hello World

Congratulations! You’ve just created your first Photon


application using PhAB.

6 To quit the application, click on the window menu button in its


top-left corner, then choose the Close item.

7 Click on Done to close the Build & Run dialog.

Want more info?


For more info on compiling, running, and debugging an application,
see the Generating, Compiling, & Running Code chapter.

34 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 2 — Editing Resources

Tutorial 2 — Editing Resources


This tutorial introduces you to PhAB’s resource editors, which let you
change how widgets look and behave. You’ll find out how to edit
virtually any kind of resource a widget may have, including:

¯ numerical resources (e.g. border width)

¯ text fonts

¯ text strings

¯ flags

¯ colors

¯ pixmaps

☞ In this tutorial, you’ll be asked to select various resources in the


Control Panel. If you don’t see a resource, resize the Control Panel
and/or use its scrollbar.

Adding a button widget


1 From the File menu, choose New to create a new application.

2 Click on PtButton in the widget bar:

3 Click near the center of the application’s window. You’ll see a


button widget.

4 Drag any of the button’s resize handles until the button matches
the following picture:

September 20, 2005 Chapter 2 ¯ Tutorials 35


Tutorial 2 — Editing Resources  2005, QNX Software Systems

base Test Wind

Button

Changing the border width


Let’s now edit a numerical resource — the button’s border width.

1 Click on the “Border Width” resource in the Control Panel.


You’ll see the number editor:

Number Editor

Border Width

Done Apply Default Cancel

This editor lets you change the value of any numerical widget
resource.
2 Change the value from 2 to 6. To do this, you can:
¯ Type in the new value.
Or
¯ Click on the increment/decrement buttons.

36 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 2 — Editing Resources

3 To apply the new value and close the editor, press Enter or click
on Done.

Changing the font


Let’s change the font of the button’s text:

1 Click on the “Font” resource. You’ll see the font editor, which
displays the button’s current font:

Font Editor
Font

Helvetica

12 Bold It alic A/A


A/A

AaBbCcXxYyZ z

Done Apply Default Cancel

This editor lets you change the text font of any widget that has
text.

2 Click on the font-name box or the point-size box, select a


typeface or size from the displayed list, and click on Apply.
The button now displays the new font.

3 Click on Default. The editor displays the widget’s default font,


but doesn’t apply the font to the widget.

4 If you want to keep the new font that you selected, click on
Cancel to ignore the default. If you want to apply the default,
click on Done. Either way, the editor closes.

September 20, 2005 Chapter 2 ¯ Tutorials 37


Tutorial 2 — Editing Resources  2005, QNX Software Systems

Changing the text alignment


Now let’s change the button’s horizontal text alignment:

1 Scroll through the Control Panel to find the “Horz Alignment”


resource, then click on it. You’ll see the flag/option editor,
which displays the widget’s current text alignment:

Flag/Option Editor
Horz Alignment
Pt_LEFT
Pt_RIGHT
Pt_CENTER

Done Apply Default Cancel

This editor serves a dual purpose in PhAB:


¯ to modify any resource — such as text alignment — that can
have one of several preset values
¯ to select one or more flags in any flags resource

2 Click on Pt LEFT or Pt RIGHT, then click on Apply. You’ll see


the button text move to the left or right edge of the button.

3 Click on Done.

Setting flags
Let’s now use the flag/option editor to set one of the widget’s flags:

38 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 2 — Editing Resources

1 Scroll through the Control Panel to find the “Flags” resource,


then click on it. The flag/option editor reopens, but this time it
shows the widget’s current flag settings:

Flag/Option Editor
Flags
Pt_SET
Pt_AUTOHIGHLIGHT
Pt_TOGGLE
Pt_SELECTABLE
Pt_SELECT_NOREDRAW
Pt_GHOST
Pt_HIGHLIGHTED
Pt_ETCH_HIGHLIGHT

Done Apply Default Cancel

A flags resource isn’t exclusive, so this time you can use the
editor to select multiple options, if desired.

2 Select the Pt ETCH HIGHLIGHT flag, then click on Done.


PhAB draws the button with an etched border:

Button

Changing the fill color


Let’s change a color resource — the button’s fill color.

1 Click on the button’s “Color: Fill” resource. You’ll see the


color editor, which displays the current fill color:

September 20, 2005 Chapter 2 ¯ Tutorials 39


Tutorial 2 — Editing Resources  2005, QNX Software Systems

Color Editor

Color: Fill Base Colors

Transparent

Color M odel Custom Colors M ix


RGB Model HSB Model

Done Apply Default Cancel

This editor lets you edit any color resource. It provides several
preset base colors, which should work well with all graphic
drivers, and 48 customizable colors for drivers that support 256
or more colors.

2 Click on any color in the Base Colors set, then click on Apply.
The button is filled with the color you selected.

3 Select a color from the Custom Colors set. The sliders will
display the color’s Red/Green/Blue (RGB) values. Change
these values till you get a color you want, then apply your
changes.
If you’d like to experiment with the Hue/Saturation/Brightness
(HSB) color model, click on the HSB Model button.

4 Click on Done when you’ve finished experimenting with the


editor.

40 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 2 — Editing Resources

Editing a pixmap
Let’s now use the pixmap editor to edit a PtBitmap widget. This
editor is called “pixmap” instead of “bitmap” since it lets you edit
many types of image resources besides bitmaps.
A PtBitmap widget can be used as a button, or as a static graphic —
which is what we’ll create here.

1 Click on PtBitmap in the widget bar:

☞ If you don’t see this widget, add it to the widget bar. To do this,
choose the Customize Widget Bar item from the Options menu.
You’ll see a dialog that lets you add the widget. For more info, see
“Widget bar” section in the PhAB Environment chapter.

2 Move the pointer into the main window and click below the
button widget you created. You’ll see a PtBitmap widget.

3 Click on the Border Width resource in the Control Panel, and


set the border width to 0. Click on Done. Removing the border
makes the widget look like a graphic instead of a button.

4 Click on the “Bitmap” resource in the Control Panel to bring up


the pixmap editor.

5 Next, bring up the color editor to select a draw color. Just click
on the following button:

6 Select a color. You’ll see that the draw color in the pixmap
editor changes immediately. You’ll also see that the color
editor’s Apply, Default, and Cancel buttons are dimmed — they
aren’t required for the pixmap editor.

7 To draw a simple bitmap, you can:

September 20, 2005 Chapter 2 ¯ Tutorials 41


Tutorial 2 — Editing Resources  2005, QNX Software Systems

¯ click the left mouse button to fill a cell with the draw color
¯ click the right mouse button to fill a cell with the
background color
¯ hold down a mouse button and drag the pointer to draw
freehand
Feel free to try the other drawing tools.

8 When you’re done, click on the pixmap editor’s Done button to


apply your changes and close the editor.

Editing multiline text


Next, we’ll edit a multiline text resource — the text of a
PtMultiText widget.

1 Click on PtMultiText in the widget bar:

2 Move the pointer below the bitmap widget you’ve just created,
and drag until the new PtMultiText widget appears big
enough to hold a few lines of text.

3 Click on the “Text String” resource in the Control Panel to


bring up the multiline text editor:
Multi- Line Text Editor

Text String

Done Apply Default Cancel

42 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 2 — Editing Resources

4 Type a few lines of text. To create a new line, press Enter. For
example:
Mary hadEnter
aEnter
little lamb.Enter

5 Click on Done. Your text should appear exactly as you typed it.
If it doesn’t, try resizing the widget — the widget might not be
wide enough or tall enough.

6 For a different effect, select the “Horz Alignment” resource and


change the text alignment to Pt CENTER. As you can see, each
line is now centered individually.

7 If you haven’t already, resize the widget by dragging on one of


its resize handles. You’ll see the text update automatically to
adjust to the new size. For example:

Mary
had
a
little
lamb.

Editing a list of text items


Let’s now create a PtList widget and add text to the widget using
the list editor. This editor lets you add and edit text for any widget
that provides a list of text items.

1 Click on PtList in the widget bar:

September 20, 2005 Chapter 2 ¯ Tutorials 43


Tutorial 2 — Editing Resources  2005, QNX Software Systems


If you don’t see this widget, add it to the widget bar. To do this,
choose the Customize Widget Bar item from the Options menu.
You’ll see a dialog that lets you add the widget. For more info, see
“Widget bar” section in the PhAB Environment chapter.

2 Move the pointer into the application’s base window, and drag
the pointer until the new PtList widget appears big enough to
hold a few lines of text.
3 Click on the “List of Items” resource to bring up the list editor:
List Editor

List of Items
Insert After

Insert Before

Modify

Delete

Done Apply Default Cancel

4 Click on the text box at the bottom of the editor. You’ll see the
text-input cursor.
5 Type some text, then click on Insert After to place the first item
in the list.
6 Now let’s create the second item. Click in the text box, and type
Ctrl – U to erase the text in the text box, then type some new
text.
Click on Insert After to place this new item after the previous
item.

44 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 2 — Editing Resources

7 Repeat the above step as often as you’d like.

8 Click on Apply. The PtList widget should now display the


list you’ve created.

9 Now try editing the list:


¯ to modify an existing item — click on the item, edit the
item’s text, then click on Modify
¯ to delete an item — click on the item, then click on Delete

10 When you’re finished experimenting, click on Done to apply


your changes and close the editor.

If you wish to save this application, follow the steps from the first
tutorial to save the application as tut2. After saving, feel free to
generate, make, and run the application.

Want more info?


You now know the basics of editing any widget resource in PhAB. For
more information, see the following sections in the Editing Resources
and Callbacks in PhAB chapter:

To edit: See this section:


Bitmaps or images Pixmap editor
Colors Color editor
Flags Flag/option editor
Fonts Font editor
Lists of text items List editor
Numbers Number editor or Flag/option editor
Single-line text strings Text editor
Multiline text strings Multiline text editor

September 20, 2005 Chapter 2 ¯ Tutorials 45


Tutorial 3 — Creating Menus and Menubars  2005, QNX Software Systems

Tutorial 3 — Creating Menus and Menubars


About link callbacks
In this tutorial you’ll learn how to set up a link callback, one of the
key components of PhAB. To understand what a link callback is, let’s
start with some background info on widget callbacks.
Almost all widgets support a variety of callbacks. These callbacks
enable your application’s interface to interact with your application
code. For example, let’s say you want your application to perform an
action when the user clicks on a button. In that case, you would attach
a callback function to the button’s “Activate” callback.
In a typical windowing environment, you can attach only code
functions to widget callbacks. But whenever you use PhAB to create
a callback, you can go one step further and attach entire windows,
dialogs, menus, and much more. It’s this extended functionality that
we call a link callback.
PhAB provides two basic types of link callbacks:

¯ module-type link callback — lets you attach an application module


(such as a window, dialog, or menu) to any widget callback. The
module will open whenever the callback’s conditions are met. In
this tutorial, you’ll link a menu module to a button’s “Arm”
callback.

¯ code-type link callback — lets you attach a code function to any


widget callback. The widget will invoke the function whenever the
callback’s conditions are met. Note that some code-type link
callbacks let you close the parent module automatically. In this
tutorial, you’ll link a code function to a menu item’s callback.

About instance names


To access a widget from your application code, you must first give the
widget an instance name. Since all widget instance names reside in
the same global namespace, no two widgets within an application can
have the same instance name.

46 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 3 — Creating Menus and Menubars

We recommend that you start every instance name with a module


prefix. For example, if your base window has a PtButton widget
that contains the label text “Blue,” you could give this widget an
instance name of base blue.

Creating a menubar
To learn about using link callbacks, let’s create two functioning
menus — File and Help — that you can later incorporate into your
own applications.
In PhAB, menus are built in two pieces:

¯ a menu button, which you’ll click to display the menu

¯ a menu module, which contains the menu items

Using link callbacks, you’ll link the menu modules to the File and
Help buttons in a menubar. You’ll also link a code-type callback to
the Quit menu item in the File menu module. This callback will
enable the Quit item to close the application.

1 From PhAB’s File menu, choose New to start a new application.

2 Select the PtMenuBar widget from the widget bar, then click
anywhere in the main window. The menubar is automatically
positioned at the top of the window, and is as wide as the
window.
The menubar grows and shrinks as you change the width of the
window, and it always stays at the top of the window. You can
see this by clicking in the titlebar of the window, then resizing
the window by dragging on one of its resize handles.

☞ If you accidentally click on the Test tab, the window won’t resize or
accept new widgets. If this happens, just click on the Wind tab.
By the time you’re finished the following steps, the menubar
will look like this:

September 20, 2005 Chapter 2 ¯ Tutorials 47


Tutorial 3 — Creating Menus and Menubars  2005, QNX Software Systems

base Test Wind

File Help

3 Place a PtMenuButton widget in the menubar you just


created. The menu button is automatically centered vertically in
the menubar.

4 Go to the Control Panel and click on the text box labeled


“Widget Instance Name.” Change the button’s instance name to
base file, and press Enter:

Widget Instance Name F9 F10

base_file

5 Change the button’s Label Text resource to File.

6 Place another PtMenuButton widget next to the first. Change


its instance name to base help and its text to Help.

Creating the File menu module


Now that you have menu buttons, you need to create your menu
modules. Let’s start with the File menu.

1 From the Application menu, choose Menus to open the module


selector. This selector lets you create or view any type of PhAB
module.

2 In the Name text box, type filemenu, then press Enter. Since
this menu module doesn’t exist yet, PhAB asks you if it should
create the module. Click on Yes.
You’ll see the menu module appear in your work area and the
module’s name in the module selector’s scrolling list.

3 The module selector stays onscreen, allowing you to create


more modules. However, you need to create only one menu
right now, so click on Done to close the selector.

48 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 3 — Creating Menus and Menubars

Adding menu items


Let’s now add the following menu items to the File menu:
New
Save
Save As

Quit

☞ If you click on another module, the menu module will become


deselected, which means you won’t be able to work on it. To reselect
the menu module, click on its titlebar.

1 Click on the Menu Items resource in the Control Panel. You’ll


see the menu editor:
Menu: File - [Menu Items]

Menu Items Lev el: 1 Menu Item Item Ty pes


< NEW > Command
Item Text: Submenu
Separator
Accel Text:
Toggle
Inst Name: Function

Callback: None

Actions

Apply

Reset

Remov e

Done Cancel

If you look at the Menu Items list, you’ll see that the <NEW>
item is selected. This special item lets you add new menu items
to the menu.

2 To add your first menu item — which also happens to be called


“New” — click on the Item Text field, then type New.

September 20, 2005 Chapter 2 ¯ Tutorials 49


Tutorial 3 — Creating Menus and Menubars  2005, QNX Software Systems

3 Now give the item an instance name. In the Inst Name field,
type file new.

4 Click on Apply to add the item to the menu. You’ll see the
item’s name in Menu Items list, prefixed by C:. The C: means
this is a Command item; that is, an item that invokes a PhAB
callback.

5 Repeat the above steps to create the two menu items labeled
“Save” and “Save As.” Give these items the instance names
file save and file as.

6 Up to now, you’ve added Command-type menu items. You’ll


now add a Separator item. Just click on the Separator button
near the upper-right corner. You’ll see a list of separator styles:
Separator Sty le

Single Line

Double Line

Single Dash Line

Double Dash Line

Etched - In

Etched - Out

Blank

7 Choose a style or just click on Apply to get the default


separator style, which is Etched - In.

8 Now let’s add the Quit item. Click on the Command button,
then specify Quit as the item text and file quit as the
instance name.

9 You’re finished with this menu module for now, so click on


Done. The module displays the items you just created:

50 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 3 — Creating Menus and Menubars

filemenu Menu
New
Save
Save As

Quit

10 You’ll want to keep this module neatly out of the way while
you work on your next task. So click on the module’s Work
menu button (upper-left corner) and choose Minimize.

Creating the Help menu module


Using what you just learned about creating a menu module, do the
following:

1 Create your Help menu module and give it a name of


helpmenu.

2 In this module, place a single command item called


About Demo and give the item an instance name of
help about. When you’re finished, minimize the module.

3 Save the application as tut3. (For info on saving, see the


previous tutorials or “Saving an application” in the Working
with Applications chapter.)

September 20, 2005 Chapter 2 ¯ Tutorials 51


Tutorial 3 — Creating Menus and Menubars  2005, QNX Software Systems

☞ If one of your menu modules seems to “disappear” (you may have


accidentally closed it or placed it behind another module), it’s easy to
bring the module back into view. See the “ Finding lost modules and
icons” in the Working with Modules chapter.

Attaching link callbacks


Let’s return to the menu buttons you created earlier and attach link
callbacks so that the buttons can pop up your menu modules.

Attaching a module-type link callback


1 Select the File menu button, then click on the Control Panel’s
Callbacks button (at the bottom of the panel). You’ll see the
File button’s callback list:

Class : PtMenuButton

Widget Instance Name F9 F10

base_file

Act ivat e None


Arm None
Disarm None
Menu None
Got Focus None
Lost Focus None
Hot key None
Raw Event None
Realized None
UnRealized None
Dest royed None

Resources Module Tree

Callbacks Module Links

52 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 3 — Creating Menus and Menubars

2 To have the File menu module pop up when you press the File
button, you need to attach an Arm callback to the button. By
attaching an Arm callback, you can open the menu using either
click-move-click or press-drag-release.
Click on Arm to bring up the callback editor.

3 The Module Types area of the editor let you choose the type of
module you wish to link to. Because you want to link the File
button to a menu module, click on Menu.

4 Click on the Name field and type filemenu, which is the name
you gave your File menu module. This links the menu button to
that module.
You can also select filemenu from a popup list of available
modules. To bring up the list, click on the icon to the right of
the Name field.

5 Click on Apply to add the link callback, then click on Done to


close the callback editor.

6 Repeat the above steps to link the Help menu button to the Help
menu module.

Attaching a code-type link callback


Let’s now attach a code-type link callback to the File menu’s Quit
item so that it can terminate the application.

1 Double-click on the iconified filemenu module. This opens


and selects the module.

2 Switch the Control Panel to Resources mode, then click on the


Menu Items resource.

3 Select the Quit item in the Menu Items list.

4 Click on the icon next to the Callback field to open the callback
editor:

September 20, 2005 Chapter 2 ¯ Tutorials 53


Tutorial 3 — Creating Menus and Menubars  2005, QNX Software Systems

5 When the editor opens, the default callback type is Code. Since
this is the type you want, all you have to do is specify the name
of the function you want to call.
The function should have a meaningful name. So type quit in
the Function field.

6 Click on Apply to update the Callbacks list, then click on Done


to close the editor.

7 Click on Done again to close the menu editor.

Setting up the code


You’ll now generate the code for your application and edit a generated
code stub so that the Quit item will cause your application to exit.

1 If you haven’t done so yet, save the application as tut3.

2 From the Application menu, choose Build & Run and generate
the application code.

3 After the generation process is complete, the Build & Run


dialog displays a list of generated files.
Scroll through the list until you see the quit.c file. This is the
generic code template that PhAB generated for your quit()
function.

4 You need to make the function exit the program. To do this,


select quit.c from the file list, click on the Edit button, then
change the quit() function to the following:
int
quit( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

/* eliminate ’unreferenced’ warnings */


widget = widget,
apinfo = apinfo,
cbinfo = cbinfo;

exit( EXIT SUCCESS );

54 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 3 — Creating Menus and Menubars

/* This statement won’t be reached, but it


will keep the compiler happy. */

return( Pt CONTINUE );
}

5 After you’ve edited the code, saved your changes, and closed
the editor, click on Make to compile the code.

6 Click on Run Application to run the application.

7 Once your application is running, try clicking on the File button


to bring up the File menu. Then choose Quit. Your application
will immediately terminate and close.

Want more info?


For more info on: See the section: In the chapter:
Widget callbacks Callbacks Editing Resources
and Callbacks in
PhAB
Editing callbacks Editing Resources
and Callbacks in
PhAB
Instance names Instance names Creating Widgets in
PhAB
Menu modules Menu modules Working with
Modules

September 20, 2005 Chapter 2 ¯ Tutorials 55


Tutorial 4 — Creating Dialogs  2005, QNX Software Systems

Tutorial 4 — Creating Dialogs


☞ This tutorial uses the application you created in Tutorial 3.

What you’ll learn


This tutorial provides a good example of how you can use setup code
to modify a widget’s resources before the widget appears onscreen.
In this tutorial, you will:

¯ link the “About Demo” item in the Help menu to a dialog

¯ add labels and a Done button to the new dialog

¯ define a setup function that changes the text of one of the labels to
display a version number when the dialog is realized.

About dialogs
Dialog modules are designed to let you obtain additional information
from the user. Typically, you use this information to carry out a
particular command or task.
Since you don’t usually need to get the same information twice,
dialogs are single-instance modules. That is, you can’t realize the
same dialog more than once at the same time. If you try create a
second instance of a dialog, PhAB simply brings the existing dialog to
the front and gives it focus.
If you need to create a window that supports multiple instances, use a
window module. You’ll learn about window modules in the next
tutorial.

More on instance names


To make it easier for you to access widgets from within your
application code, PhAB generates a global variable and a manifest.
Both of these are based on the widget’s instance name.

56 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 4 — Creating Dialogs

The global variable, which has the prefix “ABN,” represents the
widget’s name. The manifest, which has the prefix “ABW,” represents
the widget’s instance pointer.

☞ The value of a widget’s ABN ... variable is unique only in the module
that contains the widget. The variables for widgets in other modules
might have the same value.

For example, let’s say you have a widget named about version.
PhAB will use this name to generate a global variable named
ABN about version and a manifest named ABW about version.
In this tutorial you’ll learn how to use these generated names.

Attaching a dialog module


1 Open the tut3 application you created and use the File menu’s
Save As item to save the application as tut4.
2 Open the Help menu module you created (it may still be
iconified).
3 Click on the Menu Items resource in the Control Panel to open
the menu editor.
4 Select the “About Demo” item, then click on the icon next to
the Callback field to open the callback editor:

5 When the editor opens, the default callback type is Code. Go to


the Module Types group and change the callback type to
Dialog.
6 In the Name field, type aboutdlg as the name of the dialog
module you want to link to. (This dialog doesn’t exist yet, but
PhAB will ask you later to create it.)
7 In the Setup Function field, type aboutdlg setup. This is the
name we’re giving to the setup function that will be called
before the dialog is realized.

September 20, 2005 Chapter 2 ¯ Tutorials 57


Tutorial 4 — Creating Dialogs  2005, QNX Software Systems

Using this function, we’ll change the content of a label widget


within the dialog to display a version number.

8 Since you want the aboutdlg setup function to be called


before the dialog is realized, make sure the Prerealize button is
enabled.

9 Click on the Location icon to specify where you want the


dialog to appear when it gets realized. (The “Center Screen”
location is a good choice.) Click on Done.
Your callback information should now look like this:

Name: aboutdlg

Location: Center Screen (0,0)

Setup Function: aboutdlg_setup

Called: Pre- Realize Post- Realize

10 Click on Apply to add the link callback. Since the dialog


module you want to link to doesn’t exist yet, PhAB asks you
whether it should create the module. Click on Yes.
You’ll see the new dialog in the work area. You’ll also see the
new callback in the Callbacks list in the callback editor.

11 Click on Done to close the callback editor, then click on Done


again to close the menu editor.

Adding widgets to the dialog


1 Place two PtLabel widgets in the top half of the dialog, and a
PtButton near the bottom:

58 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 4 — Creating Dialogs

aboutdlg Test Dlg

Label

Label

Button

2 Select the top PtLabel widget and change its label text
resource to About this Demo. Then change its horizontal
alignment to Pt CENTER.

3 Select the other PtLabel widget and change its label text to a
blank string. Then change its horizontal alignment to
Pt CENTER.
Later, you’ll fill in the aboutdlg setup() function so that it
changes the blank text of this label to display a version number.

4 You must give this blank PtLabel widget an instance name


since you’ll be referring to it in code. So change its instance
name to about version, then press Enter.

5 Select the PtButton widget and change its button text resource
to Done. Then change its instance name to about done and
press Enter.

6 Let’s center the widgets horizontally in the dialog. Select both


PtLabel widgets and the PtButton widget, and click on the
speedbar’s Alignment icon:

September 20, 2005 Chapter 2 ¯ Tutorials 59


Tutorial 4 — Creating Dialogs  2005, QNX Software Systems

You’ll see the Align Widgets dialog.


7 In the Horizontally column, click on Center and on Align to
Container. Then click on Align Widgets.
You’ll see that the two labels and the button are now centered
horizontally within your dialog.
Your aboutdlg module should now look like this:
aboutdlg Test Dlg

About this demo

Done

Adding a callback to the Done button


Now let’s add a callback to the Done button so that the dialog closes
when the user clicks on the button.

1 Select the Done button, then switch the Control Panel to


Callbacks mode.
2 Click on Activate to add an activate callback. You’ll see the
callback editor.
3 Select the Done code type, then click on Apply. Don’t enter
anything in the Function field.

60 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 4 — Creating Dialogs

Selecting the Done code type tells the widget to perform a


“Done” operation when the widget is activated. That is, the
widget will call the function specified in the Function field (if
one is specified) and then close the dialog module.

4 Close the editor. The callback list now indicates that you’ve
added an Activate callback called Done:

Class : PtButton

Widget Instance Name F9 F10

about_done

Act ivat e Done:


Arm None
Disarm None

Modifying a generated code function


You’ll now modify the generated aboutdlg setup() function so that it
changes the text of the about version label to show a version
number.

1 Save your application.

2 Open the Build & Run dialog and generate the code.

3 When code generation is complete, select aboutdlg setup.c


from the file list and click on the Edit button (or double-click on
the filename).
Change the code from:
int
aboutdlg setup( PtWidget t *link instance,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

/* eliminate ’unreferenced’ warnings */


link instance = link instance,
apinfo = apinfo,

September 20, 2005 Chapter 2 ¯ Tutorials 61


Tutorial 4 — Creating Dialogs  2005, QNX Software Systems

cbinfo = cbinfo;

return( Pt CONTINUE );

to the following:
int
aboutdlg setup( PtWidget t *link instance,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PtArg t args[1];

/* eliminate ’unreferenced’ warnings */


link instance = link instance, apinfo = apinfo,
cbinfo = cbinfo;

PtSetArg(&args[0], Pt ARG TEXT STRING, "1.00", 0);


PtSetResources(ABW about version, 1, args);

return( Pt CONTINUE );

The code is placing the version number (1.00) into the text
string resource for the about version widget. To do this, the
code:
¯ sets up an argument list entry with the resource’s name and
the new value, using the PtSetArg() macro
¯ calls PtSetResources() to set the resource (defined in the
argument list) for the about version widget. The code
uses the PhAB-generated manifest ABW about version,
which provides access to the widget’s instance pointer.
We can use this manifest safely since we’re dealing with a
dialog module — PhAB ensures that only one instance of
the dialog will exist at any given time.

4 Save your changes and exit the text editor.

62 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 4 — Creating Dialogs

Compiling and Running


You’re now ready to compile and run the program:

1 Click on the Make button. If your program compiles and links


without errors (which it should if you edited the function
correctly), click on Run Application button to start the
application.

2 From the running application, open the Help menu and choose
About Demo. The dialog will open, and you’ll see the version
number (1.00) under the label “About this Demo.” Note that the
dialog appears in the location you specified.

3 Now try to bring up a second instance of the dialog. As you see,


it won’t work. PhAB always ensures that there is only one
instance of a Dialog widget.

4 Click on Done to close the dialog, then quit the application by


choosing the Quit item from its File menu. Finally, close the
Build & Run dialog.

Want more info?

For more info on: See the section: In the chapter:


Using dialogs Dialog modules Working with Modules
Instance names Instance names Creating Widgets in PhAB
Variables and manifests Working with Code
Callbacks Callbacks Editing Resources and
Callbacks in PhAB
Code-callback functions Working with Code
Generating code Generating application code Generating, Compiling, &
Running Code

September 20, 2005 Chapter 2 ¯ Tutorials 63


Tutorial 5 — Creating Windows  2005, QNX Software Systems

Tutorial 5 — Creating Windows


☞ This tutorial uses the application you created in Tutorial 4.

What you’ll learn


In the previous tutorial, you learned how to handle dialog modules,
which support just one instance. In this tutorial you’ll learn how to
handle window modules, which support multiple instances.
By supporting multiple instances, window modules provide more
flexibility than dialogs. But to take advantage of this flexibility, you
must keep track of each window’s instance pointer. Doing so ensures
that you correctly reference the widgets within each instance of a
window. You can’t safely use the generated global ABW xxx manifest
since it refers only to the last instance created.
To simplify the task of working with multiple instances, PhAB
provides API library functions that let you access any widget by
means of its global variable name (ABN xxx).

Creating a window
To start, let’s create a window module and attach it to the New menu
item in the File menu in tut4. This window will contain buttons that
change the color of another widget.
In the previous tutorial, you created a dialog module from within the
callback editor. But this time you’ll use the module selector to create
the module you want. In the future, use whatever method you prefer.

1 Open the tut4 application if you removed it from the PhAB


workspace.

2 Save the application as tut5.

3 Iconify the aboutdlg dialog module.

4 From the Application menu, choose the Windows item to open


the module selector.

64 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 5 — Creating Windows

5 In the Name field, type newwin for the window’s instance


name, then press Enter or click on Open.
When PhAB prompts you to create the window, click on Yes.

6 Close the module selector. The window module should now be


the currently selected item.

Attaching callbacks
Because a window module supports multiple instances, you have to
create code functions that will be called whenever the window opens
or closes (i.e. whenever the window is created or destroyed). So let’s
first set up a callback to detect when the window closes:

1 Make sure the Control Panel is in Callbacks mode.

2 From the list of callbacks, choose Window Manager. You want


to use the Window Manager callback since it’s invoked when
the Photon Window Manager closes the window.

3 In the Function field, type newwin close. You don’t have to


choose a callback type since the default, Code, is the one you
want.
Click on Apply, then on Done.

4 Switch the Control Panel to Resources mode and select the


“Flags: Notify” resource. Choose the Ph WM CLOSE flag, then
click on Done.
This flag tells the Window Manager to notify your application
when the window is closed.

5 Now let’s set up a function that’s invoked when the window


opens.
Open the filemenu menu module, then select the Menu Items
resource in the Control Panel. You’ll see the menu editor.

6 Make sure the menu’s C:New item is currently selected in the


Menu Items list, then click on the Callback icon to open the
callback editor.

September 20, 2005 Chapter 2 ¯ Tutorials 65


Tutorial 5 — Creating Windows  2005, QNX Software Systems

7 Choose the Window module type, then click on the icon next to
the Name field. You’ll see the list of existing window modules.
8 Choose newwin, which is the window you just created.
9 In the Setup Function field, enter newwin setup as the name
of the setup function. Later, you’ll modify newwin setup() to
handle the window’s multiple instances.
10 Click Apply, then on Done. Click on Done again to close the
menu editor.

Adding widgets
Let’s now add some widgets to the newwin window module. Using
these widgets, you’ll learn how to update information in the current or
other instances of a window module.

1 Add a PtRect widget and four PtButton widgets as follows:


new w in Test Wind

Button Button Button

Button

2 Now modify the left button:


¯ change the button’s label text to Red
¯ give the button an instance name of btn red, and press
Enter.

66 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 5 — Creating Windows

¯ attach an Activate callback, specifying a “Code” code type


and a function name of color change

3 Modify the middle button:


¯ change the label text to Green
¯ specify an instance name of btn green, and press Enter
¯ attach an Activate/Code callback to the same function as
above, color change

4 Modify the right button:


¯ change the label text to Blue
¯ specify an instance name of btn blue, and press Enter
¯ attach an Activate/Code callback to the same function as
above

5 Modify the large button:


¯ label text to Change Previous Window Color
¯ instance name of btn prev, press Enter
¯ Activate/Code callback to the same function as above

6 Last of all, give the rectangle an instance name of


color rect, then press Enter. You need to specify this name
so that the color change() function can change the color of the
rectangle.

September 20, 2005 Chapter 2 ¯ Tutorials 67


Tutorial 5 — Creating Windows  2005, QNX Software Systems

Your window should now look something like this:


new w in Test Wind

Red Green Blue

Change Previous Window Color

Generating and modifying the code


In the last tutorial, you used the generated ABW xxx manifest to
access a dialog’s instance pointer. You can’t use this manifest when
dealing with multiple instances of a window module since it refers
only to the last window created. Instead, you have to add code to the
generated window-setup function so that it stores a copy of each
window-instance pointer in a global widget array. In this tutorial,
you’ll need these pointers for the “Change Previous Window Color”
button to work.

Generating the code


Open the Build & Run dialog and regenerate the code.

Modifying the setup function


Now let’s modify the newwin setup() function so that it:

¯ limits the number of possible instances to five

¯ stores a copy of each window pointer

68 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 5 — Creating Windows

¯ displays a window’s instance number in that window’s titlebar

Edit the newwin setup.c file as follows:


int win ctr = 0;
PtWidget t *win[5];

int
newwin setup( PtWidget t *link instance,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PtArg t args[1];
char buffer[40];

/* eliminate ’unreferenced’ warnings */


apinfo = apinfo, cbinfo = cbinfo;

// Note: Returning Pt END in a prerealize setup


// function will tell PhAB to destroy the
// module without realizing it

/* allow only 5 windows max */


if ( win ctr == 5 ) {
return( Pt END );
}

/* save window-module instance pointer */


win[win ctr] = link instance;

sprintf( buffer, "Window %d", win ctr + 1 );


PtSetArg( &args[0], Pt ARG WINDOW TITLE,
buffer, 0 );
PtSetResources( win[win ctr], 1, args );
win ctr++;

return( Pt CONTINUE );

Modifying the color-change function


Now let’s modify the color change() function so that:

¯ pressing a Red, Green, or Blue button changes the rectangle color


to the button color

September 20, 2005 Chapter 2 ¯ Tutorials 69


Tutorial 5 — Creating Windows  2005, QNX Software Systems

¯ pressing the Change Previous Window Color button changes the


previous window to a color from an array.

If this were a dialog module you could use the ABW color rect
manifest to update the color of the rectangle. However, because these
are window modules, you must use the instance pointer for the
window in which the button is being pressed.
To get the instance pointer, you need to call the ApGetWidgetPtr() and
ApGetInstance() functions with the instance pointer of the selected
widget and the global variable name ABN color rect.
If only one instance of the window were guaranteed, the following
would work:

PtSetResources( ABW color rect, 1, args );

But in this case color change() has to use:

PtSetResources( ApGetWidgetPtr( ApGetInstance( widget ),


ABN color rect ), 1, args );

So you need to change color change.c to look like:

PgColor t colors[5] = {Pg BLACK, Pg YELLOW, Pg MAGENTA,


Pg CYAN, Pg DGREEN};
int base clr = -1;
extern int win ctr;
extern PtWidget t *win[5];

int
color change( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
int i, prev;
PtArg t args[1];

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

if ( ApName( widget ) == ABN btn red ) {


PtSetArg( &args[0], Pt ARG FILL COLOR, Pg RED, 0 );
} else if ( ApName( widget ) == ABN btn green ) {
PtSetArg( &args[0], Pt ARG FILL COLOR, Pg GREEN, 0 );
} else if ( ApName( widget ) == ABN btn blue ) {

70 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 5 — Creating Windows

PtSetArg( &args[0], Pt ARG FILL COLOR, Pg BLUE, 0 );


} else if ( ApName( widget ) == ABN btn prev ) {

// Note: Here we use the window-module instance


// pointers saved in newwin setup to update
// the window previous to the current window
// provided it hasn’t been closed.

/* determine which window


* is previous to this window
*/
prev = -1;
for ( i = 0; i < win ctr; i++ ) {
if ( win[i] == ApGetInstance( widget ) ) {
prev = i - 1;
break;
}
}

/* if window still exists,update its background color */


if ( prev != -1 && win[prev] ) {
base clr++;
if (base clr >= 5) {
base clr = 0;
}
PtSetArg( &args[0], Pt ARG FILL COLOR,
colors[base clr], 0 );
PtSetResources( win[prev], 1, args );
}

return( Pt CONTINUE );
}

PtSetResources( ApGetWidgetPtr( ApGetInstance( widget ),


ABN color rect ), 1, args );

return( Pt CONTINUE );

Modifying the window-close function


Last of all, you need to modify newwin close() so that it sets the win
array of instance pointers to NULL for a window when it’s closed.
That way, you can check for NULL in the win array to determine
whether the window still exists.

September 20, 2005 Chapter 2 ¯ Tutorials 71


Tutorial 5 — Creating Windows  2005, QNX Software Systems

Modify newwin close.c as follows:

extern int win ctr;


extern PtWidget t *win[5];

int
newwin close( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
PhWindowEvent t *we = cbinfo->cbdata;
int i;

/* eliminate ’unreferenced’ warnings */


apinfo = apinfo;

/* only process WM close events */


if ( we->event f != Ph WM CLOSE ) {
return( Pt CONTINUE );
}

/* okay it’s a close so who is it? */


for ( i = 0; i < win ctr; i++ ) {
if ( win[i] == widget ) {
win[i] = NULL;
break;
}
}

return( Pt CONTINUE );

Compiling and running


1 Make the application and run it.

2 From the application’s File menu, choose New several times to


create multiple windows. You’ll see each window’s relative
number in its titlebar.

3 Click on a color button to make the rectangle change color.


Then click on the Change Previous Window Color button in any
window to change the background color of the previous
window.

72 Chapter 2 ¯ Tutorials September 20, 2005


 2005, QNX Software Systems Tutorial 5 — Creating Windows

Want more info?

For more info on: See the section: In the chapter:


Using windows Window modules Working with Modules
Instance names Instance names Creating Widgets in PhAB
Variables and manifests Working with Code chapter
Callbacks Callbacks Editing Resources and
Callbacks in PhAB
Code-callback functions Working with Code
Generating code Generating application code Generating, Compiling, &
Running Code

September 20, 2005 Chapter 2 ¯ Tutorials 73


Chapter 3
PhAB’s Environment

In this chapter. . .
Menubar 77
Speedbar 78
Widget bar 79
Control Panel 82
Customizing your PhAB environment 89
Help 91
Exiting PhAB 92

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 75


 2005, QNX Software Systems Menubar

This chapter describes PhAB’s environment in more detail, and how


you can customize it.

Menubar
Across the top of PhAB’s workspace you’ll see the following
menubar:

File Edit View Options Application Window Help

PhAB’s menubar.

The menus include:

File Commands for creating, opening, saving, and


closing applications, (described in the Working with
Applications chapter), and for exiting PhAB.
Edit Commands for editing widgets, including cutting,
copying, pasting, transferring, grouping, and
aligning. These commands also appear on the
speedbar, and are described in the Creating Widgets
in PhAB chapter.
View Commands for displaying the clipboard and Control
Panel.
Options Allows you to set PhAB preferences, as described in
the section “Customizing your PhAB environment.”
Application Commands dealing with the application as a whole
(described in the Working with Applications
chapter), and its modules (described in the Working
with Modules chapter).
Window Commands that manipulate PhAB’s windows.
Help Access to online Help information, described in the
section “Help.”

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 77


Speedbar  2005, QNX Software Systems

Speedbar
The speedbar gives you quick access to the Edit menu’s commands:
Cut Paste To Front Group Together Alignment Position

Copy Transfer To Back Split Apart Nudge Size

PhAB’s speedbar.

To find out what a button is for, pause the pointer over it. A help
balloon will appear. For more information, see the Creating Widgets
in PhAB chapter.
You can turn PhAB’s speedbar into a floating window and drag it
anywhere onscreen. The speedbar will return to its default position
the next time you start PhAB.

Detaching the speedbar


To detach the speedbar from its default position:
1 Point to a blank area of the speedbar.
2 Press the mouse button and drag the bar to where you want it.

Reattaching the speedbar


To reattach the speedbar, drag it back close to its original position. If
the speedbar doesn’t reattach when you release the mouse, try to
position it more precisely.

Hiding the speedbar


If you don’t want to use the speedbar, you can turn it off in the
Preference Settings dialog. For more information, see “Customizing
your PhAB environment” in this chapter.

78 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Widget bar

Widget bar
At the left side of the PhAB window you’ll see the widget bar. This
bar lets you add widgets to your application.

PhAB’s widget bar.

To find out what widget a button represents:

¯ Pause the pointer over it — a help balloon will appear.


Or

¯ See the Widgets at a Glance appendix.

For information on using specific widget classes, see the Photon


Widget Reference.

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 79


Widget bar  2005, QNX Software Systems

Modes (create vs select)


The widget bar has two modes:

¯ select mode — lets you select existing widgets and modules in the
work area

¯ create mode — lets you create new widgets

Determining the mode


To find out which mode you’re in:

¯ look at the widget bar — If the arrow icon at the top is pushed in,
you’re in select mode. If any other icon button is pushed in, you’re
in create mode.

¯ look at the pointer — If the pointer is a single-headed arrow when


you move it into the work area, you’re in select mode. If the
pointer is anything else, you’re in create mode.

Switching to create mode


To switch to create mode, click on any widget icon in the widget bar.
You can now create one or more instances of that widget. For more
information, see “Creating a widget” in the Creating Widgets in
PhAB chapter.

Switching to select mode


To switch from create mode to select mode, do one of the following:

¯ Click on the arrow icon at the top of widget bar.


Or

¯ Click the right mouse button in a module.

By default, PhAB returns to select mode as soon as you’ve created a


widget.

80 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Widget bar

Customizing the widget bar


Here’s how to customize the widget bar so it displays only the
widgets you need:

1 From the Options menu, choose the Customize Widget Bar


item. PhAB displays the following dialog:
Customize Widgetbar

Widget Palettes Widgets


Basic Widgets
Graphic Widgets Ba s ic W id g e t s
Contributed Widgets
RealTime Widgets
Pt Bit map Pt But t on Pt Label

Pt MenuBut t on Pt Pane Pt ScrollArea

Pt Scrollbar Pt Separat or Pt Tex t

Pt ToggleBut t on Pt OnOf f But t on Pt List

Pt Mult iTex t Pt Bkgd Pt ComboBox

Done

Customizing the widget bar.

2 On the left, you’ll see a list of widget palettes. Each palette


groups together similar widgets or widgets within a specific
library. To view any palette, click on its entry in the list.

3 On the right, you’ll see the widgets available for the currently
selected palette. Any widget icon that’s pushed in is already
included in the widget bar.
Each widget icon is a toggle: simply click on an icon to add or
remove that widget from the widget bar.

4 After customizing the widget palette, click on Done. PhAB


immediately applies your new selections to the widget bar.

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 81


Control Panel  2005, QNX Software Systems

☞ The widget palette is saved to disk, so any changes you make will be
in effect the next time you run PhAB.
PhAB saves changes to the widget bar on a per-user basis rather than
by application.

Control Panel
PhAB’s Control Panel displays information about the currently
selected widgets. The Control Panel is displayed by default in PhAB,
and you can move it anywhere you like. If you close the control
panel, you can reopen it by choosing the Control Panel item from the
View menu. If this doesn’t make it appear, choose Arrange Modules
from the Window menu, and PhAB will cascade all open modules and
pull the Control Panel back into the PhAB work area.
The control panel looks like this:
Widget class Previous Next

Instance name

Mode buttons

Anatomy of PhAB’s control panel.

82 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Control Panel

It includes the following:

Widget class The class of the selected widget.

Next and previous buttons


Let you navigate sequentially through widgets in
the current module. These buttons also let you
select multiple widgets or select widgets within a
group. For more info, see the “Selecting widgets”
section in the Creating Widgets in PhAB chapter.

Instance name Lets you enter a unique instance name for the
widget.

After entering an instance name, press Enter.



For more info, see the section on “Instance names”
in the Creating Widgets in PhAB chapter.

Mode buttons Let you switch between the control panel’s modes:
¯ Resources — view and edit resources
¯ Callbacks — view and edit callbacks
¯ Module Tree — display the widget family
hierarchy of the current module
¯ Module Links — display a list of module links
so you can see how a module is connected to
the rest of the application

Resources mode
Resources mode displays a list of resources for the selected widget.
Here’s an example:

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 83


Control Panel  2005, QNX Software Systems

Class : PtWindow

Widget Instance Name F9 F10

base

W indow Title My Applicat ion


W indow Icon Icon
Color: Fill
Color: Top Border
Color: Bot t om Border
Flags: Render 0x31f 0
Flags: Managed 0xcb7d
Flags: Not if y 0x2101
Window St at e 0x0
Minimum Window Height 43
Minimum Window Widt h 71
Maximum Window Height 0
Maximum Window Widt h 0
Cont ainer Flags 0x10
Cursor Type Ph_CURSOR_POINTER

Resources Module Tree

Callbacks Module Links

Resources mode for the control panel.

To edit any displayed resource, click on it. For more information, see
the Editing Resources and Callbacks in PhAB chapter.
By default, the Control Panel displays resource labels descriptively. If
you pause the pointer over a resource, the header manifest is
displayed in a popup balloon.
To have the labels displayed as the actual header manifests
(convenient when writing code), open the Preferences dialog and

84 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Control Panel

change the setting in the Resource Names field. To open this dialog,
choose the Preferences item from the Options menu.
Now if you pause the pointer over a resource, the popup balloon
displays the descriptive label.

☞ The control panel doesn’t display all the resources for a widget.
PhAB sets Pt ARG AREA, Pt ARG DIM, and Pt ARG POS
automatically when you move or resize a widget. Some other
resources are too complex to edit in PhAB.

Callbacks mode
Callbacks mode displays a list of callback resources for the selected
widget. You can use this mode only when you’ve selected a single
widget. Here’s an example:

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 85


Control Panel  2005, QNX Software Systems

Class : PtButton

Widget Instance Name F9 F10

about_done

Pt _CB_ACTIVATE Done:
Pt _CB_ARM None
Pt _CB_DISARM None
Pt _CB_MENU None
Pt _CB_REPEAT None
Pt _CB_GOT_FOCUS None
Pt _CB_LOST_FOCUS None
Pt _CB_HOTKEY C- - 0x6f /Done:
Pt _CB_RAW None
Pt _CB_REALIZED None
Pt _CB_UNREALIZED None
Pt _CB_DESTROYED None

Resources Module Tree

Callbacks Module Links

Callbacks mode for the control panel.

The left side of the list indicates the callback type. The right side
displays:

¯ “None” if there are no callbacks

¯ the callback type and name if there’s one callback

¯ the number of callbacks if there’s more than one

To create a callback or to edit an existing one, click on the appropriate


resource (for example, Pt CB ACTIVATE).

86 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Control Panel

Module Tree mode


Module Tree mode displays a hierarchical tree of the widgets in the
current module. Here’s an example:

Class : PtWindow

Widget Instance Name F9 F10

aboutdlg

Pt Window: aboutdlg
Pt Label
Pt ComboBox : shapes_cbox
Pt Label: about_version
Pt Group
Pt But t on
Pt But t on
Pt But t on
Pt But t on
Pt But t on
Pt But t on
Pt But t on: about_set_cbox
Pt ScrollArea
Pt Met er
Pt Bkgd

Resources Module Tree

Callbacks Module Links

Module Tree mode for the control panel.

This mode makes it easy to:

¯ see the parent/child relationships of the module’s widgets

¯ select a widget inside a group

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 87


Control Panel  2005, QNX Software Systems

¯ find a widget by name

¯ select a widget hidden underneath another widget.

To select a widget from the tree, click on the widget’s name.

Module Links mode


Module Links mode displays a list of all link callbacks both to and
from the current module. As you can see from the following example,
the callbacks are displayed in a two-line format:

Class : PtMenuButton

Widget Instance Name F9 F10

base_file

base
St art - Up CODE
base
Hot key OTHR open_f ile_sel
base_edit_btn
Act iv at e WIND paneswin
Hot key CODE

base_file
Arm MENU f ilemenu
Hot key MENU f ilemenu

base_view
Act iv at e MENU v iewmenu

Resources Module Tree

Callbacks Module Links

Module Links mode for the control panel.

88 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Customizing your PhAB environment

To do this: Click on the:


Select a widget Instance name (e.g. base file) in line 1
Edit a widget callback Appropriate callback type (e.g. Arm) in
line 2

Customizing your PhAB environment


To customize PhAB to your preferences:

1 Choose Preferences from the Options menu. You’ll see the


Preference Settings dialog:
AppBuilder Preference Settings

General
G e n e r a l Pr e f e r e n c e s
Colors
Speedbar: On Off
Dragging

Other Module Display: As Sample As Resource List

Resource Names: Descriptive Header Manifest

Icon Descriptions: None Pop- Up

Edit Command:

View Command:

Print Command:
Done

Setting PhAB preferences.

2 Click on the button that represents the kind of settings you wish
to change: General, Colors, or Dragging.

3 When you’re finished, click on Done.

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 89


Customizing your PhAB environment  2005, QNX Software Systems

General preferences
You can set the following general preferences:

Speedbar Lets you specify whether the speedbar is displayed or


hidden. The speedbar is always displayed when PhAB
starts up.

Other Module Display


Lets you choose how “other” modules are displayed. If
you prefer to see a sample of what an “other” module
will look like, choose Sample. If you’d rather see the
module’s resource values, choose Resource List.
Resource Names
By default, the Control Panel displays resource labels
descriptively. This field lets you display the labels as
the actual header manifests, which you may find helpful
when writing code. Note, however, that manifests are
long and take up more screen space.
If you pause the pointer over a resource, the label not
displayed in the control panel is displayed in a popup
balloon.
Icon Descriptions
By default, when you leave the pointer on any icon,
descriptive text pops up in a balloon. To disable this
feature, click on None.
Edit Command
Lets you specify the editor to use with the Build & Run
dialog.

View Command
Lets you specify the file viewer to use with the Build &
Run dialog.

90 Chapter 3 ¯ PhAB’s Environment September 20, 2005


 2005, QNX Software Systems Help

Print Command
Lets you specify the print command used to print a
selected file (in the Build & Run dialog, for example).

Color preferences
You can set the following color preferences:

Resize Handle
Non-Resizable Handle
If you choose a window background that makes it
difficult to see resize handles, use these options to
customize the color. (If you select a widget and the
resize handles appear in the nonresize color, the
widget can’t be resized.)
Control Panel Lets you change the background color of the
Control Panel.

Dragging preferences
You can set the following dragging preferences:

Widget
Module Drag widgets and modules as outlines rather than as full
objects.
Drag Damping Factor
The amount you must drag a widget or module before it
moves. This factor helps avoid the annoyance of moving
a widget when you really mean to select it.

Help
There are several forms of help available in PhAB:

¯ Online documentation — To access the online docs for PhAB,


bring up the Help menu and choose a topic.

September 20, 2005 Chapter 3 ¯ PhAB’s Environment 91


Exiting PhAB  2005, QNX Software Systems

¯ Context-sensitive help — To get help on a part of PhAB’s user


interface, click on the question mark button, then click on the item
in question. The Helpviewer will display the information on the
selected item.

¯ Balloon help — To find out what a button in the widget bar or


speedbar is for, pause the pointer over it. A descriptive balloon
will appear.

¯ PhAB’s version number — To find out which version number of


PhAB you’re running, open the Help menu and choose the About
PhAB item.

Exiting PhAB
To exit PhAB, do one of the following:

¯ Choose Exit from the File menu.

¯ Press Ctrl – X.

¯ Click on PhAB’s window menu button (top-left corner) and choose


Close.

¯ Double-click on the window menu button.

92 Chapter 3 ¯ PhAB’s Environment September 20, 2005


Chapter 4
Working with Applications

In this chapter. . .
Creating an application 95
Opening an application 95
Saving an application 97
Closing an application 99
Specifying application startup information 99

September 20, 2005 Chapter 4 ¯ Working with Applications 93


 2005, QNX Software Systems Creating an application

This chapter describes working with an application as a whole in


PhAB.

Creating an application
To create a new application, choose New from the File menu, or press
Ctrl – N. If you’re already working on an application, PhAB asks if
you want to save any changes to that application before closing it.
PhAB creates a new unnamed application that consists of a single
main window, named base.
After creating an application, you should:

¯ save it, giving it a name

¯ use the Application Startup Information dialog to:


- specify a global header file
- specify an initialization function
- enable or disable command-line options

☞ A naming convention for all the widgets, modules, functions, and so


on will make managing your application easier.

Opening an application
To open an existing application:

1 Choose Open from the File menu or press Ctrl – O. You’ll see
the application selector:

September 20, 2005 Chapter 4 ¯ Working with Applications 95


Opening an application  2005, QNX Software Systems

Application Selector

Application Directory
//222/home/stever/phab

Applications M odules Owner Date


background 1 stever 02-Oct-96 12:47pm
divider 1 stever 03-Oct-96 03:30pm
exercise1 1 stever 13-Aug-96 01:31pm
group 1 stever 22-Oct-96 01:55pm
initfn 1 stever 18-Sep-96 04:21pm
initfn2 1 stever 19-Sep-96 02:39pm
lang 3 stever 21-Oct-96 12:15pm
msgpad 10 stever 11-Oct-96 03:50pm
msgpad_copy 10 stever 11-Oct-96 03:45pm
resize 1 stever 16-Sep-96 02:01pm
resize2 1 stever 16-Sep-96 04:24pm
resize_flags 1 stever 30-Sep-96 03:56pm

Application Name
background

Open Application Cancel

Application Selector dialog.

2 If the application you want is in another directory, type the


directory name in the Application Directory field, then press
Enter.

3 To choose the application, do one of the following:


¯ double-click on the application
¯ click on the application, then press Enter or click on Open
Application
¯ type the application’s name, then press Enter or click on
Open Application

96 Chapter 4 ¯ Working with Applications September 20, 2005


 2005, QNX Software Systems Saving an application

☞ If the application has already been opened (whether by you or


someone else), PhAB won’t open it unless you started PhAB with the
-n option.
If you’re using NFS or SMB, you should start PhAB with the -n
option because you can’t lock files with either.

Saving an application
You can save your application in several ways, as described in the
sections below.

☞ To ensure the latest changes to your application are in effect, PhAB


automatically saves your application whenever you regenerate or
make your application code.

For information on using version-control software with PhAB


applications, see “Version control” in the Generating, Compiling, &
Running Code chapter.

Naming or renaming an application


To save a new unnamed application or to save an application under
another name or in a different directory:

1 Choose Save As from the File menu. You’ll see the application
selector dialog.

2 The dialog lists the contents of a directory. If you want to save


your application in another directory, type the directory name in
the Application Directory field, then press Enter.

September 20, 2005 Chapter 4 ¯ Working with Applications 97


Saving an application  2005, QNX Software Systems

☞ If you type a new directory name, it’s saved. The next time you want
to look in that directory, click on the button to the right of the
directory field and select the directory from the list.

3 Type the name of the application in the Application Name field.

4 Press Enter or click on Save Application.

☞ If you rename an application, you’ll find that the name of the


executable isn’t changed. This is because PhAB doesn’t change the
Makefile. To change the name of the executable:

¯ Edit the Makefile manually and change every occurrence of the


executable’s name.
Or:

¯ If you haven’t changed the Makefile since it was first generated,


delete it and regenerate the application. See the Generating,
Compiling, & Running Code chapter.

Saving an existing application


To save an existing application, choose Save from the File menu or
press Ctrl – S.

Overwriting an existing application


To overwrite an existing application:

1 Choose Save As from the File menu.

2 Do one of the following:


¯ double-click on the existing application
¯ click on the existing application, then press Enter or click on
Save Application

98 Chapter 4 ¯ Working with Applications September 20, 2005


 2005, QNX Software Systems Closing an application

Closing an application
To close an application, choose Close from the File menu.

Specifying application startup information


The Application Startup Information dialog lets you set up the typical
operations that are performed when an application starts. You can:

¯ enable or disable command-line options

¯ define a global header

¯ define an initialization function

¯ include instance names in widgets

¯ define a mainloop function

¯ indicate whether or not proto.h is to be generated — see


“Generating function prototypes” in the Generating, Compiling, &
Running Code chapter

¯ define which windows appear when the application runs.

To open this dialog:

¯ Choose Startup Info/Modules from the Application menu.


Or

¯ Press F2.

Here’s the dialog, with some sample information filled in:

September 20, 2005 Chapter 4 ¯ Working with Applications 99


Specifying application startup information  2005, QNX Software Systems

Application Startup Information

Application Start- Up Information


Global Header: Main Loop Funct ion:
globals.h

Init ializat ion Funct ion: No Pos Arg No Dim Arg No St at e Arg

init Generat e empt y "prot o.h" f ile. Include Names

Window s Opened/Start- Up Link to Window Module Info Module Ty pe


Window: base Window
< NEW > Name: base

Location: Default @(0,0)

Setup Fun: Actions


Apply
Called: Pre- Realize Post- Realize
Reset

Remov e

Done Cancel

Application Startup Information dialog.

Once you’ve made your changes, click on Done.

Specifying a global header file


Most applications have a global header that’s included in all source
code files. If you plan to use a global header in your application, you
should set up the header before PhAB generates any code. This lets
PhAB automatically include the header in each file it generates.
To set up a global header:

1 Press F2 or choose Startup Info/Modules from the Application


menu. You’ll see the Application Startup Information dialog.

2 In the Global Header field, type the name of the header file you
plan to use. You don’t have to include the .h extension.
For example, to set up a globals.h header file, you can
simply enter: globals

3 To edit the header immediately, click on the icon next to the


Global Header field. You can edit the header only if you’ve

100 Chapter 4 ¯ Working with Applications September 20, 2005


 2005, QNX Software Systems Specifying application startup information

named the application by saving it. The format of the header


file is discussed in the Working with Code chapter.

☞ If you specify the header after some code has been generated, you’ll
have to go back and manually add the header to the stub files that
were previously generated.

Initialization function
Your application can include an initialization function that’s called
before any modules or widgets are created. In it you could initialize
data, open widget databases, set up signal handlers, and so on. To set
up an initialization function:

1 Press F2 or choose StartUp Info/Modules from the Application


menu. You’ll see the Application Startup Information dialog.

2 In the Initialization Function field, type the name of the


initialization function.
When you specify a setup function, PhAB generates a stub
function; for information on specifying the language (C or
C++) and the filename, see “Function names and filenames” in
the Working with Code chapter.

3 To edit the function immediately, click on the icon next to the


Initialization Function field. You can edit the function only if
you’ve named the application by saving it. The prototype of
this function is discussed in the Working with Code chapter.

Command-line options
By default, all PhAB-generated applications have the following
command-line options:

-h height[%] The height of the window, in pixels, or as a


percentage of the screen height if % is specified.

September 20, 2005 Chapter 4 ¯ Working with Applications 101


Specifying application startup information  2005, QNX Software Systems

-s server name
The name of the Photon server:

If server name is: This server is used:


node number //node number/dev/photon
fullpath fullpath
relative path /dev/relative path

-w width[%] The width of the window, in pixels, or as a


percentage of the screen width if % is specified.

-x position[%][r]
The x coordinate of the upper-left corner of the
window, in pixels, or as a percentage of screen
width if % is specified. If r is specified, the
coordinate is relative to the current console.
-y position[%][r]
The y coordinate of the upper-left corner of the
window, in pixels, or as a percentage of screen
height if % is specified. If r is specified, the
coordinate is relative to the current console.

-Si|m|n The initial state of the main window (iconified,


maximized, or normal).

By default, all these options are enabled so that users can dynamically
move or resize the application, or specify its initial state. For
example, to start an application in console 4 (the center of the
workspace), specify the command-line options:

-x100% -y100%

The PhAB API processes these options before it calls the initialization
function; if you plan to add your own command-line options to an

102 Chapter 4 ¯ Working with Applications September 20, 2005


 2005, QNX Software Systems Specifying application startup information

application, make sure you pick options that don’t conflict with these.
You should also code your option processing to handle and ignore
these options. If you don’t, you’ll see errors on the console when you
run the application. See the discussion on the initialization function in
the Working with Code chapter.
If you don’t want users to move or resize the application:

1 Press F2 or from the Application menu, choose Startup


Info/Modules to open the Application Startup Information
dialog.

2 To disable the size options, click on No Dim Arg. To disable


the position options, click on No Pos Arg. To disable the state
option, click on No State Arg.

Mainloop function
PhAB lets you take over the standard Photon mainloop function.

!
CAUTION: This option is provided for very advanced Photon
developers, and requires an excellent understanding of how Photon
processes events. It can also make your application incompatible with
future versions of Photon. Don’t use it unless absolutely necessary.

To specify an application-based mainloop function:

1 Press F2 or from the Application menu, choose Startup


Info/Modules to open the Application Startup Information
dialog.

2 In the Main Loop Function field, enter the name of your own
mainloop function. PhAB will generate a mainline stub that
contains the standard Photon mainline code; you can modify
this code as needed.

September 20, 2005 Chapter 4 ¯ Working with Applications 103


Specifying application startup information  2005, QNX Software Systems

Including instance names


PhAB converts your widgets’ instance names into ABN ... manifests
that you can use in your code to refer to your widgets by name. You
can optionally include the instance-name text string in the widgets’
memory. To do this:

1 Press F2 or from the Application menu, choose Startup


Info/Modules to open the Application Startup Information
dialog.

2 Click on the Include Names toggle button.

☞ Including instance names will increase the amount of memory


required to run your application.

Use the ApInstanceName() function to find this string for a widget —


see the Photon Library Reference for more information.

Startup windows
When you first create an application, the mandatory base window is
preset as the initial and only startup window. Using the Application
Startup Information dialog, you can tell your application to:

¯ use another window as the initial startup window

¯ display several windows at startup

¯ use no startup windows

The window that appears first in the Windows Opened/Startup list is


the initial startup window:

¯ it’s the first window to be displayed

¯ it acts as the default parent window for all other windows and
dialogs

¯ closing it causes the application to end

104 Chapter 4 ¯ Working with Applications September 20, 2005


 2005, QNX Software Systems Specifying application startup information

Typically, the application’s main window is the first created.


For each window in the startup list, you can specify information that’s
identical to the information used to create a module-type link
callback, as described in the Editing Resources and Callbacks in
PhAB chapter.

Adding a startup window


To add a new window to the startup window list:

1 Press F2 or choose Startup Info/Modules from the Application


menu. You’ll see the Application Startup Information dialog.

2 Click on <NEW> and fill in the “Link to Window Module Info”


fields. For example:
Link to Window Module Info Module Ty pe
Window
Name: base

Location: Default @(0,0)

Setup Fun: Actions


Apply
Called: Pre- Realize Post- Realize
Reset

Remov e

To use these fields, see “Link to Window Module Info,” below.

3 Click on Apply.

Modifying a startup window


To modify an existing startup window:

1 Select the window from the “Windows Opened/Startup” list.

2 Enter whatever changes are needed in the “Link to Window


Module Info” fields (see below).

3 Click on Apply.

September 20, 2005 Chapter 4 ¯ Working with Applications 105


Specifying application startup information  2005, QNX Software Systems

Deleting a startup window


To delete an existing startup window, select the window from the
“Windows Opened/Startup” list and click on Remove.

Link to Window Module Info


To add or modify a startup window, you use the following controls:

Name Contains the name of the window module. To select


from a list of existing windows, click on the icon next
to this field. If you specify the name of a module that
doesn’t exist, PhAB will ask whether it should create
that module.

Location Determines where the window will appear; see the


“Location dialog” section in the Working with Modules
chapter.

Setup Function
Specifies the function that will be called when the
window is realized (optional). To edit the function,
click on the icon next to this field.

Called Determines whether the setup function is called before


the window is realized, after the window is realized, or
both.

Apply Applies any changes.

Reset Restores the window information to its original state.

Remove Deletes the selected window from the startup list.

106 Chapter 4 ¯ Working with Applications September 20, 2005


Chapter 5
Working with Modules

In this chapter. . .
Overview 109
Using the module selector 112
Creating a new module 113
Viewing a module 114
Opening a module 114
Deleting a module 115
Window modules 115
Dialog modules 116
Menu modules 117
Picture modules 126
Icon modules 127
Other modules 129
Iconifying modules 130
Importing PhAB modules from other applications 130
Importing QNX Windows picture files 131
Closing a module 132
Positioning a module 132
Selecting a module 134
Finding lost modules and icons 134

September 20, 2005 Chapter 5 ¯ Working with Modules 107


 2005, QNX Software Systems Overview

Overview
Modules as containers
Modules serve as containers to hold your application’s widgets. Some
modules, such as windows and dialogs, are actually Photon
container-class widgets and let you place widgets directly inside them.
Others, such as icons and menus, have either predefined widgets or a
specialized editor for creating the widgets that they contain.

Module types
PhAB provides a number of types of modules, each with a specific
usage. Each module type is identified as follows:

¯ If the module isn’t iconified, look at the colored tab in the


module’s top-right corner.

¯ If a module is iconified, look at the small swatch of color displayed


in the icon.

¯ When you generate your code, PhAB creates a file for each
module. The extension identifies the type of module.

! CAUTION: These are all binary files. Don’t edit them with a text
editor or you could damage them.

Module Usage Color Extension


window Major application activities Blue .wgtw
dialog Obtain additional information Green .wgtd
from the user
menu Multilevel text-only menus Yellow .wgtm
picture Change the contents of an Cyan .wgtp
existing module, or create a
widget database

continued. . .

September 20, 2005 Chapter 5 ¯ Working with Modules 109


Overview  2005, QNX Software Systems

Module Usage Color Extension


icon Your application’s icons for use Red .wgti
by PDM and the Taskbar
“other” Predefined modules for specific Purple .wgtx
purposes

Changing module resources


When you select a module within PhAB, the Control Panel changes to
display the list of widget resources available for that module’s class.
Depending on which resources you change, you may see no
immediate effect. All changes will take effect, however, when you run
the application.
Because PhAB displays all modules as child windows within its work
area, you can work with any number of modules at the same time.

Anatomy of a module
PhAB displays each module as a window in its work area. Like
windows, modules have a set of controls in their frames.

110 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Overview

Work menu button Title bar Test tab Module-type tab

Anatomy of a typical PhAB module.

Most modules include these elements:

¯ Work menu button — brings up the module’s Work menu so you


can iconify the module, move the module behind all other
modules, or close the module.

¯ Title bar — displays the module’s instance name. To move a


module, point to this bar and drag the pointer.

¯ Test tab (some modules only) — lets you switch the module into
test mode so you can interact with the widgets as you would when
your application is running.

¯ Module-type tab — displays the module type. You’ll find that each
module type displays a different color in its tab. These colors are
used throughout PhAB to make identifying modules easy. For
more info, see “Module types” in this chapter.

Note that using the Work menu to close a module doesn’t delete the
module. It simply removes the module from the work area to give you

September 20, 2005 Chapter 5 ¯ Working with Modules 111


Using the module selector  2005, QNX Software Systems

more space to work with. To get the module back any time, use the
module selector, which lets you access, create, and delete any type of
module. For more info, see “Using the Module selector” in this
chapter.

How modules are saved


When you save your application, PhAB stores all the application’s
modules as files within the application’s wgt directory. Each module
is saved in its own file with a file extension based on the module’s
type. Later, when you “make” your application, PhAB binds all the
modules into the binary executable. This makes the application a
single free-standing program that you can distribute easily.
For more info, see “How application files are organized” in the
Generating, Compiling, & Running Code chapter.

Displaying modules at run time


Your application needs a way to make modules appear when you run
it. You can:

¯ Create a widget that uses a callback to display the module. For


example, you can create a PtButton with a module-type link
callback that displays the module. For more information, see
“Editing callbacks” in the Editing Resources and Callbacks in
PhAB chapter.

¯ Use an internal link to create the module in your application’s


code. See the Accessing PhAB Modules from Code chapter.

Using the module selector


When you use the Application menu to create or view any of the six
PhAB module types (windows, dialogs, menus, etc.), PhAB displays
the module selector dialog:

112 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Creating a new module

Module Selector

Module Ty pe:
Window s Dialogs Menus Pictures Icons Others

Modules Sample View


base

Name
base

Open Delete Close

Module Selector dialog.

At the top of the dialog you’ll see a set of color-coded toggle buttons.
These let you select which type of module you wish to create/open,
delete or close. The default type is determined by the menu option
you chose to bring up the dialog.

Creating a new module


To create any new module, follow these simple steps:

1 From the Application menu, choose the type of module you


want to create. You’ll see the module selector.

2 In the Name field, type the instance name of the new module,
then press Enter or click on Open.

September 20, 2005 Chapter 5 ¯ Working with Modules 113


Viewing a module  2005, QNX Software Systems

☞ Module names must not be longer than 48 characters.

3 PhAB asks whether it should create the new module. Press


Enter or click on Yes. You’ll see the new module in PhAB’s
work area.

4 Click on Done.

☞ ¯ If you choose the “Others” module type, PhAB asks you to select
the type of module you want.

¯ If you’re creating an icon module for your application’s main


window, you should name the module Icon. This is the name the
Photon Desktop Manager (PDM) uses to extract the icon for its
quick-launch folders.

For more info on creating specific types of modules, see the sections
on each type of module in this chapter.

Viewing a module
To see a sample view of any module:

1 From the Application menu, choose the type of module you


want to view. You’ll see the module selector.

2 Click on the module’s name in the Modules scrolling list.

Opening a module
To display a module in your work area:

1 From the Application menu, choose the type of module you


want to open. You’ll see the module selector.

2 Do one of the following:

114 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Window modules

¯ double-click on the module’s name


Or
¯ click on the module’s name, then press Enter or click on
Open
Or
¯ type the module’s name, then press Enter or click on Open

Deleting a module
To delete a module:

1 From the Application menu, choose the type of module you


want to delete. You’ll see the module selector.

2 Click on the module’s name.

3 Click on the Delete button.

☞ Deleting a module doesn’t delete the module’s file; it just removes the
name from the list. Any callbacks belonging to the module or its
children are deleted.

Window modules

Widget class Color code File extension Widget creation


PtWindow Dark blue .wgtw Directly from the
widget bar

Typically, you use window modules for your application’s major


activities. Since most applications use a window module for their
main window, PhAB automatically generates a window module
named base when you first create any application. It also presets the
application’s startup information to make the base window open when

September 20, 2005 Chapter 5 ¯ Working with Modules 115


Dialog modules  2005, QNX Software Systems

the application starts up. (See “Specifying application startup


information” in the Working with Applications chapter.)
Window modules can support multiple instances. That is, two or more
copies of the same window module can be displayed at the same time.
As a result, you should keep track of each window’s instance pointer,
which is generated when you create the window. That way, you’ll
always know which window you’re dealing with when you process
callbacks. For more information, see “Handling multiple instances of
a window” in the Working with Code chapter.
Even though your application’s base window is a window module,
you usually display it only once, at startup. So unless your application
needs to display more than one copy of the base window at the same
time you won’t have to keep track of the base window’s instance
pointer.
For an example of code for handling multiple instances of window
modules, see “Creating Windows” in the Tutorials chapter.

Resizing a window module


When you set a window module’s size in PhAB, that’s the size it will
be when you run the application.

Dialog modules

Widget class Color code File extension Widget creation


PtWindow Green .wgtd Directly from the
widget bar

Dialog modules let you obtain additional information from the user.
Typically, you use this information to carry out a particular command
or task.
Most dialog modules include the following buttons:

116 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Menu modules

¯ Done — allows users to indicate that they’ve finished entering


information

¯ Cancel or Close — allows users to close the dialog without


responding

From PhAB’s perspective, dialog modules are almost identical to


window modules, with one important difference — a dialog module
can have only one active instance. So if you invoke a dialog that’s
already open, the PhAB API simply brings the existing instance of the
dialog to the front of the screen. This behavior fits with the nature of a
dialog — you rarely want to get the same information twice. If for
any reason you need a dialog that can support multiple instances, use
a window module.
Limiting a dialog to a single instance makes callback handling simpler
since you can use the widget manifests that PhAB generates to access
the widgets within the dialog. For more info, see the discussion on
instance names in the Creating Widgets in PhAB chapter.

Resizing a dialog module


When you set a dialog module’s size in PhAB, that’s the size it will be
when you run the application.

Menu modules

Widget class Color code File extension Widget creation


PtMenu Yellow .wgtm Special editor

A menu module provides a multilevel text-only menu. Unlike most


other modules, a menu module doesn’t let you create widgets directly
inside it. Instead, you use PhAB’s menu editor to create the menu’s
items.

September 20, 2005 Chapter 5 ¯ Working with Modules 117


Menu modules  2005, QNX Software Systems

Opening the menu editor


To open the menu editor:

1 Select a menu module.


2 Click on Menu Items in the Control Panel. PhAB displays the
menu editor:
Menu: File - [Menu Items]

Menu Items Lev el: 1 Menu Item Item Ty pes


< NEW > Command
Item Text: Submenu
Separator
Accel Text:
Toggle
Inst Name: Function

Callback: None

Actions

Apply

Reset

Remov e

Done Cancel

Menu editor.

In the upper-right corner you’ll see buttons that represent the


types of menu items you can create:
¯ Command — invokes a PhAB callback.
¯ Submenu — displays a child menu.
¯ Separator — provides lines or spacing between other menu
items.
¯ Toggle — changes or displays an application state.
¯ Function — specifies an application function that can
dynamically add menu items to the menu.

At the bottom of the dialog are two buttons:

118 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Menu modules

When you want to: Use this


button:
Apply any changes and close the editor Done
Cancel any changes made since you opened the editor Cancel

Specifying instance names


To create any command or toggle menu item (that is, any item that
can invoke a callback), you must enter a unique instance name —
PhAB enforces this. The instance name lets you access the menu item
from within your application code.
When PhAB generates the code for your application, it generates an
ABN ... global variable for each menu item that requires it. You use
this variable with the menu-item related API functions,
ApModifyItemState() and ApModifyItemText().
For example, let’s say a menu item isn’t available when the user clicks
on the widget that brings up the menu. Using the instance name, you
can dim that item before displaying the menu. For more information,
see “Initializing menus” in the Working with Code chapter.

Creating hotkeys and shortcuts


To help the user select a menu item more quickly, you can:

¯ provide a keyboard shortcut that selects the item

¯ provide a hotkey that directly invokes the command that the item
represents, even when the menu isn’t visible

A keyboard shortcut works only when the menu is currently visible.


A hotkey, on the other hand, should work whether the menu is visible
or not.
Creating a keyboard shortcut is easy. When you’re entering the Item
Text, simply place “&” in front of the character that will act as the
shortcut. For example, let’s say you’re creating a “Save As” item. You
could enter Save &As, which will underline the “A.” When the menu

September 20, 2005 Chapter 5 ¯ Working with Modules 119


Menu modules  2005, QNX Software Systems

opens, the user can press either A or a to invoke the callback


associated with “Save As”.
Creating a hotkey takes a bit more work, but it’s still easy to do. First,
you want to make sure that the hotkey accelerator appears next to the
menu item when the menu is displayed. To do this, use the Accel Text
field. For example, let’s say the hotkey accelerator for a “Save” menu
item will be Ctrl – S. In that case, you would type Ctrl-S in the
Accel Text field.
Next, you need to create a hotkey callback for Ctrl – S. Since the
menu might not be created when the user presses Ctrl – S, you can’t
attach the hotkey callback to the menu or to the menu item. Rather,
you must attach the callback to the application’s main module, which
is usually the base window module. When you specify the hotkey
callback’s function, use the same function you defined for the menu
item’s callback.
If for some reason you need to differentiate between the two methods
of invoking the callback, look at the callback’s reason code. Hotkeys
always have a reason code of Pt CB HOTKEY.
For more info on creating hotkey callbacks, see “Hotkey callbacks” in
the Editing Resources and Callbacks in PhAB chapter.

Resizing a menu module


Feel free to resize a menu module to make it more readable or take up
less space. When you run the application, the actual size of the
PtMenu widget will be determined by the menu items.

Creating command items


A command item lets you invoke application code or display a
module.

120 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Menu modules

Field Description
Item Text The text that will be displayed
Accelerator Text The hotkey to invoke the command
Instance Name The name used within the application code
Callback The function that will be called when the item
is selected

To create a command item:

1 Click on <NEW>.

2 Click on the Command button in the upper-right corner.

3 In the Item Text field, enter the item’s text. To create a shortcut
key, place “&” in front of the character that will act as the
shortcut.
For example, let’s say you enter &File. In that case, the user
can select the item by pressing F.

4 In the Inst Name field, enter the instance name you’ll use.

5 If you plan to have a hotkey callback for this item, enter the
hotkey string (for example, Ctrl-S) in the Accel Text field.
This string will appear in the menu as a reminder to the user.

6 Add a PhAB callback by clicking on the Callback icon:

For more info on creating a callback, see “Editing callbacks” in


the Editing Resources and Callbacks in PhAB chapter.

7 Click on Apply to add the item to the menu.

September 20, 2005 Chapter 5 ¯ Working with Modules 121


Menu modules  2005, QNX Software Systems

Creating submenu items


A submenu item lets you create another menu level.

Field Description
Item Text The text that will be displayed

To create a submenu item:

1 Click on <NEW>.

2 Click on the Submenu button in the upper-right corner.

3 In the Item Text field, type the name of the submenu. To create
a keyboard shortcut, place “&” in front of the character that will
act as the shortcut (just like command items, above).

4 Click on Apply.

5 You can now add items to the submenu. At the top of the Menu
Items list you’ll see the Level control:
Lev el: 1

Click on the down arrow, then add the submenu items you
want. You can add any type of menu item to a submenu,
including another submenu item.

Creating separator items


A separator item lets you create spacings between menu items. You’ll
find this item type handy for creating logical groupings of menu
items. You can choose from several separator styles.
To create a menu separator:

1 Click on <NEW>.

2 Click on the Separator button in the upper-right corner. You’ll


see a list of separator styles:

122 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Menu modules

Separator Sty le

Single Line

Double Line

Single Dash Line

Double Dash Line

Etched - In

Etched - Out

Blank

Styles of menu separators.

3 Click on the separator style you want, then click on Apply.

Creating toggle items


A toggle item lets you change or display an application state, which
can be either on or off.

Field Description
Item Text The text that will be displayed
Instance Name The name used within the application code
Callback The function that will be called when the item is
selected

To create a toggle item:

1 Click on <NEW>, then click on the Toggle button.

2 Follow the same procedure used to create command items.

September 20, 2005 Chapter 5 ¯ Working with Modules 123


Menu modules  2005, QNX Software Systems

Creating function items


A function item lets you specify an application function that
dynamically adds menu items to the menu at runtime. For example,
you could use a function item in a File menu to display the last three
files the user worked on.
The PhAB library invokes the specified function as the menu is built.
The dynamically created menu items appear where you’ve positioned
the function item in the menu.

Field Description
Function The function that will be called

To create a function item:


1 Click on <NEW>, then click on the Function button.
2 In the Function field, enter the name of the application function
that will dynamically add menu items to the menu.
If you specify this function name, PhAB will generate a stub
function; for information on specifying the language (C or
C++) and the filename, see “Function names and filenames” in
the Working with Code chapter.
3 You can edit the function right away by clicking on the button
to the right of the function name.
4 Click on Apply.
For information on the application function, see “Generating menu
items” in the Working with Code chapter.

Moving menu items


The Menu Items scrolling list lets you move a menu item to a new
position in the menu.
Let’s say you want to move an item named Browse so it appears just
before an item named Edit. You would:

124 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Menu modules

1 Drag the Browse item until its outline is directly over Edit.
2 Release the mouse button. The Browse item appears in its new
position.

Using a menu module


Once you’ve created a menu module, you need a way to make your
application display it. Typically, you do the following:

1 Create a PtMenuBar widget at the top of a window.


2 Add a PtMenuButton widget to the menu bar, giving it an
appropriate instance name and text string.
3 Add a module-link callback to the menu button’s Pt CB ARM
callback list.


You could add the callback to the Pt CB ACTIVATE list, but adding it
to Pt CB ARM allows the user to access it in two ways:
¯ by pressing the left mouse button on the menu button widget,
dragging to highlight a menu item, and releasing to select it.
This is known as the press-drag-release (PDR) method.
¯ by clicking on the menu, and then clicking on a menu item
If you use an Activate callback, the user can only use the second
method.

4 Have the callback display the menu module. See “Module


callbacks” in the Editing Resources and Callbacks in PhAB
chapter.
5 If you need to initialize the menu whenever it’s displayed,
specify a setup function for it. See “Initializing menus” in the
Working with Code chapter.

If you want your menu to appear when you press the right mouse
button while pointing at a widget, you’ll need to use an internal link.
For more information, see the Accessing PhAB Modules from Code
chapter — there’s even an example.

September 20, 2005 Chapter 5 ¯ Working with Modules 125


Picture modules  2005, QNX Software Systems

Picture modules

Widget class Color code File extension Widget creation


Not applicable Light blue .wgtp Directly from
the widget bar

Using a picture module, you can change the contents of an existing


module or create a convenient database of widgets. You always
display a picture inside a container-class widget or another module,
such as a window or dialog.
Like windows, picture modules support multiple instances. So you
should keep track of the instance pointer of the container that each
picture is placed into. That way, you’ll always know which picture
you’re dealing with when you process callbacks.
If you’re sure that your application will use only one instance of the
picture at any given point, you don’t have to keep track of instance
pointers. Instead, you can use PhAB-generated manifests to access
the picture’s widgets.

Displaying a picture
You always access picture modules from within your application
code. To access a picture, you must create an internal link to it. This
tells PhAB to generate a manifest that you can use with PhAB’s API
functions — such as ApCreateModule() — to access the picture.
For more information, see the Accessing PhAB Modules from Code
chapter.

Using pictures as widget databases


You can use a picture module as a widget database. A widget
database contains predefined widgets that you can copy at any time
into a window, dialog, or container.

126 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Icon modules

When using a widget database, you don’t have worry about handling
multiple instances since the generated PhAB widget manifests don’t
apply to widget databases: each widget you create is a new instance.
The instance pointer is returned to you when you create the widget
using ApCreateWidget(). You’ll need to keep track of this pointer
manually if you need to access the widget in the future.
For more info, see “Widget databases” in the Accessing PhAB
Modules from Code chapter.

Resizing a picture module


It doesn’t matter how large or small you make a picture module.
That’s because it has no associated widget class. Only the widgets
inside the module are used.

Icon modules

Widget class Color code File extension Widget creation


PtIcon Red .wgti Widgets are
predefined

Icon modules let you design your application’s icons. PhAB ensures
that these icons are automatically supported by Photon’s Desktop and
Window Managers.
Icon modules consist of two icon widgets:

¯ a large one for the Photon Desktop Manager (PDM) quick-launch


folders

¯ a small one for the Photon Window Manager (PWM) taskbar

PhAB automatically supplies samples of these icons when you create


the module. At any point, you can use PhAB’s pixmap editor,
described in the Editing Resources and Callbacks in PhAB chapter, to
redraw these samples into something more appropriate for your

September 20, 2005 Chapter 5 ¯ Working with Modules 127


Icon modules  2005, QNX Software Systems

application. You can even use the pixmap editor to import an existing
graphic.
Feel free to resize an icon module as you wish — it isn’t used to
display the icons.

Naming the icon module


When you create your application’s icon module, remember to
specify Icon as the module’s name. Then, open the base window’s
Window Icon (Pt ARG ICON WINDOW) resource and specify Icon
there as well. This ties the icon module to the application’s base
window module and makes it possible for PDM to find the icon.

Specifying sizes and instance names


The widgets in an icon module can be of any class, but they must have
the following sizes and instance names:

Instance name Size


LIcon 43¢43 pixels
SIcon 15¢15 pixels

The two sample icon widgets that PhAB provides are PtLabel-class
widgets with the Label Type resource set to Pt IMAGE. These icons
are prenamed and presized to match the specification. Unless you
have a specific icon requirement, we recommend you use these
samples and edit them with the pixmap editor.

☞ When you view the icon module using the Module Tree mode of the
Control Panel, LIcon must come before SIcon for Photon to find the
icons properly.

128 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Other modules

Other modules

Widget Color code File extension Widget creation


class
Depends Purple .wgtx Widgets are predefined
on
module’s
class

Other modules are predefined modules that PhAB provides for


specific purposes. Currently, you can choose from the following
types:

¯ file selector — to allow the user to open and save files


(class = AwFileSelect)

¯ message — to provide a text-based message, with optional buttons,


in a popup window (class = AwMessage)

Since each of these modules is predefined, you can’t add any widgets.
Nevertheless, you can edit several resources provided for the module
itself. Note, however, that changing a resource has no immediate
visual effect. That’s because the displayed module shows either a
sample of the widget class it represents or its current list of resources.
If you want to see the effects of any change, run the application.

☞ We strongly recommend that you not use these modules. Instead, use
the PtFileSel and PtMessage widgets (see the Photon Widget
Reference) or PtFileSelection(), and PtAskQuestion() or
PtMessageBox() (see the Photon Library Reference).

Resizing an “other” module


Feel free to resize these modules to take up less space in PhAB.
They’ll appear in a predefined size when you run your application.

September 20, 2005 Chapter 5 ¯ Working with Modules 129


Iconifying modules  2005, QNX Software Systems

Iconifying modules

about dlg PhAB’s work area lets you work on several application modules at
once. You can iconify modules to organize your work area. The icons
are color-coded so you can identify what kind of module each icon
represents. See “Module types” in this chapter.
To reduce any module in the work area to an icon:

¯ double-click on the module’s Work menu button (upper-left corner


of the module)
Or

¯ click on the Work menu button and choose Minimize

Once it’s iconified, the module positions itself at the bottom of the
work area. You can drag it anywhere in the work area, so (for
example) you can group commonly used or related icons.

Rearranging icons
To automatically rearrange module icons into neat rows starting at the
bottom-left corner, choose Arrange Icons from the Window menu.

Importing PhAB modules from other


applications
To import a PhAB module from another application:

1 Choose Import Files from the File menu, then choose PhAB
Module from the Import Files submenu. You’ll see a file
selector.

2 The file selector may display several modules. To identify the


module you want by its file extension, see “Module types” in
this chapter.

3 To select the module, do one of the following:

130 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Importing QNX Windows picture files

¯ double-click on the module


¯ click on the module, then press Enter or click on Open
¯ type the module’s name, then press Enter or click on Open

☞ Callbacks aren’t imported, only the module and the widgets


themselves. After importing the module, you can attach new
application-specific callbacks.
Normally, PhAB retains the instance name of each imported widget.
However, if it detects a duplicate name, it changes that name to the
widget-class name to avoid code-generation errors.

Importing QNX Windows picture files


To import a QNX Windows picture (.pict) file:

1 Choose Import Files from the File menu, then choose QNX
Windows Picture File from the Import Files submenu. You’ll
see a file selector.

2 Choose the picture file. You’ll be asked to choose the type of


module you want to import the picture file into:

Window main base window picture


Dialog popup window picture
Picture database picture (that is, QNX Window links), or
pictures that replace other pictures

September 20, 2005 Chapter 5 ¯ Working with Modules 131


Closing a module  2005, QNX Software Systems

☞ ¯ QNX Windows window files (.wnd) can’t be imported, as they


have no equivalent in Photon. Only picture files (.pict) can be
imported.

¯ Not all QNX Windows elements are supported. Photon doesn’t


currently have a Meter, Dial or Number widget, so the importer
converts Numbers into PtText widgets, and ignores Meters and
Dials.

¯ Not all QNX Windows format options are supported.

Closing a module
If you wish to stop working on a module and remove it from the work
area:

1 Click on the module’s Work menu button (upper-left corner of


the module).

2 Choose the Close item.


If you simply wish to iconify the module, choose the Minimize
item.

To reopen any module that’s been closed, see the “Module selector”
section in this chapter.

Positioning a module
You can specify where a module will display when you create a link
callback from a widget to that module. To do this, you use the
location dialog.

Opening the location dialog


To open the Location dialog and select a module’s location:

132 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Positioning a module

1 When creating or editing a link callback to a module, click on


the Location field or on the icon to the right of the field. You’ll
see a list of locations:
Dialog Location
Location

Below Widget Top/Lef t Screen Cent er Screen

Abov e Widget Bot /Lef t Screen Relat ive t o Point er

Right of Widget Top/Right Screen Relat ive t o Module

Lef t of Widget Bot /Right Screen Def ault

+ Offset: X 0 Y 0

Done Cancel

Location dialog.

For windows and dialogs, the default location is Default (0,0),


which places the window at the next available position defined
by the Window Manager. The default location for a menu
module is Below Widget.

2 Click on the location you want.

September 20, 2005 Chapter 5 ¯ Working with Modules 133


Selecting a module  2005, QNX Software Systems

3 You can also specify x and y offsets. For example, if you set the
location to the bottom-right corner and set the x offset to -100,
the window will be displayed so that its bottom-right corner is
100 pixels to the left of the bottom-right corner of the screen.

☞ If you choose Default as the location, the offsets are ignored.

4 Click on Done.

Selecting a module
To select a module that’s in the PhAB work area:

¯ Click on the module’s titlebar.


Or

¯ If the module is iconified, double-click on its icon.


Or

¯ Bring up the Window menu and choose the module by name (this
works for both iconified and noniconified modules).

Whichever method you choose, you’ll see resize handles that indicate
the module is selected.
For information on opening a module that’s not currently in PhAB’s
work area, see “Opening a module” in this chapter.

Finding lost modules and icons


To find a lost module or icon:

¯ Choose Arrange Modules from the Window menu. PhAB cascades


all open modules and pulls the Control Panel back into the PhAB
work area.

¯ Choose Arrange Icons from the Window menu. PhAB rearranges


all existing icons along the bottom of the work area.

134 Chapter 5 ¯ Working with Modules September 20, 2005


 2005, QNX Software Systems Finding lost modules and icons

If the above techniques don’t work, you may have “closed” the
module. (PhAB lets you close a module to remove it from your work
area and reduce clutter.) To find how to reopen a closed module, see
“Opening a module” in this chapter.

September 20, 2005 Chapter 5 ¯ Working with Modules 135


Chapter 6
Creating Widgets in PhAB

In this chapter. . .
Types of widgets 139
Instance names 140
Creating a widget 142
Selecting widgets 143
Positioning widgets with a grid 147
Aligning widgets 149
Common User Access (CUA) and handling focus 150
Ordering widgets 152
Dragging widgets 153
Setting a widget’s x and y coordinates 154
Transferring widgets between containers 154
Resizing widgets and modules 154
Moving and resizing widgets with the nudge tool 155
Clipboard 156
Duplicating widgets and containers 159
Deleting widgets 159
Importing graphic files 159

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 137


 2005, QNX Software Systems Types of widgets

Once you’ve created or opened an application, you’ll probably want


to add, delete, and modify widgets. This chapter describes how to
work with widgets.

☞ For information on using specific widget classes, see:

¯ the Widgets at a Glance appendix in this guide

¯ the Photon Widget Reference

Since widgets inherit a lot of behavior from their parent classes, you
should make yourself familiar with the fundamental classes:
PtWidget, PtBasic, PtContainer, and so on.

Types of widgets
There are two major types of widgets:

¯ container widgets — such as PtPane and PtScrollArea


¯ noncontainer widgets — such as PtButton and PtText

Container-class widgets can contain other widgets — including other


containers. Widgets placed inside a container are known as child
widgets; the hierarchy resulting from this nesting is called the widget
family. Container widgets can look after sizing and positioning their
children, as described in the Geometry Management chapter.
When working with container-class widgets in PhAB, remember the
following:

¯ If you move a container, all the container’s child widgets also


move.

¯ If you position the pointer inside a container when creating a new


widget, that widget is placed hierarchically within the container.

¯ If you wish to use the bounding-box method to select widgets in a


container, you must:
- press Alt before you start the bounding box

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 139


Instance names  2005, QNX Software Systems

- start the bounding box within the container


For more info, see “Selecting widgets” in this chapter.

Instance names
If your program has to interact with a widget, that widget must have a
unique instance name. Using this name, PhAB generates a global
variable and a manifest that let you easily access the widget from
within your code.
To view or edit a widget’s instance name, use the Widget Instance
Name field at the top of the Control Panel:
Widget Instance Name F9 F10

base_file

Editing a widget’s instance name.

☞ ¯ A widget’s instance name is used to make several C variables, so it


can include only letters, digits and underscores. PhAB won’t let
you use any other characters. An instance name can be no longer
than 64 characters.

¯ You should develop a naming convention for all the widgets in


your application — it will make large applications more
manageable.

You can optionally include the instance name in the widget’s memory.
See “Including instance names” in the Working with Applications
chapter.

Default instance name


When you create a widget, PhAB automatically gives it a default
instance name. Typically, this default name is the widget’s class

140 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Instance names

name. For example, if you create a PtButton-class widget, the


Control Panel displays PtButton as the instance name.
If a widget simply serves as a label or window decoration, it doesn’t
have to be accessed from within your application code. So you should
tell PhAB to ignore the widget’s instance name during code
generation. To do this:

¯ Leave the instance name equivalent to the class name (that is, leave
the default alone).
Or

¯ Provide a blank instance name.

When to assign a unique name


You should give a widget a unique name if:

¯ the widget needs to have a callback attached

¯ the application needs to change the widget by setting a resource

¯ the application needs to extract information from the widget

☞ To keep the number of global variables to a minimum, don’t give a


widget a unique name unless you really need to access the widget
from within your application. If you’ve given a widget a name and
later decide you don’t need the name, just change it back to the
widget’s class name or blank it out.

Instance names and translations


As described in the chapter on International Language Support, you’ll
need an instance name for every text string in your application’s user
interface. These instance names aren’t needed in your code.
To indicate that an instance name isn’t required for code generation,
start the name with the @ character. PhAB recognizes such a name
when generating the text language database, but skips over it when
generating code.

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 141


Creating a widget  2005, QNX Software Systems

If you don’t want to create a unique instance name for a string that’s
to be translated, specify a single @ character for the instance name,
and PhAB appends an internal sequence number to the end.
If you don’t want to create unique instance names, but you want to
organize the text for translation (say by modules), you can give the
strings the same instance name, and PhAB will append a sequence
number to it. For example, if you assign an instance name of @label
to several strings, PhAB will generate @label, @label0, @label1,
... as instance names.

Duplicate names
PhAB resets the instance name of a widget back to the widget class
name if it detects a duplicate name when you:

¯ copy and paste a widget (see “Clipboard”)

¯ import a widget from another application (see “Importing PhAB


modules from other applications” in the Working with Modules
chapter)

¯ duplicate a widget (see “Duplicating widgets and containers”)

Creating a widget
To create a widget:

1 If the widget isn’t in the widget bar, you’ll have to add it. See
“Customizing the widget bar” in the PhAB Environment
chapter.

2 Click on widget-bar icon for the type of widget you want to


create (see the Widgets at a Glance appendix to identify the
widget-bar icons).

3 Move the pointer to where you want to create the widget. The
pointer changes to show you what to do next:
¯ If the pointer is a crosshair and you’re creating a
PtPolygon or PtBezier widget, hold down the mouse

142 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Selecting widgets

button and drag the pointer until the line goes where you
want it to go. To add points, you must start the next point on
top of the last.
¯ If the pointer is a crosshair and you’re creating any other
type of widget, click the mouse button.
¯ If the pointer is a two-headed arrow, hold down the mouse
button and drag the pointer until the widget is the size you
want.

Creating several widgets


Once you’ve created a widget, you’re returned to select mode. To stay
in create mode so you can create several widgets of the same type:
1 Press and hold down Ctrl.
2 Create as many widgets as you want.
3 Release Ctrl.

Canceling create mode


To cancel create mode without creating a widget:
¯ Click the right mouse button in a module.
Or
¯ Click on the arrow icon at the top of the widget bar.

Selecting widgets
When PhAB is in select mode, the pointer appears as an arrow. To put
PhAB into select mode:
¯ Click the right mouse button in a module.
Or
¯ Click on the arrow icon at the top of the widget bar:

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 143


Selecting widgets  2005, QNX Software Systems

A single widget
To select a single widget, you can:

¯ Point and click.


Or

¯ Use the Control Panel.

Point-and-click method
To select a single widget using point and click:

1 Make sure you’re in select mode.

2 Click on the widget, using the left mouse button. Resize


handles will appear around the widget.

Control-Panel methods
The Next and Previous buttons in the Control Panel let you select any
widget in the current module.

To select the: Click on: Or press:

Previous widget in the current module F9

Next widget in the current module F10

The Control Panel also provides a Module Tree mode that displays a
tree of all the widgets in the module. Using this tree, you can:

¯ select a widget inside a group

¯ find a widget by name

¯ select a widget hidden underneath another widget

To select a widget from the tree, click on the widget’s name.

144 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Selecting widgets

Multiple widgets
To select multiple widgets, you can:
¯ Use a bounding box.
Or
¯ Use “Shift and click.”
Or
¯ Use the Control Panel

☞ When you select two or more widgets, the Control Panel displays
only the resources that those widgets have in common. Editing any of
these resources will affect all the selected widgets.

Using a bounding box


A bounding box lets you select several widgets all at once:
1 Position the pointer above and to the left of the widgets you
want to select.
2 If the widgets belong to a container such as PtPane, make sure
the pointer is within the container, then hold down the Alt key.
3 Hold down the left mouse button, then drag the pointer down to
the right. You’ll see an outline “grow” on the screen. For
example:

Red Blue Green

4 When all the widgets are within the outline, release the mouse
button. You’ll see resize handles appear around the area defined
by the selected widgets.

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 145


Selecting widgets  2005, QNX Software Systems

Using “Shift and click”


To add or remove a widget from the current list of selected widgets,
hold down Shift and click on the widget. This is also known as the
extended selection method.
If the widget isn’t already selected, it’ll be added to the list. If the
widget is already selected, it’ll be removed from the list.

☞ The above methods for selecting multiple widgets work only for
widgets at the same hierarchical level. For example, let’s say you’ve
just selected two buttons inside a window. You can’t extend that
selection to include a button that’s inside a pane.

Using the Control Panel


To select multiple widgets, using the Control Panel’s Next and
Previous buttons:

1 Hold down Shift.

2 Click on the Next button.


Every time you click, PhAB adds the next widget in the current
module to your selection.

To remove the last widget from the current list of selected widgets:

1 Hold down Shift.

2 Click on the Previous button.


Every time you click, PhAB removes another widget.

Widgets within a group


To select a widget inside a group, you can use the Control Panel’s
Module Tree mode or its Next and Previous buttons.

146 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Positioning widgets with a grid

Selecting a single widget


To select a single widget within a group:

1 Switch the Control Panel to Module Tree mode.

2 Find the group in the tree and click on the widget’s name.

3 To edit the widget, switch the Control Panel to either Resources


mode or Callbacks mode.

Selecting multiple widgets


To select one or more widgets within a group:

1 Click on any widget within the group to select the entire group.

2 Click on the Control Panel’s Next button (or press F10) until
the widget you want is selected.

3 To select additional widgets, press Shift, then click again on the


next-widget button.

4 You can now edit the widgets’ resources or callbacks.

Hidden widgets
If you can’t find a widget (it may be hidden behind another widget or
is outside the boundaries of its container), do the following:

1 Using the Control Panel’s Next and Previous buttons or Module


Tree mode, select the widget.

2 If the widget seems to be outside the current boundaries of its


container, bring it back into view by using the speedbar’s x and
y fields.

Positioning widgets with a grid


PhAB lets you use a grid to position and size widgets. You can turn
the grid on or off, or change its origin and size. The grid doesn’t
appear onscreen.

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 147


Positioning widgets with a grid  2005, QNX Software Systems

To change the grid:

1 Choose Grid from the Options menu. The following dialog


appears:

Grid Settings

Grid Origin

Horizontal: Pixels

Vertical: Pixels

Grid Frequency

Horizontal: Pixels

Vertical: Pixels

Snap to Grid

Done Cancel

Grid Settings dialog.

2 Type in an origin and a frequency.

3 Enable Snap to Grid — otherwise the grid isn’t used.

4 Click on Done.

☞ Grid settings remain for the current session only. They aren’t saved.

148 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Aligning widgets

Aligning widgets
You can align several widgets to another widget or to their parent
container.

To another widget
When you use this method to align widgets, the widgets are aligned to
the first widget you select:

1 Select the first widget.

2 Using the “Shift and click” selection method, select the


remaining widgets. (This method is described in “Selecting
widgets.”)

3 Bring up the Align Widgets dialog. To do this, you can:


¯ choose Alignment from the Edit menu
¯ press Ctrl – A
¯ click on the Alignment icon in the speedbar:

4 Choose one or more alignment options, then click on the Align


Widgets button. Don’t click on an Align to Container button.

To a parent container
To align widgets to their parent container:

1 Select one or more widgets in any order.

2 Bring up the Align Widgets dialog, choose your alignment


options, then click on the appropriate Align to Container button.
If you choose both vertical and horizontal options, make sure to
click on both Align to Container buttons.

3 Click on the Align Widgets button.

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 149


Common User Access (CUA) and handling focus  2005, QNX Software Systems

☞ When aligning widgets to a container you may want the widgets to


retain their relative positions to each other. To do this:

1 Group the widgets together (see the section “Aligning widgets


using groups” in the Geometry Management chapter).

2 Align the widgets.

3 Break the group apart (optional).

Common User Access (CUA) and handling


focus
Common User Access (CUA) is a standard that defines how a user
can change the keyboard focus. A widget is focusable if it can be
given focus by pressing CUA keys or by calling a focus function.

Changing focus with the keyboard


The following keys move focus only to focusable widgets:

To go to the: Press:
Next widget Tab
Previous widget Shift – Tab
First widget in the next container Ctrl – Tab
Last widget in the previous container Ctrl – Shift – Tab

For information on specifying the order in which the widgets are


traversed, see the section “Ordering widgets” in this chapter.

150 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Common User Access (CUA) and handling focus

Controlling focus
Use the following Pt ARG FLAGS flags to control focus for a widget:

Pt GETS FOCUS
Make the widget focusable
Pt FOCUS RENDER
Make the widget give a visual indication that it has focus

In addition, use the following Pt ARG CONTAINER FLAGS flags to


control focus for a container:

Pt BLOCK CUA FOCUS


Prevent the CUA keys from being used to enter the container.
However, if the user clicks inside the container, or a focus
function gives it focus, the CUA keys can then be used.

Pt ENABLE CUA
Give the parent widget the chance to control whether or not a
child container handles the CUA keys:
¯ If this flag is set, the widget’s code handles the CUA keys.
¯ If it isn’t set, the CUA keys are passed up the widget family
until an ancestor is found with this flag set. This ancestor (if
found) handles the keys.

Pt ENABLE CUA ARROWS


The same as Pt ENABLE CUA, but it applies only to the arrow
keys.

Focus callbacks
All descendants of the PtBasic widget have the following callback
resources:

¯ Pt CB GOT FOCUS — called when the widget gets focus

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 151


Ordering widgets  2005, QNX Software Systems

¯ Pt CB LOST FOCUS — called when the widget loses focus

For more information, see the Widget Reference.

Focus-handling functions
For a list of functions that deal with focus-handling, see the Summary
of Entries in the Photon Library Reference.

Ordering widgets
In PhAB, each widget exists in front of or behind other widgets. This
is known as the widget order, and you can see it when you overlap
several widgets.
Here’s how to ensure that widgets are in the order you want (so that,
for example, using CUA keys to move between widgets works in the
correct order):

1 Using the extended (“Shift and click”) selection method, select


the widgets in the order you want. (This selection method is
described in “Selecting widgets.”)

2 Do one of the following:


¯ choose To Front or To Back from the Edit menu
¯ press Ctrl – F or Ctrl – B
¯ click on one of these icons:

PhAB will place the widgets in the order you selected them.

☞ If you’re not using PhAB, the widget order is the order in which the
widgets are created. To change the order, see “Ordering widgets” in
the Creating Widgets in Application Code chapter.

To view the widget order, do one of the following:

152 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Dragging widgets

¯ use the Control Panel’s Module Tree mode

¯ use the module’s Test mode to check the focus order

Dragging widgets
Dragging a widget is the easiest way to move a widget in most
situations since it’s quick and fairly accurate:

1 Select the widgets.

2 Point to one of the selected widgets, press down the mouse


button, then drag the widgets to the new position.

3 Release the mouse button.

To cancel a drag operation, press Esc before releasing the mouse


button.

☞ ¯ Widgets will snap to the grid if the grid is enabled. See the
“Positioning with a grid” section in this chapter.

¯ Widgets may “disappear” if you move them beyond the boundaries


of their container. If this happens, use the previous/next buttons in
the Control Panel to select the widgets, then use the x and y fields
in the speedbar to bring the widgets back into view.

Dragging preferences
There are several preferences that you can set for dragging (see the
“Customizing your PhAB environment” section in the chapter on
PhAB’s environment):

¯ Dragging has a damping factor that determines how far you must
drag before the widget moves. The default is 4 pixels.

¯ You can drag widgets either as an outline or as full widgets.

¯ You can drag modules either as an outline or as full modules.

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 153


Setting a widget’s x and y coordinates  2005, QNX Software Systems

Setting a widget’s x and y coordinates


To place one or more widgets at specific coordinates:
x y
1 Select the widgets.

2 Type the coordinates in the x and y fields in the speedbar, then


press Enter.

Transferring widgets between containers


To move one or more widgets directly from one container or module
to another:

1 Select the widgets.

2 Do one of the following:


¯ Choose Transfer from the Edit menu.
Or
¯ Press Ctrl – T.
Or
¯ Click on the Transfer icon in the speedbar:

3 Move the pointer into the other container and click the mouse
button.

Resizing widgets and modules

Bu When you select a widget or module, you’ll see its height and width
— including margins — displayed in the speedbar’s height and width
fields. (These values are maintained by the Pt ARG DIM resource;
see the description of PtWidget in the Widget Reference.)
To resize a selected widget, do one of the following:

154 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Moving and resizing widgets with the nudge tool

¯ Drag one of the widget’s resize handles.


Or

¯ Click on the height or width field in the speedbar, type in a new


value, then press Enter.
Or

¯ Use the nudge tool.

☞ If a module is in Test mode, its resize handles won’t function. To


resize the module using the handles, click on the module-type tab to
switch the module to build mode.
If you have trouble seeing a widget’s resize handles because of the
background color you’ve chosen, you can change the resize-handle
color. For more info, see “Customizing your PhAB environment” in
the PhAB Environment chapter.

Moving and resizing widgets with the nudge


tool

The nudge tool has three modes of operation. To switch between


these modes, click on the small box in the center of the arrows. The
box changes to indicate which function is active.

If the box is a: Clicking on an arrow will:


Square Nudge the currently selected widget
+ Stretch the widget
- Shrink the widget

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 155


Clipboard  2005, QNX Software Systems

Each arrow has a different effect. Experiment to see exactly how this
tool works. One thing you should note: If the box is a “-”, clicking on
an arrow shrinks the widget in the opposite direction of the arrow.
Every click on the nudge tool will nudge, stretch, or shrink the
selected widget by one pixel. To nudge by multiple pixels, hold down
the mouse button.

☞ You can also use the Ctrl key and the numeric keypad to nudge,
stretch, or shrink a widget. Each key corresponds to one of the nudge
buttons. For example, Ctrl – 5 switches between modes, and Ctrl – ↑
works like the tool’s ↑ button.

Clipboard
PhAB’s clipboard lets you cut, copy, and paste widgets. You can’t use
this clipboard with other applications but you can use it to copy or
move widgets from one PhAB application to another.
You’ll find the clipboard helpful for two reasons:

¯ it saves you from creating large numbers of widgets from scratch

¯ it helps you create applications whose widgets look and behave


consistently with each other

Cutting and copying


A cut operation removes the currently selected widgets from their
module and places them in the clipboard. A copy operation copies the
currently selected widgets to the clipboard without removing them
from their module.

☞ Whenever you cut or copy, PhAB removes any widgets already in the
clipboard.

To cut or copy one or more widgets:

1 Select the widgets.

156 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Clipboard

2 To cut, do one of the following:


¯ Choose Cut from the Edit menu.
Or
¯ Press Del.
Or
¯ Click on the Cut icon in the speedbar:

3 To copy, do one of the following:


¯ Choose Copy from the Edit menu.
Or
¯ Press Shift – Del.
Or
¯ Click on the Copy icon in the speedbar:

☞ ¯ PhAB deletes a widget’s callbacks when you cut or copy the


widget to the clipboard. If you want to move a widget to another
container but retain its callbacks, see “Transferring widgets
between containers” in this chapter.

¯ The Edit menu also contains a Delete command. This command


permanently removes widgets without copying them to the
clipboard.

Pasting
A paste operation copies widgets from the clipboard into a module.
To paste the contents of the clipboard:

1 Make sure you’re in Select mode.

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 157


Clipboard  2005, QNX Software Systems

2 Do one of the following:


¯ Choose Paste from the Edit menu.
Or
¯ Press Insert.
Or
¯ Click on the Paste icon in the speedbar:

3 Point to where you’d like the clipboard objects to appear, then


click the mouse.

☞ ¯ Instance names are normally maintained when you paste. But if


PhAB detects a duplicate name, it changes that name back to the
class name.

¯ Because the clipboard state is saved between PhAB applications,


you can cut widgets from one PhAB application and paste them
into another.

Viewing the clipboard


To view the contents of the clipboard, choose Clipboard from the
View menu.

Editing the clipboard


To add new widgets to the clipboard, or to edit or delete specific
widgets already in the clipboard, use the same methods that you
would use to edit widgets in a window or dialog module.
For a quicker way to duplicate widgets, see “Duplicating widgets and
containers.”
For a quicker way to move widgets from one container to another, see
“Transferring widgets between containers” in this chapter.

158 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


 2005, QNX Software Systems Duplicating widgets and containers

Duplicating widgets and containers


Here’s a quick and easy way to duplicate a widget or container (it’s
much simpler than using the clipboard):

1 Press and hold down Ctrl.

2 Point to the widget or container, hold down the left mouse


button, then drag the pointer to where you’d like the new
widget to appear.

3 Release Ctrl and the mouse button.

☞ ¯ You can duplicate only one container or widget at a time. If you


duplicate a container, all its children are duplicated as well.

¯ The instance names of the new widgets are reset to be the widget
class name.

¯ Callbacks aren’t duplicated.

Deleting widgets
To permanently remove one or more selected widgets without
copying them to the clipboard:

1 Select the widgets.

2 Choose Delete from the Edit menu or press Ctrl – D.

If you want put the widgets somewhere else, you should cut the
widgets, not delete them. For more information, see the section on the
clipboard in this chapter.

Importing graphic files


PhAB lets you import several kinds of graphic files into your
application. To import a graphic file:

September 20, 2005 Chapter 6 ¯ Creating Widgets in PhAB 159


Importing graphic files  2005, QNX Software Systems

1 Select the module in which you want to place the graphic.

2 Choose Import Files from the File menu. You’ll see the Import
submenu. If this menu is dimmed, you haven’t selected a
module.

3 Choose Graphics Image File from the Import submenu. You’ll


see a file selector.

4 To choose a file, do one of the following:


¯ double-click on the file
¯ click on the file, then press Enter or click on Open
¯ type the file’s name, then press Enter or click on Open
PhAB will read the file, convert it into a PtLabel widget, and
set the widget’s Pt ARG LABEL TYPE resource to Pt IMAGE.

5 If you wish to edit the imported file, use the pixmap editor,
described in the Editing Resources and Callbacks in PhAB
chapter.

☞ PhAB doesn’t export graphic files directly. That’s because any


imported file is saved with the module in a PhAB-specific format.

The Pixmap editor (described in the Editing Resources and Callbacks


in PhAB chapter) also lets you import graphics: select the widget you
want to add the image to, edit its image, and choose the pixmap
editor’s Import button.

160 Chapter 6 ¯ Creating Widgets in PhAB September 20, 2005


Chapter 7
Editing Resources and Callbacks in
PhAB

In this chapter. . .
Editing widget resources 163
Pixmap editor 164
Color editor 172
Flag/option editor 173
Font editor 175
List editor 176
Number editor 178
Text editor 179
Multiline text editor 180
Function editor 182
Callbacks 183
Editing callbacks 185
Module callbacks 187
Code callbacks 189
Hotkey callbacks 190
Raw-event callbacks 196

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 161
 2005, QNX Software Systems Editing widget resources

Editing widget resources


A widget typically has many resources that let you change its
appearance and behavior. Each type of resource has its own editor.
To open any resource editor:

1 Select one or more widgets.

☞ When you select two or more widgets, the Control Panel displays
only the resources that those widgets have in common. Editing any of
these resources will affect all the selected widgets.

2 Switch the Control Panel to Resource mode, if necessary.


If a resource’s value has been changed from the default value
set for the widget, the resource’s label is displayed in bold.

3 Click on a resource in the Control Panel. The appropriate


resource editor will pop up.

Every resource editor provides the following buttons:

Done Apply Default Cancel

Common buttons for resource editors.

When you want to: Use this button:


Apply any changes and close the editor Done
Apply any changes and continue editing Apply
Restore the resource to the default value (or Default
values if more than one widget is selected)
Cancel any changes made since you opened the Cancel
editor or last clicked on Apply

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 163
Pixmap editor  2005, QNX Software Systems

The editors for different types of resources are described in the


sections that follow.

To edit: See this section:


Bitmaps or images Pixmap editor
Colors Color editor
Flags Flag/option editor
Fonts Font editor
Lists of text items List editor
Numbers Number editor or Flag/option editor
Single-line text strings Text editor
Multiline text strings Multiline text editor
Functions Function editor

Pixmap editor
The pixmap editor lets you customize a widget’s pixmap. The editor
provides a complete range of tools, so you can draw virtually any
pixmap your application might need.

➤ To open the pixmap editor for any widget that can contain an
image (for example, PtBitmap, PtButton), click on the
widget, then click on a Bitmap or Label resource in the Control
Panel.

164 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Pixmap editor

Select an area

Freehand drawing

Straight line

Hollow rectangle

Filled rectangle

Hollow circle

Filled circle

Fill an area

Drawing color

Background color

Pixmap size

Nudge arrows

Sample pixmap editor session.

The editor has several drawing modes and tools. The default is
freehand mode — you simply drag the pointer across the drawing
grid.

Setting the pixmap’s size


The editor contains fields for the pixmap’s height and width, both
specified in pixels. To change a dimension, edit the field and press
Enter.

☞ If you reduce the size of a pixmap, part of the image may be cut off.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 165
Pixmap editor  2005, QNX Software Systems

Choosing colors
To choose the draw color:

1 Click on the following color selector:

If you’re editing a bitmap, you’ll see the color editor. If you’re


editing an image, you’ll see the palette color selector.

2 Click on the color of your choice. All drawing will be done in


that color until you select a new color.

Choosing a background color


If you’re editing a bitmap, the background color is always transparent.
If you’re editing an image resource, you can choose the background
color (which you draw using the right mouse button). To choose the
background color:

1 Click on the following color selector:

2 Click on the color of your choice.

For more info, see the Color editor section.

How to draw and erase


The following applies to all drawing tools:

In order to: Use the:


Draw in the current color Left mouse button

continued. . .

166 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Pixmap editor

In order to: Use the:


Erase a pixel or area (i.e. draw in the Right mouse button
background color)

Drawing freehand
The freehand tool lets you draw freeform lines and erase single pixels
for quick fix-ups.
To draw in freehand mode:

1 Click on the freehand tool:

2 Point to where you’d like to start drawing.

3 Drag the pointer, moving it as if you were drawing with a


pencil, then release the mouse button when you’re done.
You can repeat this step as often you’d like.

➤ To erase the pixel under the pointer, click the right mouse
button.

Drawing lines, rectangles, and circles


To draw lines, rectangles, or circles, you use one standard method:

1 Click on the appropriate tool.

2 Point to where you’d like the object to begin.

3 Drag the pointer to where you’d like the object to end, then
release the mouse button.
You can repeat this step as often as you’d like.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 167
Pixmap editor  2005, QNX Software Systems

Filling an enclosed area


To fill any enclosed area (i.e. any area made up of a single color):

1 Click on the fill tool:

2 Move the pointer inside the area you wish to fill, then click.

☞ If an outline area has a break, the fill operation will spill out of the
hole and potentially fill the entire pixmap display.

Selecting an area
To use some tools, you first select an area of the pixmap.
To select an area:

1 Click on the Select tool:

2 Point to where you’d like the selection to begin.

3 Drag the pointer to where you’d like the selection to end, then
release the mouse button.
You can now “nudge” the area or perform any of the operations
described in “Using the Pixmap Tools window,” below.

Nudging an area
To nudge a selected area one pixel at a time:

1 Select the area you wish to nudge.

2 Click on a nudge arrow:

168 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Pixmap editor

Some things to note:

¯ PhAB overwrites any pixels in the direction of the nudge.

¯ A nudge can’t push an area out of the pixmap.

¯ PhAB introduces blank space into the pixmap to fill the space left
by the area you’ve nudged.

Using the Pixmap Tools window


The pixmap editor provides several other tools in their own window;
if you click on the Tools button, the Pixmap Tools window opens:
Cut

Rotate clockwise Insert a column

Rotate counterclockwise Delete a column

Flip horizontally Insert a row

Flip vertically Delete a row

Copy Paste

Pixmap Tools window.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 169
Pixmap editor  2005, QNX Software Systems

Rotating an area
To rotate an area 90 degrees clockwise or counterclockwise:

1 Select the area you wish to rotate.

2 Open the Tools window and click on a rotate tool.

Some things to note:

¯ If you rotate an area that isn’t perfectly square, the area may
overwrite some pixels.

¯ If part of the rotated area falls out of the pixmap, that part may be
deleted.

Flipping an area
To flip an area sideways or upside-down (where the first pixel in the
area will become the last, and so on):

1 Select the area you want to flip.

2 Open the Tools window and click on a flip tool.

☞ By using the flip tools with the copy tool, you can create mirror
images.

Inserting or deleting a row or column


To insert or delete either a row or column of pixels:

1 Choose the Select tool, then click on a row or column.

2 Click on the icon that represents the action you want.

☞ When you insert a row or column, the last row or column will shift off
the pixmap.

170 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Pixmap editor

Cutting, copying, and pasting


To cut or copy an area of pixels:

1 Select the area you wish to move or copy.

2 Open the Tools window and click on either cut or copy.

To paste an area of pixels:

1 Click on the paste icon.

2 Point to the new location, then click. This click specifies the
top-left corner of the area’s new position.

☞ Using the pixmap clipboard, you can:

¯ copy images from one widget to another

¯ copy an image to its “set” version to make minor modifications

Other pixmap controls


The pixmap editor also includes the following buttons:

When you want to: Use this button:


Quickly erase the pixmap Clear
Toggle the grid on and off Grid
See the pixmap drawn to its actual size View
Delete the pixmap and dismiss the pixmap Delete
editor
Import an image (for image-type resources Import
only)

For a description of the standard editor buttons at the bottom of the


editor, see the “Editing widget resources” section.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 171
Color editor  2005, QNX Software Systems

Color editor
The color editor lets you modify any color resource. To open the color
editor:

1 Select one or more widgets.

2 Click on a color resource in the Control Panel. You’ll see the


color editor:

Color Editor

Color: Fill Base Colors

Transparent

Color M odel Custom Colors M ix


RGB Model HSB Model

R 254

G 128

B 1

Done Apply Default Cancel

Color Editor.

The color editor provides 16 base colors that you can’t change. It also
provides an additional 48 colors that you can customize using either
the RGB (red/green/blue) or the HSB (hue/saturation/brightness) color
model, whichever you prefer.
To change a color resource:

172 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Flag/option editor

1 Click on the color you want. If you click on a custom color, you
can modify it with the sliders.

2 Click on Apply or Done.

Ensuring color consistency


The Mix box helps ensure that your application colors look as
accurate as possible on target systems where the graphics card doesn’t
support the actual color you’ve chosen. With Mix enabled, the
graphics driver dithers available colors to get a closer match.
For a description of the standard editor buttons at the bottom of the
editor, see the “Editing widget resources” section.

Flag/option editor
Whenever you click on a flags resource or on a resource that lets you
select only one of several preset values, you’ll see the flag/option
editor. For example:

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 173
Flag/option editor  2005, QNX Software Systems

Flag/Option Editor
Flags
Pt_SET
Pt_AUTOHIGHLIGHT
Pt_TOGGLE
Pt_SELECTABLE
Pt_SELECT_NOREDRAW
Pt_GHOST
Pt_HIGHLIGHTED
Pt_ETCH_HIGHLIGHT

Done Apply Default Cancel

Flag/Option Editor.

Flag resources
If you click on a flag resource, this editor lets you make multiple
selections from the displayed list.
To edit a flag list:

1 Select (or deselect) the flags you want. Since each flag is a
separate toggle, you can select any number of flags or leave
them all unselected.
2 Apply your changes. The widget changes to reflect the new
flags.

Option list resources


If you click on a resource that can have only one value, the flag/option
editor lets you make only one selection from the displayed list.
To choose an option from a list:

174 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Font editor

1 Click on the option. The previously selected option is


deselected.

2 Apply your changes. The widget changes to reflect the new


option.

For a description of the standard editor buttons at the bottom of the


editor, see the “Editing widget resources” section.

Font editor
Whenever you select any font resource in the Control Panel you’ll see
the font editor:

Font Editor
Font

Helvetica

12 Bold It alic A/A


A/A

AaBbCcXxYyZ z

Done Apply Default Cancel

Font Editor.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 175
List editor  2005, QNX Software Systems

Control Function
Typeface field Lets you view or change the typeface of the
widget. Just click on this field or its adjacent
menu button, then choose from the displayed list
of typefaces.
Point size field Lets you view or change the point size. Works
just like the typeface field.
Bold Toggles the font to bold, if available for the
current typeface and size.
Italic Toggles the font to italic, if available for the
current typeface and size.
A/A Anti-Aliased. This smooths the font edges to
make the font look nicer. A/A is available only
for scalable fonts such as Swiss or Dutch.

☞ If a typeface doesn’t support bold or italic at a given type size, the


corresponding toggle will dim or become unselectable.

For a description of the standard editor buttons at the bottom of the


editor, see the “Editing widget resources” section.

List editor
Widgets such as PtList provide a list of text-based items. To edit the
list, you use PhAB’s list editor.
To open the editor and add the first item:

1 Select the widget, then click on the appropriate resource in the


Control Panel (usually “List of Items”). You’ll see the editor:

176 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems List editor

List Editor

List of Items
Insert After

Insert Before

Modify

Delete

Done Apply Default Cancel

List Editor.

2 Click on the text field near the bottom of the dialog, then type
the text you want.

☞ If you need to type characters that don’t appear on your keyboard, you
can use the compose sequences listed in the International Character
Support chapter of the Photon User’s Guide.

3 Press Enter or click on Insert After.

4 Click on Apply or Done.

To add more items to the list:

1 Click on an existing item, then click on Insert After or Insert


Before. You’ll see a new item added to the list.

2 Using the text field, edit the new item’s text.

3 Click on Modify, then click on Apply or Done.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 177
Number editor  2005, QNX Software Systems

☞ You can’t create blank lines within the list of items.

Editing existing list items


To edit an existing item:

1 Click on the item.

2 Edit the item’s text.

3 Click on Modify, then click on Apply or Done.

☞ For text-editing shortcuts, see the “Text editor” section.

Deleting list items


To delete an item:

1 Click on the item, then click on Delete.

2 Click on Apply or Done.

For a description of the standard editor buttons at the bottom of the


editor, see the “Editing widget resources” section.

Number editor
Whenever you select any resource that’s specified as a number you’ll
see the number editor:

178 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Text editor

Number Editor

Border Width

Done Apply Default Cancel

Number Editor.

To change the value that the editor displays, you can:

¯ Use the text-editing techniques described in the Text editor section.


Or
¯ Click on the editor’s increase/decrease buttons.

For a description of the standard editor buttons at the bottom of the


editor, see the “Editing widget resources” section.

Text editor
Whenever you click on a single-line text resource in the Control Panel
(e.g. the Text String resource for PtText), you’ll see the text editor:

Text Editor
Text String

Text String

Done Apply Default Cancel

Text Editor.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 179
Multiline text editor  2005, QNX Software Systems

In order to: Do this:


Delete the character before the Press Backspace
text cursor
Delete the character after the Press Del
cursor
Delete several characters all at Drag the pointer across the
once characters, then press Del
Delete the entire line Press Ctrl – U
“Jump” the cursor to any Click on that position
position in the line
Move the cursor character by Press ← or →
character
Move the cursor to the start or Press Home or End
end of the line
Process a text change Press Enter, or click on Done or
Apply

☞ If you need to type international characters that don’t appear on your


keyboard, you can use the compose sequences listed in the
International Character Support chapter of the Photon User’s Guide.

To edit widgets that support multiline text, see the “Multiline text
editor” section.
For a description of the standard editor buttons at the bottom of the
editor, see the “Editing widget resources” section.

Multiline text editor


When you select any multiline text resource — such as the Text String
resource of a PtLabel or PtMultiText widget — you’ll see the
multiline text editor:

180 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Multiline text editor

Multi- Line Text Editor

Button Text

Help

Done Apply Default Cancel

Multiline Text Editor.

In order to: Do this:


Enter a new line of text Press Enter
Delete the character before the Press Backspace
text cursor
Delete the character after the Press Del
cursor
Delete several characters or Drag the pointer across the
lines all at once characters, then press Del
Delete the current line Press Ctrl – U
“Jump” the cursor to any Click on that position
position in a line
Move the cursor character by Press ← or →
character
Move the cursor to the start or Press Home or End
end of a line

continued. . .

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 181
Function editor  2005, QNX Software Systems

In order to: Do this:


Move the cursor to the start or Press Ctrl – Home or Ctrl – End
end of the text string
Apply your changes and Press Ctrl – Enter
dismiss the editor

☞ If you need to type characters that don’t appear on your keyboard, you
can use the compose sequences listed in the International Character
Support chapter of the Photon User’s Guide.

For a description of the standard editor buttons at the bottom of the


editor, see the “Editing widget resources” section.

Function editor
When you select a function resource, such as the Draw Function
(Pt ARG RAW DRAW F) resource of a PtRaw widget, you’ll see the
Function editor:

Function Editor
Pt_ARG_RAW_DRAW_F

my_drawing_fn

Done Apply Default Cancel

Function Editor.

Type the name of the function — see “Function names and filenames”
in the Working with Code chapter. You can edit the function by
clicking the button to the right of the text field.
For a description of the standard editor buttons at the bottom of the
editor, see the “Editing widget resources” section.

182 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Callbacks

Callbacks
Callbacks form the link between your application interface and your
application code. For example, let’s say you want your application to
perform an action when the user selects a certain button. In that case,
you would attach a callback function to that button’s Activate
callback. When the user selects the button, the widget invokes the
callback function, and your application takes the appropriate action in
the callback code.
Almost all widgets support several types of callbacks. These
callbacks can be specific to the widget or inherited from its parent
classes. Some of these types (defined in the PtBasic widget) are
defined in the following table:

Type Resource Typically invoked when the user:


Activate Pt CB ACTIVATE Presses and releases the left mouse
button
Arm Pt CB ARM Presses the left mouse button
Disarm Pt CB DISARM Releases the left mouse button
Repeat Pt CB REPEAT Holds down the left mouse button
Menu Pt CB MENU Presses the right mouse button

For more information about these callbacks, see the Widget Reference.
If you’re interested in using Pt CB MENU to display a menu module,
see the Accessing PhAB Modules from Code chapter.
All Photon widgets inherit two other types of callbacks:

hotkey callbacks
link callback code to a key or keychord. When the application
window gets focus, the hotkeys will become active. Pressing
one will invoke the appropriate hotkey link callback.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 183
Callbacks  2005, QNX Software Systems

raw-event callbacks or event handlers


link callbacks directly to Photon events

In the development environments for most windowing systems, you


can attach only callback code functions to a widget’s callbacks. But
whenever you use PhAB to create a callback, you can go one step
further and attach windows, dialogs, menus, and much more. As we
mentioned earlier, this extended functionality is provided by PhAB’s
special form of callback, called the link callback.
Link callbacks also let you add functionality that isn’t available when
you attach callbacks “by hand.” For example, if you link a dialog to a
button widget, you can specify where the dialog will appear. You can
also specify a setup function that will be automatically called before
the dialog is realized, after the dialog is realized, or both.
PhAB provides two general categories of link callbacks:

module-type link callbacks


let you attach an application module to any widget callback.
PhAB provides the following categories of module-type link
callbacks:
¯ Dialog
¯ Window
¯ Menu
¯ Picture
¯ Other
For more information, see “Module callbacks” later in this
chapter.
code-type link callbacks
let you run a code function when the widget’s callback is
invoked. PhAB provides the following categories of code-type
link callbacks:
¯ Code

184 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Editing callbacks

¯ Done
¯ Cancel
The Done and Cancel types provide an additional feature:
they’ll automatically close or destroy the widget’s parent
module after the callback function is called. You’ll find these
types useful for creating any button that closes a dialog window.

A Done callback in the base window exits the application. A Cancel


☞ callback in the base window closes the application’s windows but
doesn’t exit the application.
For more information, see “Code callbacks” later in this chapter.

Editing callbacks
The callback editor lets you add, change, delete, or view a widget’s
list of callbacks.
To add a callback to a command item or toggle item in a menu, see
the “Menu modules” section of the Working with Modules chapter.

☞ If you’re adding a link callback to a widget, the widget’s instance


name must be unique. If PhAB tells you the name isn’t unique, use
the Control Panel’s Widget Instance Name field to edit the name.

To open the callback editor and edit a widget’s list of callbacks:

1 Select the widget, then switch the Control Panel to Callbacks


mode.

2 Choose the callback type from the widget’s callback list. (For
example, to add an Pt CB ACTIVATE callback, click on
Activate.)

Here’s a sample callback-editor session, with information filled in for


a module-type link callback:

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 185
Editing callbacks  2005, QNX Software Systems

Widget: base_helpbut - [Activ ate Callbacks]

Callbacks Link to Callback/Module Info Module Ty pes


Dialog: about_dlg Dialog
< NEW > Window
Name: about_dlg
M enu
Location: Center Screen (0,0)
Other
Setup Function: aboutdlg_setup Code Ty pes
Code
Called: Pre- Realize Post- Realize
Done
Cancel
Actions
Apply
Reset
Remov e

Sav e
Restore

Done Cancel

Callback Editor.

1 To add a new callback, click on <NEW>. To edit an existing


callback, click on that callback in the Callbacks list.

2 If you’re adding a new callback, choose the type of callback


you want to add. To do this, choose from from either “Module
Types” or “Code Types.”

3 Fill in the information in the “Link to Callback/Module Info”


section. The fields in this section depend on the type of
callback chosen. For more information, see the sections in this
chapter on specifying:
¯ module callbacks
¯ code callbacks
¯ hotkey callbacks
¯ raw-event callbacks

4 After you’ve added or edited any callback, click on the


appropriate button:

186 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Module callbacks

¯ Apply — Apply any changes; be sure to do this before you


start working on other callbacks.
¯ Reset — Restore the callback information to the original
values.
¯ Remove — Delete the callback from the callback list.

Module callbacks
A module-type link callback can be used to connect a widget to a
module. For example, selecting a button could create a module.

☞ You can use an internal link to create the module in your application’s
code. For more information, see the Accessing PhAB Modules from
Code chapter.

Depending on the kind of module-type link callback you’re creating,


PhAB’s callback editor displays some or all of these fields:

Name: aboutdlg

Location: Center Screen (0,0)

Setup Function: aboutdlg_setup

Called: Pre- Realize Post- Realize

Callback Editor fields for module-type link callbacks.

Name The name of the module. If you click on the icon next to
this field, you’ll see a list of existing modules. Either
choose from this list or enter the name of a module that
doesn’t exist (PhAB will create the module for you
when you add the callback).

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 187
Module callbacks  2005, QNX Software Systems

If you wish to create a link callback to an “Other”


module, you must create the module first, then bring up
the callback editor.

Location Lets you specify where the module will display. By


default, a menu module is located below the widget that
invokes it. For all other modules, the default location is
determined by the Window Manager. For more info, see
the “Location dialog” section in the Working with
Modules chapter.
Setup Function
Lets you specify a function that can be called at two
different times (as specified by the Called field):
¯ before the module is displayed (prerealize)
¯ after the module is displayed (postrealize)
You can specify only one setup function — the PhAB
API calls the same function for both pre- and
postrealization of the module. To distinguish which pass
is being invoked, check the PhAB reason code.
Click on the icon beside the Setup Function field to edit
the function.
Hotkey — (hotkey callbacks only)
The keyboard key and modifier (such as Alt or Ctrl) that
will trigger the callback. See the section “Specifying
hotkey callbacks.”

Event Mask — (raw-event callbacks/event handlers only)


Lets you specify which Photon events the widget will be
sensitive to. See the section “Specifying raw-event
callbacks.”

188 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Code callbacks

Prerealize setup function


The prerealize setup function lets you preset a module. For example,
let’s say your application needs to “fill in the blanks” of a dialog
before displaying that dialog. In the setup function, you would use
PhAB-generated manifest names to preset the resources of the
dialog’s various widgets.
After the setup function runs, it returns Pt CONTINUE. The dialog is
then realized and displayed on the screen, using all the preset values.

Postrealize setup function


The postrealize function works much like the prerealize function,
except that it’s called after the dialog is displayed on the screen. You
typically use this type of function when you need to update the
module after it’s become visible. PhAB’s code-generation dialog
provides a good example. It displays on the screen and then, using a
postrealize function, updates a progress bar continuously as the
application code is generated.

☞ The setup function for a menu module is called only before the menu
is displayed. For most applications, you would use this function to set
the initial states of the menu items. For example, you could use it to
disable certain menu items before the menu is displayed.

Setup functions are stored in stub files


When you specify a setup function, PhAB generates a stub function;
for information on specifying the language (C or C++) and the
filename, see “Function names and filenames” in the Working with
Code chapter.

Code callbacks
When you’re creating a code-type link callback, the callback editor
asks you to specify the following:

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 189
Hotkey callbacks  2005, QNX Software Systems

Function This is the function that’s called when the widget


invokes the callback. For the Done and Cancel types,
this function is optional, so you can attach the callback
just to close the module.

There’s no real difference between Done and Cancel — they simply


☞ provide different reason codes in the callback. For example, let’s say
you have a dialog with a Done button and a Cancel button. If you
attach a Done-type callback to the Done button and a Cancel-type
callback to the Cancel button, you could use the same code function
in both and just look at the reason code to determine which button the
user selected.
Hotkey — (Hotkey callbacks only)
The keyboard key and modifier (such as Alt or Ctrl) that
will trigger the callback. See the section “Specifying
hotkey callbacks.”

Event Mask — (raw-event callbacks/event handlers only)


Lets you specify which Photon events the widget will
be sensitive to. See the section “Specifying raw-event
callbacks.”

Callback functions are stored in stub files


When you specify a callback function, PhAB generates a stub
function; for information on specifying the language (C or C++) and
the filename, see “Function names and filenames” in the Working
with Code chapter.

Hotkey callbacks
Widgets support hotkey callbacks. These callbacks let you attach
keyboard keys to specific callback functions. When the application
window gets focus, the hotkeys become active. Pressing one invokes
the appropriate hotkey link callback.

190 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Hotkey callbacks

Hotkeys — the basics


Here’s some basic information about hotkeys:

¯ Hotkeys are a combination of a character key and a modifier key


(Alt, Shift or Ctrl). Most of the time, Alt is used for hotkeys.

¯ You can use a modifier on its own as a hotkey, but it’s probably not
a good idea.

¯ A hotkey isn’t invoked if any ancestor of the widget that owns it is


blocked.

¯ A hotkey is processed after the widgets have been given the key
event. If a widget consumes the event, no hotkey callback is called.
So when a text field has focus, the Enter key, arrow keys, Space,
and all displayable characters won’t work as hotkeys because the
widget consumes those events. This is usually the desired behavior
(consider editing in an application which has hotkeys defined for
all the arrow keys).
You can force the hotkey processing to be done first by setting
Pt HOTKEYS FIRST in the Pt ARG CONTAINER FLAGS resource
of the container widget (window, pane, . . . ) that contains the
widgets that would normally consume your would-be hotkey
events. Setting this flag on the window guarantees all hotkey
processing is done before any widgets get the key event. For more
information, see “Processing hotkeys,” below.

¯ Widgets must be selectable for their hotkeys to be active (with the


exception of disjoint widgets such as windows and menus). Make
sure the widget’s Pt ARG FLAGS has Pt SELECTABLE and
Pt GETS FOCUS set.
If the widget isn’t normally selectable and you don’t want its
appearance to change when selected, you’ll also want to set the
Pt SELECT NOREDRAW widget flag.

¯ Often it doesn’t matter which widget a callback is connected to. In


those cases, just attach the hotkey to the window.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 191
Hotkey callbacks  2005, QNX Software Systems

Specifying the hotkey label


Setting up a hotkey isn’t enough — you need to tell your user about
it! You should display a hotkey label in the widget invoked by the
hotkey:

¯ For most widgets, edit the Accelerator Key


(Pt ARG ACCEL KEY) resource. Specify the character in the
widget’s label that you want underlined. You can’t include any
modifier keys in the label.

¯ For menu items, the underlined character is the shortcut that you
can use to select an item when the menu’s displayed. The hotkey
label is displayed separately, to the right of the menu item’s label.
Specify the hotkey (including the modifier keys) in the menu
editor’s Accel Text field.

Specifying the callback


In PhAB, each widget’s callback list displays an entry called
“Hotkey” or Pt CB HOTKEY that you use to define hotkeys. Before
you define the hotkey, you need to determine where to do so. Where
you define the hotkey callback depends on:

¯ where you want a module (such as a menu) to appear

¯ what widget you need in the callback function

¯ where the user is going to type the hotkey

Where you want a module to appear


When you define the hotkey, you can specify where the module is to
appear. For example, if the hotkey is meant to display the menu
module associated with a PtMenuButton widget in your window’s
PtMenuBar, define the hotkey in the menu button. Use the Location
dialog to have the menu appear under the menu button.

192 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Hotkey callbacks

What widget you need in the callback function


The widget that owns the callback is the one passed to the callback
function.

Where the user is going to type the hotkey


For example, if the hotkey is an accelerator for a menu item, add the
hotkey to the window in which the menu is used, not to the menu
module.

☞ ¯ The hotkeys in a given module should be unique. If you define the


same hotkey more than once, the last one is used.

¯ If you’re developing a multilingual application, you’ll need to


choose hotkeys carefully so they’ll be relevant in each language, or
you’ll need a different set of hotkeys for each language. See the
International Language Support chapter for more information.

When you select the Pt CB HOTKEY callback, the callback editor


pops up with a Hotkey field in the link-information area:

HotKey: 0x66 Ctrl Shift Alt

Hotkey field in the Callback Editor.

You must fill in the Hotkey field when creating a hotkey callback.
There are two ways to set up the hotkey: one easy, the other not so
easy.

¯ the not-so-easy way — you can type the hotkey value, in hex, in
the Hotkey field. To find the value for the keycap you want to use,
see the header file <photon/PkKeyDef.h>, and search for the
name of the keycap, prefixed by Pk .

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 193
Hotkey callbacks  2005, QNX Software Systems


Use lowercase letters for hotkeys; uppercase letters won’t work. For
example, for a hotkey Alt – F, look up the hex value for Pk f, not
Pk F.
The field also has 3 toggle buttons — Ctrl, Shift, and Alt — to let
you specify modifiers for the hotkey value.
¯ the easy way — press the button to the right of the Alt toggle
button, then press the keychord you want to use for the hotkey.
PhAB automatically determines the key and modifiers you
pressed.

Processing hotkeys
Here’s how a hotkey works:
¯ When a key event arrives at a window, the window passes the
event to its child widgets.
¯ If a child consumes the event, nothing further happens.
¯ Otherwise, the event is checked against the window’s list of
hotkeys. If the hotkey is found, its callback is invoked.
¯ If the hotkey isn’t found, the parent window’s hotkey list is
searched, and so on up the hierarchy of windows.
The Pt ARG CONTAINER FLAGS resource of container-class
widgets includes some flags that affect the processing of hotkeys:

Pt HOTKEY TERMINATOR
Prevent the hotkey search from going up to the parent container.

The Pt HOTKEY TERMINATOR flag works only if it’s set in a


disjoint container-class widget.
Pt HOTKEYS FIRST
Process key events that reach this container as hotkeys before
passing them to the container’s children. If the event is a hotkey,
it’s consumed, so it isn’t passed to the children.

194 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Hotkey callbacks

Disabling hotkeys
Giving the user a visual indication that a hotkey is disabled is
different from actually disabling the hotkey.
To give the visual indication, use the technique appropriate to the
widget:

¯ If the hotkey is associated with a button, set the Pt GHOST flag and
remove the Pt SELECTABLE and Pt GETS FOCUS flags in the
button’s Pt ARG FLAGS resource.

¯ If the hotkey is associated with a menu item created in PhAB, call


ApModifyItemState().

¯ ...

To disable the hotkey, use one of the following techniques:

¯ Don’t disable the hotkey. Instead, as the first thing you do in your
hotkey’s callback code, check to see if anything should be done. If
not, just return from the callback. For example, if the hotkey
callback is the one for pasting text, check to see if there’s anything
to paste. If there isn’t, simply return.
Or

¯ With the exception of disjoint widgets, if the widget that the


hotkey callback is attached to isn’t selectable, the hotkey will be
treated as if it didn’t exist. For a widget to be selectable, the
Pt SELECTABLE flag must be set in the Pt ARG FLAGS resource.
One good reason for this approach is that it works even if your
application has the same hotkey defined in more than one window.
For example, we might have an Edit menu in the base window and
an Erase button in a child window, both with Alt – E as a hotkey. If
the child window currently has focus and the user presses Alt – E,
the child window’s Erase button callback is called.
Now, if we disable the Erase button in the child window, we would
want Alt – E to cause the base window’s Edit menu to appear. In
this scenario, as long as the Erase button is selectable, its callback

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 195
Raw-event callbacks  2005, QNX Software Systems

would be called. So we simply make the Erase button unselectable.


Now when the user presses Alt – E, the base window’s Edit menu
appears, even though the child window still has focus.
Or

¯ You could call PtRemoveHotkeyHandler() to remove the hotkey


and later call PtAddHotkeyHandler() to enable it again.

Raw-event callbacks
Raw-event callbacks (also called event handlers) let you respond
directly to Photon events. PhAB lets you attach raw callbacks to any
widget. A raw callback is like a standard widget callback, but with the
addition of an event mask. Using this mask, you can choose which
events you’ll receive.
You’ll find them particularly useful for getting the Ph EV DRAG
events for a particular window. For more information on dragging, see
“Dragging” in the Events chapter.

☞ The Pt CB RAW callbacks defined for PtWidget are invoked after


the widget has processed the event, and then only for events that the
widget doesn’t consume.
In contrast, the Pt CB FILTER callbacks defined for PtContainer
are invoked before the event is passed to the child widget.

To attach a raw callback:

1 Select the widget, then switch the Control Panel to Callbacks


mode.

2 Click on the Pt CB RAW or Raw Event resource to open the


callback editor.

3 The editor pops up with an Event Mask field in the link


information area:

196 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
 2005, QNX Software Systems Raw-event callbacks

Event Mask: 0x0

Event Mask field in the Callback Editor.

The Event Mask field lets you specify which Photon events you
want the widget to be sensitive to. When any of those low-level
events occur, the widget will invoke the callback.
Click on the icon next to this field to open the event selector.

4 Select the events you want the widget to be sensitive to, then
close the selector.

☞ When you attach raw events to a widget, the widget library creates a
region, if necessary, that will pick up specific events for the widget.
This increases the number of regions the Photon Manager must
manage and, as a result, may reduce performance.
For that reason, use raw events only when you have to do something
that can’t be done using standard widget callbacks. If you do use raw
events, consider using them only on window widgets, which already
have regions.

For more info, see the event types described for the PhEvent t
structure in the Photon Library Reference.

September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 197
Chapter 8
Geometry Management

In this chapter. . .
Container widgets 201
Geometry negotiation 201
Absolute positioning 207
Aligning widgets using groups 208
Constraint management using anchors 213
Enforcing position or size constraints without anchors 218

September 20, 2005 Chapter 8 ¯ Geometry Management 199


 2005, QNX Software Systems Container widgets

This chapter discusses how to set up or fine-tune your widgets’


geometry.

Container widgets
A container widget is a child of the PtContainer widget class.
Container widgets are the only widgets that can have children. Any
widget that doesn’t have a window of its own is always rendered
within the boundaries of its parent. Only widgets belonging to a
subclass of the PtWindow widget class get a window of their own.
Container widgets are responsible for performing geometry
management. A container widget’s primary responsibility is to
position each child and size itself appropriately to accommodate all
its children at their desired locations. The container may also impose
size constraints on its children (for example, forcing them all to be the
same size). The container must also constrain the children so that they
don’t appear outside the container’s boundaries. This is normally
done by clipping the child.
To understand how different containers handle geometry
management, it’s important to understand the geometry of a widget.
See “Widget Geometry” in the Introduction to this guide.

Geometry negotiation
When a widget is realized, a geometry negotiation process is initiated
in all the widgets in the widget family hierarchy. Each child of the
widget is given the opportunity to calculate its size. This ripples down
through all the widgets in the family, resulting in a calculation of the
size of each of the descendants first.
Once each child has calculated its desired size, the parent widget may
attempt to determine the layout for its children. The layout that the
widget performs depends on:

¯ the widget’s layout policy

¯ any size that has been set for the widget

September 20, 2005 Chapter 8 ¯ Geometry Management 201


Geometry negotiation  2005, QNX Software Systems

¯ the dimensions and desired position of each of the children.

If the application has specified a size for the widget, then it may
choose to lay out the children using only that available space. This is
influenced by the resize policy set for the widget. The
Pt ARG RESIZE FLAGS resource is a set of flags that determine the
resizing policy for the widget. The flags specify a separate resizing
policy for the width and height of the widget. If no policy is specified
for either dimension, the widget won’t attempt to resize itself in that
dimension when performing the layout. Any other resize policy will
allow the widget to grow in that dimension to accommodate its
children. Resize policies are described in greater detail in the “Resize
policy” section.
If the widget doesn’t have a predetermined size, it will try to size
itself to accommodate all the children using the appropriate layout
policy. It does so by first attempting to determine a correct layout and
then determining the space required to accommodate it.
The layout process determines the desired location of each child. The
layout policy used by the widget controls how the layout will attempt
to position the children relative to each other. It must take into account
the dimensions of the children. The container is responsible for fixing
the position of each child, so the layout policy may choose whether or
not to take into account the position attributes of the children.
In performing the layout, the widget may also take the resize policy
into account. Based on this policy, it determines whether it must
adjust its width or height, or change the layout to account for space
restrictions. The widget tries to choose a layout that best meets the
constraints imposed by any size restrictions and by the layout policy.
After determining the desired position of each of its children, the
widget calculates the width and height it needs to accommodate the
children at these locations. It changes its dimensions, if necessary, to
fit each of the children at the desired position. If this isn’t possible
because the resize policy doesn’t allow it, the widget recalculates the
positions to fit the children within the space available.

202 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Geometry negotiation

Once the layout is successfully established, the widget sets the


position of each of the children by altering the child’s position
attribute.

Resize policy
Any change to a widget that may affect the amount of space required
to display its contents can result in the widget’s resizing itself to fit its
contents. This is governed by the resize policy enforced by the widget.
The resize policy affects both basic widgets and containers. A
container checks its resize policy when it lays out its children to
determine whether it should resize itself to accommodate all the
children at their desired locations. Through the geometry negotiation
process, this effect is propagated up the widget family until the size of
the window widget is determined.
The Pt ARG RESIZE FLAGS resource controls the resize policy. This
resource consists of a separate set of flags for the width and the
height. The values of the flags determine the conditions under which
the widget will recalculate the corresponding dimension. The values
are checked whenever the widget is realized or its contents change.
The resize flags are as follows:

Pt RESIZE X ALWAYS
Recalculates the widget’s size whenever the value of the x
dimension changes. This will grow or shrink the widget as its
contents change.
For example, the following figure shows a button with the
Pt RESIZE X ALWAYS flag set as the label changes from Hello
to Hello, world to Hi.

September 20, 2005 Chapter 8 ¯ Geometry Management 203


Geometry negotiation  2005, QNX Software Systems

Pt RESIZE Y ALWAYS
Recalculates the widget’s size whenever the value of the y
dimension changes. The widget grows or shrinks vertically as
its contents change.
Pt RESIZE XY ALWAYS
Recalculates the widget’s size whenever the value of the x or y
dimension changes. This will grow or shrink the widget as its
contents change.

The Pt RESIZE XY ALWAYS flag isn’t defined in PhAB. It’s provided



for your convenience when setting resize flags from your code.
Pt RESIZE X AS REQUIRED
Recalculates the the widget’s size whenever the x dimension
changes and will not fit within the current space available.
For example, the following figure shows a button with the
Pt RESIZE X AS REQUIRED flag set as the label changes from
Hello to Hello, world to Hi.

Pt RESIZE Y AS REQUIRED
Recalculates the the widget’s size whenever the y dimension
changes and will not fit within the current space available.
Pt RESIZE XY AS REQUIRED
Recalculates the the widget’s size whenever the x or y
dimension changes and will not fit within the current space
available.

The Pt RESIZE XY AS REQUIRED flag isn’t defined in PhAB. It’s



provided for your convenience when setting resize flags from your
code.

These flags may also be modified by the values of another set of flags,
namely:

204 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Geometry negotiation

¯ Pt RESIZE X INITIAL

¯ Pt RESIZE Y INITIAL

¯ Pt RESIZE XY INITIAL

☞ The Pt RESIZE XY INITIAL flag isn’t defined in PhAB. It’s provided


for your convenience when setting resize flags from your code.

If you set any of these “initial” flags, the widget doesn’t resize in
response to a change in the data — it will change its size only during
the geometry negotiation process whenever it is realized. The widget
will either make itself exactly the right size for its contents, or grow to
fit its contents if the dimensions it has at the time aren’t large enough.

☞ If none of the resize flags is set, the widget won’t try to calculate its
own dimensions, but will use whatever dimensions have been set by
the application (thereby possibly clipping the widget’s contents as a
result).
For example, the following figure shows a button with no resize flags
set as the label changes from Hello to Hello, world to Hi.

Setting the resize policy in PhAB


You can set these flags in PhAB by editing the container’s resize flags,
Pt ARG RESIZE FLAGS, as shown below:

September 20, 2005 Chapter 8 ¯ Geometry Management 205


Geometry negotiation  2005, QNX Software Systems

Flag/Option Editor
Resize Flags
Pt_RESIZ E_Y_AS_REQUIRED
Pt_RESIZ E_Y_ALWAYS
Pt_RESIZ E_Y_INITIAL
Pt_RESIZ E_X_AS_REQUIRED
Pt_RESIZ E_X_ALWAYS
Pt_RESIZ E_X_INITIAL

Done Apply Default Cancel

Setting the resize policy in your application’s code


You can also set the container’s resize flags in your code, if required,
using the method described in the Manipulating Resources in
Application Code chapter.
Bit masks are provided for controlling which bits will be set. There’s
one bit mask for each of the x and y resize policies:

¯ Pt RESIZE X BITS

¯ Pt RESIZE Y BITS

¯ Pt RESIZE XY BITS

For example, to make a container grow to fit all its children if it isn’t
large enough when it’s realized, set both the initial and required resize
flags for x and y, by setting up the argument list as follows:

PtSetArg(&arg[0], Pt ARG RESIZE FLAGS,


(Pt RESIZE XY INITIAL|Pt RESIZE XY AS REQUIRED),
Pt RESIZE X BITS|Pt RESIZE Y BITS);
PtSetResources (ABW my container, 1, args);

To set up the argument list to clear the x resize policy:

PtSetArg(&arg[0], Pt ARG RESIZE FLAGS, Pt FALSE,


Pt RESIZE X BITS);
PtSetResources (ABW my container, 1, args);

206 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Absolute positioning

There are also some constants that simplify the setting of these flags.
For example, there’s a constant representing the bitmask for setting
both the x and y flags simultaneously, and there are constants for each
flag with the x or y shift applied. All these constants are defined in the
<photon/PtWidget.h> header file.

Absolute positioning
The most basic form of layout a container can provide is to position
its children without imposing any size or positioning constraints on
them. In such a situation, a child widget is pinned to a particular
location within the container, and the container doesn’t change its
size.
A widget employing this layout policy is somewhat analogous to a
bulletin board. You can pin items to the bulletin board, and they stay
wherever they’re pinned. All container widgets can perform absolute
positioning.
The easiest way to position and size each child is to use the mouse in
PhAB.
To position each of the children from your application’s code, you
must set the Pt ARG POS resource for each child. If the widgets must
be a consistent or predetermined size, you must also set the
Pt ARG DIM resource for each child. The position you specify is
relative to the upper left corner of the parent’s canvas, so you can
disregard the parent’s margins when positioning children.
By default, all widgets that perform absolute positioning use a resize
policy of Pt AS REQUIRED and Pt INITIAL. In other words, the
container’s initial size is chosen when it’s realized. The container is
made large enough to fit all the children at their specified locations,
given their size after they’ve been realized.
The simplest way to do absolute positioning is to place and position
widgets within the main PtWindow widget of the application. If you
need to create a container widget that does absolute positioning as
part of another container, you can use a PtPane widget.

September 20, 2005 Chapter 8 ¯ Geometry Management 207


Aligning widgets using groups  2005, QNX Software Systems

Aligning widgets using groups


PtGroup widgets are container-class widgets that can manage the
geometry of their children. You’ll find them useful for aligning
widgets horizontally, vertically, or in a matrix. They also have the
unique ability to stretch child widgets.
PhAB extends the usefulness of this widget class by turning it into an
action-oriented “Group” command. Using this command, you can
select several widgets within a module and group them together to
form a single group widget. If you try to select any widget in the
group by clicking on it, the entire group is selected instead.
When you select a group, the Control Panel shows the resources
available to the PtGroup widget class. These include resources that
allow you to align the widgets inside the group and to set up
exclusive-selection behavior.
The PtGroup widget can be used to arrange a number of widgets in a
row, column, or matrix. Several resources are used to control this, and
they’re interpreted slightly differently depending on the desired
arrangement of the children.

Joining widgets into a group


To join widgets into a group:

1 Select the widgets using either a bounding box or the “Shift and
click” method (as described in the Creating Widgets in PhAB
chapter).
You should use “Shift – click” if you plan to align the widgets
in order using the Orientation resource. The first widget you
select will become first within the group. If order isn’t
important or alignment isn’t required, the bounding box method
will work just fine.

2 Do one of the following:


¯ choose Group Together from the Edit menu
¯ press Ctrl – G

208 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Aligning widgets using groups

¯ click on the Group icon in the speedbar:

PhAB will group the widgets and select the group.

Accessing widgets in a group


Although PhAB treats a group as a single widget, you can still access
any of the individual widgets that make up the group. To do this, use
the Control Panel’s next and previous buttons or module tree. For
more info, see “Selecting widgets” in the Creating Widgets in PhAB
chapter.

Aligning widgets horizontally or vertically


The orientation resource, Pt ARG GROUP ORIENTATION, controls
whether the group widget’s children are arranged as rows or columns.
The default value, Pt GROUP VERTICAL, causes the children to be
arranged vertically. A value of Pt GROUP HORIZONTAL causes the
children to be arranged horizontally.
You can control the amount of space to be left between the widgets
arranged in the group widget by using the
Pt ARG GROUP SPACING resource. The value of the resource gives
the number of pixels to be left between widgets.
The following example shows how several children are laid out if the
default vertical orientation is used and a space of five pixels is left
between children:

One

Two

Another

If the orientation is changed to horizontal, the group appears like this:

September 20, 2005 Chapter 8 ¯ Geometry Management 209


Aligning widgets using groups  2005, QNX Software Systems

One Two Another

When first realized, the group widget initially sizes itself to be large
enough to hold all the children after they’ve been arranged.

Aligning widgets in rows and columns


The group widget may also be used to layout children in both rows
and columns for creating tables or spreadsheets by setting the value of
Pt ARG GROUP ROWS COLS resource to some value other than
one.
The interpretation of this resource depends on the orientation:

¯ When the orientation is vertical, this resource specifies the number


of rows to be displayed; the number of columns is calculated based
on the number of widgets to yield the correct number of rows.

One Another

Two

¯ Otherwise, the value specifies the number of columns, and the


widget calculates the number of rows.

One Two

Another

The last row or column may have fewer widgets than the others.
When the elements of a group are laid out in rows and columns, the
widgets themselves may either be tightly packed or they may be
spaced out equally as rows and/or columns. This is controlled by the
Pt ARG GROUP SPACING resource.

210 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Aligning widgets using groups

Using the Group flags


The PtGroup widget includes a set of flags,
Pt ARG GROUP FLAGS, that can be used to control how the child
widgets can be selected, sized, and stretched:

Pt GROUP EXCLUSIVE
Allow only one child to be set at a time. This flag can be used to
make a group of toggle buttons into radio buttons (that is, a set
of mutually exclusive choices).
Pt GROUP EQUAL SIZE
Lay out the widgets in a grid, using a cell size chosen by the
group based on the width of the widest child and the height of
the tallest child. The dimensions of all the children are set to
this size when they’re laid out.
Pt GROUP EQUAL SIZE HORIZONTAL
Make all the children the width of the widest one.
Pt GROUP EQUAL SIZE VERTICAL
Make all the children the height of the tallest one.
Pt GROUP NO SELECT ALLOWED
Set this flag for an exclusive group if it’s valid not to have any
child set. The user can unselect the currently set child by
clicking on it again.
Pt GROUP NO KEYS
Don’t allow the user to move inside the group by pressing the
arrow keys.
Pt GROUP NO KEY WRAP HORIZONTAL
Don’t wrap around to the other side of the group when using the
left and right arrow keys.
Pt GROUP NO KEY WRAP VERTICAL
Don’t wrap around to the top or bottom of the group when
using the up and down arrow keys.

September 20, 2005 Chapter 8 ¯ Geometry Management 211


Aligning widgets using groups  2005, QNX Software Systems

Pt GROUP STRETCH VERTICAL


Stretch the bottom row of widgets as the group expands.

One Another

Two

Pt GROUP STRETCH HORIZONTAL


Stretch the right column of widgets as the group expands.

One Another

Two

Pt GROUP STRETCH FILL


Stretch the last widget(s) to fill the available space in the
direction indicated by the orientation.

One
Another
Two

☞ Don’t set the Pt GROUP EQUAL SIZE ... and Pt GROUP STRETCH ...
flags for the same direction — the group will expand every time its
extent is calculated.

For more information, see the description of the PtGroup widget in


the Widget Reference.

212 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Constraint management using anchors

Splitting apart a group


To split a group into its individual widgets:

1 Select the group.

2 Do one of the following:


¯ choose Split Apart from the Edit menu
¯ press Ctrl – P
¯ click on the Split icon in the speedbar:

PhAB will split apart the widgets and remove the PtGroup
container.

Constraint management using anchors


Here’s a common layout situation that’s not handled by any of the
layout policies we’ve examined. Suppose a container is divided into a
number of panes that have constraints on their size and position.
Normally, we don’t want the panes to overlap, and we want control
over how the panes are resized if the container itself grows or shrinks.
A constraint mechanism provides this control.
Anchors are provided as a constraint mechanism on the position and
size of a scroll area, group widget, or pane widget used as a pane
within another container. The position attribute and the anchors of
each of the children will always be used to determine their positions.
An anchor may be specified for any side of a child widget. The
anchor is attached to one of the sides of the parent. It maintains the
corresponding side of the child at a fixed distance, the anchor offset
from the anchoring side of the parent. The anchor offset may also be
expressed as a proportion of the canvas width or height of the parent.
Any time the parent is resized, the child’s position (and possibly size)
is altered to maintain this relationship. If any side of the child is not
anchored to the parent, it’s allowed to float freely.

September 20, 2005 Chapter 8 ¯ Geometry Management 213


Constraint management using anchors  2005, QNX Software Systems

☞ When using PhAB, you don’t specify anchor offsets. Instead you
position the widgets at the desired offset by setting the position
(Pt ARG POS) and dimension (Pt ARG DIM) resources. PhAB
calculates the anchor offsets automatically, based on the relative sizes
and positions of the parent and the anchored child.

The width of the child widget is influenced by the anchors for its left
and right sides; the height is influenced by the anchors for the top and
bottom. If either of an opposing pair of edges is allowed to float, the
constraints will be met by altering only the position of the widget in
the corresponding dimension. This means that the widget may slide in
any of the four directions to satisfy the anchor constraints. If both
edges are anchored, the widget must be resized in that dimension as
well.

Anchor

Proportional position

Example of anchoring.

214 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Constraint management using anchors

☞ Anchor size determination takes precedence over the resize policy or


any other resize mechanism in place.

Creating an application’s main window provides a simple example of


using anchor resources. The window commonly has at least two parts
to it: the menu bar and the work area. If we consider an application
that has a group widget for the work area, we can identify the types of
anchors necessary to make it resize correctly in response to a change
in the size of the window widget.
Each edge of the work area is anchored to the corresponding edge of
the window. The left and top anchor offsets are set to be the same as
the position attribute for the widget. This must be calculated to sit
below the menu bar. The dimensions of the widget are set to the
desired amount of work space.
When realized, the window positions the work area at the location
specified by its position attribute. The window’s size is set to be large
enough to contain the work area.
If the window is resized, the width and height of the work area are
resized accordingly, since all the edges are anchored. If the anchor
offsets were specified correctly, the position of the widget won’t be
altered.
We don’t have to do anything for the menu bar, because it’s
automatically anchored to the top and sides of the window.

Anchor resources
The Pt ARG ANCHOR FLAGS resource controls the anchor
attachments. Within the container flags, there are three flags
associated with each edge of the widget for anchoring purposes.
The three flags available for each edge allow that edge to be anchored
in one of three possible ways:

¯ anchored to the corresponding edge of its parent

¯ anchored to the opposite edge of its parent

September 20, 2005 Chapter 8 ¯ Geometry Management 215


Constraint management using anchors  2005, QNX Software Systems

¯ given a specified location, i.e. some proportion of the widget’s


width or height.

Each of these flags follows a consistent naming scheme:


Pt edge ANCHORED anchor
where

edge is the name of the edge to be anchored, and must be TOP,


LEFT, RIGHT, or BOTTOM.

anchor is the name of the parent edge it’s to be anchored to, or


RELATIVE for a proportional anchor.

Thus, the following flags are defined:

¯ Pt LEFT ANCHORED LEFT

¯ Pt LEFT ANCHORED RELATIVE

¯ Pt LEFT ANCHORED RIGHT

¯ Pt RIGHT ANCHORED LEFT

¯ Pt RIGHT ANCHORED RELATIVE

¯ Pt RIGHT ANCHORED RIGHT

¯ Pt TOP ANCHORED BOTTOM

¯ Pt TOP ANCHORED RELATIVE

¯ Pt TOP ANCHORED TOP

¯ Pt BOTTOM ANCHORED BOTTOM

¯ Pt BOTTOM ANCHORED RELATIVE

¯ Pt BOTTOM ANCHORED TOP

216 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Constraint management using anchors

A proportional anchor specifies the edge’s position as a percentage of


one of the parent widget’s dimensions. The left or right edges are
specified as a proportion of the parent’s width, and the top and bottom
edges are specified as a proportion of the parent’s height. The
proportion is provided by the anchor offset and is expressed in tenths
of a percentage point.

Setting anchor flags in PhAB


To set the anchor flags, click on the anchor flags
(Pt ARG ANCHOR FLAGS) resource and use PhAB’s flag editor:

Flag/Option Editor
Anchor Flags
Pt_LEFT_ANCHORED_RELATIVE
Pt_LEFT_ANCHORED_RIGHT
Pt_LEFT_ANCHORED_LEFT
Pt_RIGHT_ANCHORED_RELATIVE
Pt_RIGHT_ANCHORED_RIGHT
Pt_RIGHT_ANCHORED_LEFT
Pt_TOP_ANCHORED_RELATIVE
Pt_TOP_ANCHORED_BOTTOM

Done Apply Default Cancel

Setting anchor flags in your application’s code


You can also set these flags from your code, using the method
described in the Manipulating Resources in Application Code chapter.
For convenience, each set of flags has an associated bit mask:
¯ Pt LEFT IS ANCHORED — isolates the bits responsible for
specifying an anchor for the left edge.
¯ Pt RIGHT IS ANCHORED — isolates the bits responsible for
specifying an anchor for the right edge.
¯ Pt TOP IS ANCHORED — isolates the bits responsible for
specifying an anchor for the top edge.
¯ Pt BOTTOM IS ANCHORED — isolates the bits responsible for
specifying an anchor for the bottom edge.

September 20, 2005 Chapter 8 ¯ Geometry Management 217


Enforcing position or size constraints without anchors  2005, QNX Software Systems

So to set the left and right edge for our menu bar in the example
above, the argument list element would be initialized as follows:
PtSetArg(&arg[n], Pt ARG ANCHOR FLAGS,
Pt LEFT ANCHORED LEFT|Pt RIGHT ANCHORED RIGHT|
Pt TOP ANCHORED TOP,
Pt LEFT IS ANCHORED|Pt RIGHT IS ANCHORED|
Pt TOP IS ANCHORED);

When setting anchor flags from your application’s code, all the anchor
offsets are specified using the Pt ARG ANCHOR OFFSETS resource.
This resource takes a PhRect t as a value. The upper left corner of
the rectangle is used to specify the anchor offset for the top and left
edges of the widget, and the lower right corner of the rectangle
indicates the anchor offset for the right and bottom edges.
So, for example, to make the work area 90% of the width of the
window with equal space on either side, the left and right edges are
anchored using the following:
PhRect t offsets;
offsets.ul.x = 50;
offsets.lr.x = 950;
PtSetArg(&arg[n], Pt ARG ANCHOR FLAGS,
Pt LEFT ANCHORED RELATIVE|
Pt RIGHT ANCHORED RELATIVE,
Pt LEFT IS ANCHORED|Pt RIGHT IS ANCHORED);
PtSetArg(&arg[n+1], Pt ARG ANCHOR OFFSETS, &offsets, 0);

Enforcing position or size constraints


without anchors
If you wish to maintain more complex relationships among the
positions of children relative to the container, or relative to each other,
you must catch resize events for the container. The PtContainer
widget class provides a resize callback, Pt CB RESIZE, that you can
use for this purpose.
The cbdata member of the PtCallbackInfo t structure is a pointer
to a PtContainerCallback t structure that contains at least the
following:

218 Chapter 8 ¯ Geometry Management September 20, 2005


 2005, QNX Software Systems Enforcing position or size constraints without anchors

PhRect t old size


the former size of the container
PhRect t new size
the new size of the container

September 20, 2005 Chapter 8 ¯ Geometry Management 219


Chapter 9
Generating, Compiling, & Running
Code

In this chapter. . .
Using the Build & Run dialog 223
Generating application code 225
How application files are organized 230
Editing source 233
Compiling & linking 235
Running the application 237
Debugging 237
Including non-PhAB files in your application 239

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 221
 2005, QNX Software Systems Using the Build & Run dialog

PhAB automatically generates everything that’s required to turn your


application into a working executable, including:

¯ code to handle the user-interface portion of your application

¯ stub C and/or C++ files for application-specific callbacks,


module-setup functions, application-initialization functions, and so
on

¯ all the files required to compile and link the application —


Makefile, global header, main-line file, and prototype file.

By doing all this, PhAB lets you get on with the job of writing the
code that implements your application’s main functionality.
For most code generation, you use the Build & Run dialog. However,
you can also generate some C and C++ stub files on the spot when
using various dialogs to develop your application; use the icons that
are located next to function or filename fields:

This means you’re free to edit a callback function while still in the
process of attaching it to the widget. You don’t have to go into the
Build & Run dialog, generate code from there, and then come back to
write the function.

Using the Build & Run dialog


Think of the Build & Run dialog as the development center for
building your applications. From this dialog, you can:

¯ generate the application code

¯ make (compile and link) your application

¯ debug your application

¯ edit code

¯ run your application

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 223
Using the Build & Run dialog  2005, QNX Software Systems

To open the Build & Run dialog, choose the Build & Run item from
the Application menu or press F5.

☞ If the Build & Run item is dimmed, your application hasn’t been
named yet. For more info, see “Saving an application” in the Working
with Applications chapter.

PhAB automatically saves your application when you open the Build
& Run dialog.

B&R: sample - /home/stev er/phab/sample/src

.. File Spec

default *
ntoold
Makefile
Refresh
abHfiles
abOfiles Create

abSfiles Edit
abdefine.h View
abevents.h
Delete
abimport.h
Print
ablinks.h

Library Usage Target Platform Commands


Default (default)
Static Lib Generate...
9.5x
Shared Lib 9.5x.16 Make...
Language Run Arguments Run Application

(Default) Debug Application

Build Preferences...
Done

Sample Build & Run session.

The scrolling list displays the application source files that PhAB has
generated, as well as any you’ve created by hand. This list may be

224 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Generating application code

empty if you’re designing a new application and haven’t yet generated


any code.

Generating application code


When you make changes to your application, even within your own
source files, you may need to generate the application code. Doing so
ensures that the prototype header file, proto.h, is up to date. You
can safely generate the code at any time — PhAB won’t overwrite
any code you’ve added to the stubs it generated earlier.
Before generating the code, PhAB saves your application if you’ve
modified any modules. To minimize compile time, PhAB compiles
only the files that have changed.

☞ If you plan to use a global header in your application, you should set
up the header before generating any code. For more information, see
“Specifying application startup information” in the Working with
Applications chapter, and “Global header file” in the Generating,
Compiling, & Running Code chapter.

To generate your application code:

1 Click on the Generate button in the Build & Run dialog. Wait
for the progress meter to reach 100%.

2 Click on Done in the progress dialog.

The file list now shows all the generated code files.

What PhAB generates


PhAB generates various files and stores them in the application’s src
directory.

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 225
Generating application code  2005, QNX Software Systems

!
CAUTION: Any filename that starts with ab is a PhAB file and
shouldn’t be modified at any time. If you try to edit an ab file, you
could lose work (when PhAB overwrites the file) or experience
incorrect behavior (when files get out of sync).

You can modify any other files that PhAB generates, with few
conditions. These conditions are described in the following sections.
Here are the files that PhAB generates:

Makefile Used to compile and link the application

Usemsg A usage message for the application

abHfiles
abOfiles
abSfiles External PhAB references in the Makefile

abdefine.h Contains all the PhAB-generated manifests. PhAB


includes this header in all C files.

abevents.h Contains all the application’s callbacks

abimport.h The extern reference header that’s included in all


C files. See “Function prototypes”, below.

ablinks.h Contains all the application’s module definitions

abmain.c The application’s main-line C file. This file starts


with ab, so don’t modify it. If you need to control
the main-line processing, specify a mainloop
function in the Application Startup Information
dialog, as described in the Working with
Applications chapter.

abmain.cc If PhAB detects any C++ functions in your


application, it generates abmain.cc instead of
abmain.c. This file also starts with ab, so don’t
modify it.

226 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Generating application code

abplatform Contains a list of the platform directories for the


application

abvars.h Contains all the PhAB-generated global variables

abwidgets.h Contains all the PhAB data references

proto.h Contains the application’s prototypes — see


“Function prototypes”, below. Don’t rename this
file.

Version control
Here are the files you need to save if you’re using version-control
software (PhAB can generate some of them, but it’s a good idea to
save them all):

abapp.dfn Callbacks and other information — this is a binary


file.

wgt/* Widget resources — these might look like text, but


they’re binary.
src/*.{c,cc,cpp,C,h}
Source files and headers.

src/*files Files that list non-PhAB source files. Be sure to


save the non-PhAB source, too.
src/Makefile, src/*/Makefile
All the make files.
application name.ldb
Your application’s language database. Save any
translation files as well.

You’ll need to keep a matched set of all the files that PhAB generates;
save the same version of the abapp.dfn, src/ab*, and
wgt/*.wgt? files.

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 227
Generating application code  2005, QNX Software Systems

Tips on using CVS


It’s easier to save a PhAB application in CVS than RCS. Here are
some things to keep in mind:

¯ Flag the *.wgt? and abapp.dfn files as binary (-kb).

¯ Since binary files can’t be merged, try to prevent multiple people


from modifying the binary files at the same time. CVS doesn’t
support locking; the closest you can get is to set a “watch” on
abapp.dfn (cvs watch on abapp.dfn).
This way, if you just check out an application, your copy of
abapp.dfn is read-only and PhAB doesn’t let you load the
application. If you do want to modify the application, you have to
run cvs edit abapp.dfn, which makes the file writable. Even
though this doesn’t prevent other people from doing the same, it at
least adds you to a list of “editors” on the CVS server that other
people can query.

Function prototypes
PhAB generates function prototypes that are used by the compiler to
check that your functions are called correctly. These prototypes are
placed in abimport.h and optionally in proto.h. Here’s how these
files compare:

proto.h abimport.h
Generated by parsing your Generated by looking at your
source code. application’s settings.
Prototypes for all functions are Only prototypes known to
generated. PhAB (callbacks, setup
functions, pointer-to-function
resources) are generated.

continued. . .

228 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Generating application code

proto.h abimport.h
You can have problems with Prototypes don’t depend on the
preprocessor directives (see source code.
“Potential problems with
generating proto.h”), unusual
C constructs, syntax errors, and
C++ code.
Doesn’t work with C++. Contains the appropriate
#ifdefs and extern "C"
declarations required by C++.
Prototypes match what the Prototypes match what the
functions look like. functions are supposed to look
like — if the source code is
different, the compiler can
detect it.

To suppress the generation of prototypes in proto.h:

1 Press F2 or from the Application menu, choose Startup


Info/Modules to open the Application Startup Information
dialog.

2 Click on the Generate empty “proto.h” file button.

Potential problems with generating proto.h


In the interests of speed, the program that scans your source files for
function prototypes ignores preprocessor directives. This can cause
some problems in proto.h.
For example, say we have the following code:

#ifdef DOUBLE
for (i = 0; i < 18; i++, i++) {
#else
for (i = 0; i < 18; i++) {
#endif
x += 2 * (i + x);
y += x;
}

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 229
How application files are organized  2005, QNX Software Systems

Since preprocessor directives are ignored, the prototype generator


sees:

for (i = 0; i < 18; i++, i++) {


for (i = 0; i < 18; i++) {
x += 2 * (i + x);
y += x;
}

The two opening braces will cause it some confusion, and an incorrect
prototype will be generated. Look for this type of thing if the
prototype generator is creating incorrect prototypes.
To fix the example above, we could remove the opening braces and
put an opening brace on the line after the #endif. Alternatively, we
could do the following:

#ifdef DOUBLE
#define ADDAMOUNT 2
#else
#define ADDAMOUNT 1
#endif

for (i = 0; i < 18; i += ADDAMOUNT) {


x += 2 * (i + x);
y += x;
}

How application files are organized


PhAB stores each application as a directory structure. This structure
consists of a main directory that holds the application-definition file,
two subdirectories that store the module files and application source
code, and, potentially, directories for different development platforms:

230 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems How application files are organized

appl

src wgt

platforms

Directories for a PhAB application.

The platforms directories are created if you generate your application


for the first time after having installed Watcom C version 10.6 or later.
You can choose the platforms on which to compile your application.

☞ You should choose default as the platform unless you specifically


need a different one. If you choose default, new versions of the
compiler will be used automatically when they’re installed.

Multiplatform applications
Here’s what each directory contains if you generate your application
for the first time after installing Watcom 10.6 or later:

appl The name of this directory is the same as your


application. It contains the application-definition file,
abapp.dfn. Because this file is proprietary to PhAB,
you shouldn’t try to modify it.

appl/src The src directory contains the source code, headers,


and a Makefile generated by PhAB, as well as any

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 231
How application files are organized  2005, QNX Software Systems

code you create yourself. The Build & Run dialog


initially displays the contents of this directory.
For detailed information on the files stored in this
directory, see “What PhAB generates” in this chapter.

appl/src/platforms
These directories contain the Makefile, object files
and executables for the chosen platforms. The
Makefile in the src directory runs those in the
platform directories.

appl/wgt The wgt directory contains your application modules.


Because each type of module has a different file
extension, it’s fairly easy to recognize the exact
modules you want when importing modules from
another application. For more info, see the handy
tables in the “Module types” section in the Working
with Modules chapter.

!
CAUTION: Always use PhAB to edit the module files in the wgt
directory. Don’t try to edit these binary files with another editor.
Never modify any files prefixed by ab.

Single-platform applications
Here’s what each directory contains if you first generate your
application before installing Watcom 10.6 or later:

appl The name of this directory is the same as your


application. It contains the application-definition file,
abdefn.app. Because this file is proprietary to PhAB,
you shouldn’t try to modify it. After you’ve compiled
and linked the application, the executable is also placed
in this directory.

232 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Editing source

appl/src The src directory contains the source code, headers,


object files, and Makefile generated by PhAB, as
well as any code you create yourself. The Build & Run
dialog initially displays the contents of this directory.
For detailed information on the files stored in this
directory, see “What PhAB generates” in this chapter.

appl/wgt The wgt directory contains your application modules.


Because each type of module has a different file
extension, it’s fairly easy to recognize the exact
modules you want when importing modules from
another application. For more info, see the handy
tables in the “Module types” section in the Working
with Modules chapter.

Converting to multiplatforms
You can convert your application to multiple platforms after installing
Watcom 10.6 or later, but it isn’t necessary; PhAB works with both
types of application.
To convert to multiple platforms, choose Convert to Multiplatform
from the Application menu. PhAB moves any existing Makefile to
src/default/Makefile.old. Use the Generate command in the
Build & Run dialog to generate a new Makefile for the desired
platforms, and then edit them to propagate any required changes from
the old Makefile to the new.

Editing source
Once you’ve generated your application code, you’ll see the C and/or
C++ source code modules displayed in Build & Run’s file list. Next to
the file list, you’ll see several buttons to perform various actions on
the files.
To edit, view, or delete source code:

1 Click on the source-code file.

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 233
Editing source  2005, QNX Software Systems

2 Click on the appropriate action button (Edit, View, Delete, ...).


You can also edit a file by double-clicking on its name.

Choosing an editor or browser


To choose which editor or browser the Edit and View buttons will
invoke, see “Customizing your PhAB environment” in the chapter on
PhAB’s Environment.

Creating a source module


To create a new source-code module:

1 Click on the Create button to open the Create File dialog, then
type the name of the new file.

2 If you wish to create the file using a template (for a header file
or widget callback), select a format from the Template
combobox.

3 Click on Create. You’ll see a terminal window that displays


either an empty file or a file that contains the template.

If you create any files, click on the Refresh button to reread the
application directory and refresh the list of files on the left side of the
Build & Run dialog,

Changing the file display


To control which files are displayed in the Build & Run dialog, use
the following:

¯ Refresh — forces a reread of the application source directory to


ensure that your file list is current

¯ File Spec — lets you specify a filename pattern

234 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Compiling & linking

Compiling & linking


After generating the application code, you need to:

1 Choose the libraries your application will use.

2 Use Make to compile and link your application.

Choosing the libraries


PhAB lets you use the following libraries with your application:

¯ Static Lib — Link the Photon and PhAB libraries into the
application executable. The application will be larger than if you
used the shared library, but will run without the shared libraries.
This might be useful in an embedded environment.

¯ Shared Lib — Don’t include the libraries in the application. The


application will be much smaller, but requires the Photon shared
libraries to run.

The default is shared libraries.

Running make
Once you’ve chosen the library type, you’re ready to compile and link.
The first time you generate your application, PhAB creates a
Makefile in the src directory (plus a Makefile for each platform
selected for multiplatform development) so you can make the
application. Subsequent generations don’t modify the file directly;
instead, they update external files referenced in the Makefile.
Once the Makefile is generated you’re free to modify it, with a few
conditions:

¯ PhAB places external file references in the Makefile for the


object, source, and header files it generates and uses. Don’t
remove these references.

¯ PhAB also uses three target-name references called app, shr, and
proto. Don’t rename these make targets.

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 235
Compiling & linking  2005, QNX Software Systems

The app and shr targets are used to compile and link the
application with static or shared libraries. The proto target is
used to generate the application prototype file, proto.h; see
“Generating function prototypes” later in this chapter.

By default, the Makefile is compatible with the installed make


command. You can convert the file to a format that suits the make
command you prefer — just make sure the external file reference
method is still compatible.
For more information, see “Including non-PhAB files in your
application,” later in this chapter.
To make your application:

1 Click on the Make button to open the Make Application dialog


and start the make process.

2 If any errors or warnings are detected during the make process,


PhAB enables the Edit and Restart buttons.
To edit the first file that contains errors, click on Edit. After
fixing the problems, click on Restart to run make again.
To stop make at any time, click on Abort.

3 Once the application has been compiled and linked, PhAB will
enable the Make dialog’s Done button. Click on Done to close
the dialog.
The Done button is also enabled when you click on Abort.

Modifying the make command


By default, PhAB uses the installed make command to make your
application. If you need to change this command in any way, click on
the Build Preferences button.

☞ Any changes you make to Build Preferences settings are saved with
the application itself rather than as a global preference.

236 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Running the application

Running the application


Once your application has been compiled and linked without errors,
it’s ready to run. Just follow these steps:

1 If you’ve used PhAB to create a multilingual application, you


can choose the language in the Build & Run dialog before
running your application. For more information, see the
International Language Support chapter.

2 If your application needs command-line arguments, type them


into the Run Arguments box.

3 Click on Run Appl.

☞ When your application runs, its working directory is the one that’s
displayed in the Build & Run dialog.

If you use functions such as printf() in your application, the output


goes to your console if you run your application from PhAB. To see
this output:

¯ Open a pterm window and use the ditto utility to view the
console (ditto is described in the QNX Utilities Reference).
Or

¯ Open a pterm and run the application from there instead of from
PhAB.

PhAB is still active while your application is running. To switch


between the two, use the Window Manager’s taskbar.

Debugging
PhAB lets you run your application with a debugger such as wd,
which can be handy if your application crashes or behaves incorrectly.

➤ To run your application from inside a debugger, click on the


Debug Application button.

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 237
Debugging  2005, QNX Software Systems

The debugger will start up in a terminal window. Your


application will display once you run it from the debugger.

To switch between the debugger and the application, use the Window
Manager’s taskbar.

Modifying the debugger command


The default debugger is wd. If you need to change this command in
any way, click on the Build Preferences button and edit the debugger
command. For example, if you’re using Watcom 9.5x, change the
command to wvideo.
If you’re using printf() calls to debug your program, the easiest way to
see the output is to change the default debugger to:

pterm -z

When you click on Debug Application in the Build & Run dialog,
PhAB creates a pterm, which runs your application. The program’s
output appears in the pterm window. The -z option makes the pterm
window remain open until explicitly closed. For more information on
pterm, see the Photon Installation & Configuration guide.
You can even use printf() and wd together by setting the default
debugger to:

pterm wd

When you click on Debug Application in the Build & Run dialog,
PhAB starts pterm, which starts wd, which starts your application.
You can then use wd and see the program’s printed output.

☞ Any changes you make to Build Preferences settings are saved with
the application itself rather than as a global preference.

238 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
 2005, QNX Software Systems Including non-PhAB files in your application

Including non-PhAB files in your application


Your application can include files that aren’t created with PhAB, but
you need to tell PhAB how to find them.

Multiplatform applications
PhAB generates empty lists in the following files in the src directory,
and you can edit them:

indHfiles Non-PhAB header files. For example:

MYHDR = ../header1.h ../header2.h

indOfiles Non-PhAB object files. For example:

MYOBJ = file1.o file2.o

indSfiles Non-PhAB source files. For example:

MYSRC = ../file1.c ../file2.c

September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 239
Including non-PhAB files in your application  2005, QNX Software Systems

☞ Remember to specify the filenames relative to where the Makefiles


are found. For a multiplatform application, that’s relative to the
platform directory:

¯ header files and source files are usually in the parent directory,
src, so their names start with ../

¯ object files are usually in the same directories as the Makefiles

Single-platform applications
If you generated your application for the first time before installing
Watcom 10.6, you won’t have the indHfiles, indOfiles and
indSfiles files. Instead, you’ll find MYHDR, MYOBJ and MYSRC
in your Makefile, and you can specify filenames there.

☞ Remember to specify the filenames relative to where the Makefile is


found. For a single-platform application, that’s relative to the src
directory.

Adding libraries
If your application uses a library that isn’t included by default in the
Makefile, you can add it by editing the following variables:

¯ LDFLAGS — used when linking against static Photon libraries.

¯ SDFLAGS — used when linking against shared Photon libraries.

240 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
Chapter 10
Working with Code

In this chapter. . .
Variables and manifests 243
Global header file 248
Function names and filenames 249
Multithreaded programs 251
Initialization function 251
Mainloop function 254
Module setup functions 255
Code-callback functions 257
Initializing menus 258

September 20, 2005 Chapter 10 ¯ Working with Code 241


 2005, QNX Software Systems Variables and manifests

PhAB makes it easy to create the user interface for an application.


Once PhAB has generated code stubs for your application, you’ll
need to write the parts that make the application do something. This
chapter describes how to work with the code for a PhAB application.

Variables and manifests


Widget variables and manifests
PhAB creates global variables and manifests for every module you
create, and every widget with a unique instance name. This makes it
easier to access the widgets from your application code.
The global variable represents the widget’s name, and is defined in the
abvars.h file. Each global variable takes this form:

¯ ABN widget name — where widget name is the widget name or


module-instance name that you defined in the Control Panel.

☞ The value of a widget’s ABN ... variable is unique only in the module
that contains the widget. The variables for widgets in other modules
might have the same value.

The manifest represents the widget’s instance pointer, and is defined


in the abdefine.h file. This file, which is included in all application
C files, also defines an external reference to the global variables. Each
manifest takes this form:

¯ ABW widget name — where widget name is the widget name or


module-instance name that you defined in the Control Panel.

September 20, 2005 Chapter 10 ¯ Working with Code 243


Variables and manifests  2005, QNX Software Systems

☞ PhAB doesn’t create ABW ... manifests for menu modules or menu
items. Menus typically don’t exist for very long, so manifests for
them aren’t very useful. If you need to change the resources of the
PtMenu, create a setup function for the menu module and do the work
there. See “Module setup functions,” below.
The manifest for a window module refers to the last created instance
of the module. See “Handling multiple instances of a window,” below.

When PhAB detects a unique instance name it generates a global


variable name and a widget manifest. For example, if you change the
instance name for a PtButton-class widget to done, PhAB will
generate the following:

¯ ABN done

¯ ABW done

☞ A widget’s global variable and manifest are valid only after the widget
has been created, and before it has been destroyed.

Using the global variable and widget manifest


Let’s now look at some examples of how you can use the global name
and widget manifest within application code. First, here’s an example
of using the ABN done global variable and the ApName() function to
check for a specific widget in a callback:

int
mycallback( PtWidget t *widget, ... )

/* check for specific widget */


if ( ApName( widget ) == ABN done ) {
/* done button processing */
}

return( Pt CONTINUE );
}

244 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Variables and manifests

The next example uses ABW done to change the done widget’s
background color to red (for more information, see the Manipulating
Resources in Application Code chapter):

int
mycallback( PtWidget t *widget, ... )

{
PtArg t args[1];

PtSetArg( &args[0], Pt ARG FILL COLOR, Pg RED, 0 );


PtSetResources( ABW done, 1, args );

return( Pt CONTINUE );
}

☞ Remember that the global variable and the manifest are valid only
after the widget has been created and before it has been destroyed.

Handling multiple instances of a window


If you have more than one instance of a window module displayed at
a time, then you’ll have a problem accessing the widgets in the
window. The problem stems from the fact that ABW instance name
for any widget in a window module points to the last created instance
of that widget. If you have more than one instance of the window,
then you have more than one instance of the widgets within the
window created.
Let’s say you have the following window module:

September 20, 2005 Chapter 10 ¯ Working with Code 245


Variables and manifests  2005, QNX Software Systems

search_win

name_txt

search_btn

A sample search window.

If you have two instances of it on the screen at the same time and the
user clicks on the Search button, how can you get the value in the
Name text widget? Since two instances of the window exist, two
instances of the text widget exist. ABW name txt points to the last
instance of the text widget that was created.
The solution lies in the fact that ABN name txt can be used to refer to
both instances of name txt, provided you have the widget pointer to
the window that contains the desired text widget. This is done using
the ApGetWidgetPtr() function:
PtWidget t *window wgt, *text wgt;

text wgt = ApGetWidgetPtr(window wgt, ABN name txt);

Where do you get window wgt? In the above case, you’d have a code
callback on the Search button. The first parameter passed to that code
callback is the widget pointer to the Search button. You can use
ApGetInstance() to get a pointer to the window that contains the
Search button.
So the callback would become:
int search callback( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo)
{
char *name;
PtArg t arg;

246 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Variables and manifests

PtWidget t *window wgt, *text wgt;

// Get the window that the Search button is in

window wgt = ApGetInstance( widget );

// Given the window, find the text widget

text wgt = ApGetWidgetPtr( window wgt, ABN name txt );

// Now get the text

PtSetArg( &arg, Pt ARG TEXT STRING, &name, 0 );


PtGetResources( text wgt, 1, &arg );

// The ’name’ variable now points to the correct name text

// Process the text as appropriate


.
.
.

return( Pt CONTINUE );
}

Internal link manifests


PhAB generates a manifest for each internal link defined in your
application:

¯ ABM internal link name — where internal link name is a pointer


to the module’s internal definition.

For more information about using internal links, see the Accessing
PhAB Modules from Code chapter.

Icon manifests
PhAB also provides two manifests to access the application’s icons.
The names correspond to the default names that you should always
use when defining icons:

¯ ABW LIcon — Instance pointer of the large icon. This icon is only
used by the Photon Desktop Manager, PDM. For more info, see
“Icon modules” in the Working with Modules chapter.

September 20, 2005 Chapter 10 ¯ Working with Code 247


Global header file  2005, QNX Software Systems

¯ ABW SIcon — Instance pointer of the small icon displayed in


PWM’s taskbar. Because you can use this pointer to access the
icon, it’s easy to customize or animate the icon as required.

Global header file


PhAB lets you define one global header file for each application.
PhAB generates this file only once, the first time you generate the
application’s code.

☞ Once you’ve defined the header, PhAB automatically includes it in


any generated C or C++ stub file. So it’s best to define the header
when you first create the application. See “Specifying application
startup information” in the Working with Applications chapter. You
can modify the header whenever you need to.

Here’s a handy way of using this single header file to simultaneously


define all your global variables and the extern references to those
variables:
/* Header "globals.h" for my appl Application */

#include <Pt.h>

#ifdef DEFINE GLOBALS

#define GLOBAL
#define INIT(x) = x

#else

#define GLOBAL extern


#define INIT(x)

#endif

/* global variables */
GLOBAL int variable1 INIT(1);

If DEFINE GLOBALS is defined, then the last line in the above


example looks like:
int variable1 = 1;

248 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Function names and filenames

If DEFINE GLOBALS isn’t defined, then the last line in the above
example looks like:

extern int variable1;

Remember to define all your application’s global variables with the


GLOBAL prefix, as shown above. Also make sure to include the
following line in one (and only one) of your code files:

#define DEFINE GLOBALS

Including this line ensures that the global variables are defined in this
code file and used as extern declarations in all other code files.

☞ In the Makefile, make the code files dependent on the header file.
That way, if you make any changes to the header, all the code will be
recompiled when you make your application.

Function names and filenames


PhAB generates a function for every initialization function, module
setup function, callback, function menu item, and so on you’ve
specified in your application. If you don’t need a function, leave its
name blank.
After a function has been generated, you’re free to modify it. There’s
just one condition: if you change the function’s name, you must also
change the name you specified in the link callback or internal link
definition. Otherwise, PhAB will continue to regenerate the old name
every time it generates the application.
The way you specify the function name in PhAB determines the name
of the file the stub is put into:

function name
Create a C stub file called function name.c

September 20, 2005 Chapter 10 ¯ Working with Code 249


Function names and filenames  2005, QNX Software Systems

function [email protected]
Create a stub function and put it in filename.ext. This file will
include the headers and function structure required to compile
in the Photon environment.

PhAB recognizes .cc, .cpp, and .C as C++ extensions.



Under QNX 4, make doesn’t recognize .cpp as a C++ extension by
default.
If this file already exists, the stub function is added to it. You
can use this technique to reduce the number of code files for
your application. You can place any number of functions in the
same file. We recommend you put all functions related to a
module in the same file.
function name.ext
Short form for function name@function name.ext
class::function [email protected]
Generate a stub C++ static member function, but no prototype.
class::function name@
Don’t create a stub function or a prototype. Instead, invoke a
C++ static class member function. Prototypes aren’t generated
for class member functions; your application must have the
necessary declarations in its global header file.
function name@
Generate a prototype for a C function, but not a stub. This is
useful if you’re using a library of C functions.
::function name@
Generate a prototype for a C++ function, but not a stub. This is
useful if you’re using a library of C++ functions.

You can use C and C++ in the same PhAB application. See “What
PhAB generates” in the Generating, Compiling, & Running Code
chapter.

250 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Multithreaded programs

Multithreaded programs
In general, the Photon libraries aren’t threadsafe. In a multithreaded
program, only the thread that called PtInit() is allowed to call Photon
functions. The only exception is PtPulseDeliver() — you can use it in
other threads to send notifications to the Photon thread.

Initialization function
PhAB lets you define an application-level initialization function. The
PhAB API calls this function once at startup, before any windows or
other widgets are created. For information on setting up this function,
see “Specifying application startup information” in the Working with
Applications chapter.
The initialization function includes the standard argc and argv
arguments so that your application can parse command-line options if
needed (see below). You can also use this function to open any widget
databases (see the Accessing PhAB Modules from Code chapter) or
other application-specific data files.
Here’s a sample initialization function generated by PhAB:
/* Initialization Function - init.c */
/* AppBuilder Photon Code Lib */
/* Version 1.10 */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* see Global Header above */


#define DEFINE GLOBALS

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

September 20, 2005 Chapter 10 ¯ Working with Code 251


Initialization function  2005, QNX Software Systems

/* Application Options string */


const char ApOptions[] =
AB OPTIONS ""; /* Add your options in the "" */

int
init( int argc, char *argv[] )

{
char *device;

/* Eliminate ’unreferenced’ warnings. */


argc = argc, argv = argv;

/* Handle command-line options - if required.


Remember to ignore the ones handled by Photon. */

/* Typical spot to open widget databases */

/* Any other application-specific initialization */

return( Pt CONTINUE );

Processing command-line options


PhAB applications have several command-line options by default:

-h height[%] The height of the window, in pixels, or as a


percentage of the screen height if % is specified.
-s server name
The name of the Photon server:

If server name is: This server is used:


node number //node number/dev/photon
fullpath fullpath
relative path /dev/relative path

252 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Initialization function

-w width[%] The width of the window, in pixels, or as a


percentage of the screen width if % is specified.

-x position[%][r]
The x coordinate of the upper-left corner of the
window, in pixels, or as a percentage of screen
width if % is specified. If r is specified, the
coordinate is relative to the current console.
-y position[%][r]
The y coordinate of the upper-left corner of the
window, in pixels, or as a percentage of screen
height if % is specified. If r is specified, the
coordinate is relative to the current console.

-Si|m|n The initial state of the main window (iconified,


maximized, or normal).

You can suppress the options for the application’s size and position —
see “Command-line options” in the Working with Applications
chapter. You can also define additional options.

☞ You should edit the application’s usage message to reflect any


additions you make. For applications created with PhAB version 1.12
or later, edit the Usemsg file in your application’s src directory. For
details about the usage message syntax, see usemsg in the QNX
Utilities Reference.

Use the getopt() function (described in the Watcom C Library


Reference) to process the command-line options. The following
example shows how you could process several options (three of which
take arguments):

const char ApOptions[] = AB OPTIONS "a:b:c:pqr";

int init( int argc, char *argv[] ) {


int opt;
while ( ( opt = getopt( argc, argv, ApOptions ) ) != -1 )
switch ( opt ) {

September 20, 2005 Chapter 10 ¯ Working with Code 253


Mainloop function  2005, QNX Software Systems

case ’a’ : ...


case ’b’ : ...
...
case ’?’ : ...
}
...
return Pt CONTINUE;
}

AB OPTIONS is a macro that defines the default options added by


PhAB. It’s generated by PhAB, based on your Application Startup
settings. For example, if you set the No Pos Arg button, the
AB OPTIONS macro won’t contain x: or y:. You can process the
options in AB OPTIONS in two ways:

¯ include a case branch for each option, but do nothing in it. You
could also include a default that prints a message if an invalid
option is given.
or

¯ don’t include case branches for them. If you do this, you won’t be
able to have a default branch.

The PhAB library also looks at the ApOptions array to take into
account the options you’ve added. For example, for the above code
the library recognizes that -px100 specifies the X position (along
with -p), while -ax100 doesn’t.

☞ For applications generated with PhAB 1.11 or earlier, AB OPTIONS is


defined as "s:h:w:x:y:", and a default version of ApOptions in the
library is used. If you manually define ApOptions in your program,
it’s used instead of the default.

Mainloop function
The standard Photon mainloop function, PtMainLoop(), can handle
almost every application’s requirements. It takes care of all Photon
events, non-Photon events, and background processes.

254 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Module setup functions

Using the Application Startup Information dialog, you can define


your own mainloop function to replace the standard Photon function.
But you should use this advanced feature only if your application
won’t work with the standard PtMainLoop() function. For
information on setting up this function, see “Specifying application
startup information” in the Working with Applications chapter.
If you specify your own mainloop function, PhAB will generate a
mainline stub that contains the standard main-line code. You can
modify this code as needed.

!
CAUTION: This option is provided for very advanced Photon
developers, and requires an excellent understanding of how Photon
processes events. It can also make your application incompatible with
future versions of Photon. Don’t use it unless absolutely necessary.

Module setup functions


A module setup function is generated if you specify a function name
in a module-type link callback, as described in “Module callback” in
the Editing Resources and Callbacks in PhAB chapter.
All PhAB setup functions have three main arguments:
int
base setup( PtWidget t *link instance,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

/* eliminate unreferenced warnings */


link instance = link instance,
apinfo = apinfo,
cbinfo = cbinfo;

/* your code here */

return( Pt CONTINUE );
}

where:

September 20, 2005 Chapter 10 ¯ Working with Code 255


Module setup functions  2005, QNX Software Systems

link instance an instance pointer for the PhAB module being


created. You’ll need to save this pointer if it points
to a window module that supports multiple
instances.

apinfo a pointer to a PhAB structure. The structure


provides:
¯ A pointer to the widget that caused the setup
function to be invoked (that is, the widget that
caused the module to be displayed). For an
internal link, this pointer is a copy of the widget
pointer passed to ApCreateModule(); this pointer
is useful for positioning the module.
You can also determine the widget that caused
the setup function to be invoked by calling
ApWidget().
¯ Reason codes related to the type of setup
function being invoked:
ABR PRE REALIZE
This setup function is being called before
the module is realized.
ABR POST REALIZE
This setup function is being called after the
module is displayed on the screen.

cbinfo a pointer to a common Photon callback structure.


The structure provides information related to the
widget callback being invoked, the Photon event,
and some widget-specific callback data. The format
of the data varies with the widget class and callback
type. For more info, see PtCallbackInfo t in
the Widget Reference.

Normally, a setup function returns the value Pt CONTINUE. This tells


the PhAB API to continue processing and to display the module being
linked. For window and dialog modules, you can return Pt END to

256 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Code-callback functions

terminate the link callback and destroy the module without displaying
it. For window modules, you can return Pt HALT to neither realize nor
destroy the window. This is useful if you want to realize the window
later.

Code-callback functions
A code-callback function is generated if you specify a code-type link
callback, as described in “Code callbacks” in the Editing Resources
and Callbacks in PhAB chapter.
All code-type callback functions have three main arguments:
int
mycallback( PtWidget t *widget,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

/* eliminate unreferenced warnings */


widget = widget,
apinfo = apinfo,
cbinfo = cbinfo;

/* your code here */

return( Pt CONTINUE );
}

where:

widget a pointer to the widget instance that invoked the callback.

apinfo a pointer to a PhAB structure. The structure provides


reason codes related to the type of callback function being
invoked:

ABR CANCEL This callback function is being called by a


Cancel link.
ABR CODE This callback function is being called by a
Code link.

September 20, 2005 Chapter 10 ¯ Working with Code 257


Initializing menus  2005, QNX Software Systems

ABR DONE This callback function is being called by a


Done link.

cbinfo a pointer to a common Photon callback structure. The


structure provides information related to the widget
callback being invoked, the Photon event, and some
widget-specific callback data. The format of the data
varies with the widget class and callback type. For more
information, see PtCallbackInfo t in the Widget
Reference.

Your callback should return Pt CONTINUE unless the description of


the callback gives you a reason to return some thing else.

Initializing menus
You may want to do various things to a menu before it’s displayed.
You can use the menu’s setup function to:

¯ enable, disable, or toggle items

¯ change the text for an item

You can also use a function menu item to generate new items at
runtime.
The methods for doing these things are discussed in the sections that
follow.

Enabling, disabling, or toggling menu items


If a menu item isn’t currently a valid choice, it’s a good idea to
disable it so the user won’t try to select it. Of course, you’ll need to
enable it when appropriate, too. If your menu has any toggle items,
you’ll also need to set them before the menu is displayed. To do these
things, use the ApModifyItemState() function.
ApModifyItemState() takes a variable number of arguments:

258 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Initializing menus

¯ The first argument is a pointer to the menu module. For example,


if the instance name of the menu module is draw menu, pass
&draw menu as the first parameter.

¯ The second argument is the desired state:

AB ITEM DIM
to disable the item
AB ITEM NORMAL
to enable and unset the item
AB ITEM SET
to set a toggle item

¯ The rest of the arguments form a NULL-terminated list of the menu


items to be set to the given state. This list consists of the ABN ...
global variables of the items.

For example, suppose our application has a menu module whose


name is draw menu, which includes items with the instance names
draw group and draw align. We can disable these items with the
following call:
ApModifyItemState (&draw menu, AB ITEM DIM,
ABN draw group, ABN draw align, NULL);

Changing menu-item text


You can use the ApModifyItemText() function to change the text for a
menu item, for example, to replace a command by its opposite. The
arguments are as follows:

¯ a pointer to the menu module. For example, if the instance name


of the menu module is draw menu, pass &draw menu as the first
parameter.

¯ the ABN ... global variable for the menu item

¯ the new text

September 20, 2005 Chapter 10 ¯ Working with Code 259


Initializing menus  2005, QNX Software Systems

For example, our Draw menu might have an item that’s either Group
or Split, depending on what objects the user chooses. We could
change the text of the draw group item in the draw menu with the
following code:

ApModifyItemText (&draw menu, ABN draw group, "Split");

To get the current item text, call ApGetItemText().

Generating menu items


Sometimes you may need to generate the menu items at runtime. For
example, PhAB’s Window menu includes a list of the modules in your
application. To generate menu items, add a function item to your
menu module (as described in “Creating function items” of the
Working with Modules chapter), and edit the stub function PhAB
generates.
For example, if our draw menu module includes a function item that
calls add shapes(), PhAB generates the following code:

int add shapes (PtWidget t *widget, ApInfo t *apinfo,


PtCallbackInfo t *cbinfo)
{

/* eliminate ’unreferenced’ warnings */


widget=widget, apinfo=apinfo, cbinfo=cbinfo;

return (Pt CONTINUE);


}

The parameters passed to this function are of no use.


We use the PtCreateWidget() function to create the menu items,
which are usually PtMenuButton widgets. As discussed in the
Manipulating Resources in Application Code chapter, we can use the
same sort of argument list to set initial values for the resources as we
use with PtSetResources(). For example, to add an item Rectangle
with a keyboard shortcut of R:

PtArg t args[2];
PtWidget t *new item;

260 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Initializing menus

PtSetArg (&args[0], Pt ARG TEXT STRING, "Rectangle", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "R", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);

The second parameter in the call to PtCreateWidget() is the parent of


the widget; when you’re generating menu items, this should be set to
NULL. This makes the new item a child of the current menu or
submenu. Don’t call PtSetParentWidget() in this case.
Next, we need a callback function for the new item. We have to create
this manually; PhAB doesn’t create a stub function for it. For
example, the callback for our new item could be:
int rect callback( PtWidget t *widget,
void *client data,
PtCallbackInfo t *cbinfo )
{
...
}

This callback is similar to a code callback generated by PhAB. Its


arguments are:

widget A pointer to the menu item selected.


client data Arbitrary data passed to the callback.

This is different from a PhAB code callback, which receives apinfo as



its second argument.

cbinfo a pointer to a common Photon callback structure. The


structure provides information related to the widget
callback being invoked, the Photon event, and some
widget-specific callback data. The format of the data
varies with the widget class and callback type. For
more info, see PtCallbackInfo t in the Widget
Reference.

The last thing we need to do is add the callback to the menu item’s
Pt CB ACTIVATE callback list, using the PtAddCallback() function:

September 20, 2005 Chapter 10 ¯ Working with Code 261


Initializing menus  2005, QNX Software Systems

PtAddCallback (new item, Pt CB ACTIVATE,


rect callback, NULL);

The last argument to PtAddCallback() specifies what’s to be passed as


the client data argument of the callback. For more information, see
“Manipulating callbacks in your code” in the Creating Widgets in
Application Code chapter.
Let’s put all this together:

int rect callback( PtWidget t *widget,


void *client data,
PtCallbackInfo t *cbinfo)
{
...
}

int
add shapes (PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo)
{
PtArg t args[2];
PtWidget t *new item;

/* eliminate ’unreferenced’ warnings */


widget=widget, apinfo-apinfo, cbinfo=cbinfo;

PtSetArg (&args[0], Pt ARG TEXT STRING,


"Rectangle", 0);
PtSetArg (&args[1], Pt ARG ACCEL KEY, "R", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);
PtAddCallback (new item, Pt CB ACTIVATE,
rect callback, NULL);

/* Repeat the above for other shapes... */

return (Pt CONTINUE);


}

Creating submenus
You can create submenus in the menu created for a menu function
item as follows:

262 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Initializing menus

1 Create a menu button for the cascade menu, setting the


Pt ARG BUTTON TYPE to Pt MENU RIGHT or
Pt MENU DOWN, as required.

2 Save a pointer to the current parent widget:


menu = PtGetParentWidget ();

3 Create a new PtMenu widget and set Pt MENU CHILD in the


new menu’s Pt ARG MENU FLAGS resource.

☞ PtMenu is a container, so this new menu becomes the current default


parent.

4 Create submenu items, as described above.

5 Reset the default parent from the saved value:


PtSetParentWidget( menu );

6 Continue adding items to the top menu, if desired.

This example shows how to generate a submenu, as well as one way


the client data can be used in a generic callback to identify the item
chosen from the menu:

/* A menu with a submenu */


/* AppBuilder Photon Code Lib */
/* Version 1.11B */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */

September 20, 2005 Chapter 10 ¯ Working with Code 263


Initializing menus  2005, QNX Software Systems

#include "abimport.h"
#include "proto.h"

// Constants for the shapes in the menu


#define RECTANGLE 1
#define CIRCLE 2
#define DOT 3
#define BLOB 4
#define POLYGON 5

int
ShapeMenuCB( PtWidget t *widget, void *client data,
PtCallbackInfo t *cbinfo )

{
int shape chosen = (int) client data;

widget=widget, client data=client data, cbinfo=cbinfo;

// This callback uses the client data to determine


// which shape was chosen.

switch (shape chosen) {

case RECTANGLE: ...


break;
case CIRCLE : ...
break;
case DOT : ...
break;
case BLOB : ...
break;
case POLYGON : ...
break;
default : printf ("Unknown shape: %d\n",
shape chosen);
}

return (Pt CONTINUE);


}

int
add shapes( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PtArg t args[3];
PtWidget t *menu, *new item;

/* eliminate ’unreferenced’ warnings */

264 Chapter 10 ¯ Working with Code September 20, 2005


 2005, QNX Software Systems Initializing menus

widget = widget, apinfo = apinfo, cbinfo = cbinfo;

PtSetArg (&args[0], Pt ARG TEXT STRING, "Rectangle", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "R", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);
PtAddCallback ( new item, Pt CB ACTIVATE, ShapeMenuCB,
(void *)RECTANGLE );

PtSetArg (&args[0], Pt ARG TEXT STRING, "Circle", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "C", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);
PtAddCallback ( new item, Pt CB ACTIVATE, ShapeMenuCB,
(void *)CIRCLE );

// Create a menu button for the submenu.

PtSetArg (&args[0], Pt ARG TEXT STRING, "Miscellaneous", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "M", 0);
PtSetArg (&args[2], Pt ARG BUTTON TYPE, Pt MENU RIGHT, 0 );
new item = PtCreateWidget (PtMenuButton, NULL, 3, args);

// Save the current default parent.

menu = PtGetParentWidget();

// Create a submenu. It becomes the new default parent.

PtSetArg (&args[0], Pt ARG MENU FLAGS,


Pt MENU CHILD, Pt MENU CHILD);
new item = PtCreateWidget (PtMenu, NULL, 1, args);

// Add items to the submenu.

PtSetArg (&args[0], Pt ARG TEXT STRING, "Dot", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "D", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);
PtAddCallback ( new item, Pt CB ACTIVATE, ShapeMenuCB,
(void *)DOT );

PtSetArg (&args[0], Pt ARG TEXT STRING, "Blob", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "B", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);
PtAddCallback ( new item, Pt CB ACTIVATE, ShapeMenuCB,
(void *)BLOB);

// Restore the current default parent.

PtSetParentWidget (menu);

// Continue adding items to the top menu.

September 20, 2005 Chapter 10 ¯ Working with Code 265


Initializing menus  2005, QNX Software Systems

PtSetArg (&args[0], Pt ARG TEXT STRING, "Polygon", 0);


PtSetArg (&args[1], Pt ARG ACCEL KEY, "P", 0);
new item = PtCreateWidget (PtMenuButton, NULL, 2, args);
PtAddCallback ( new item, Pt CB ACTIVATE, ShapeMenuCB,
(void *)POLYGON);

return( Pt CONTINUE );

266 Chapter 10 ¯ Working with Code September 20, 2005


Chapter 11
Manipulating Resources in
Application Code

In this chapter. . .
Argument lists 269
Setting resources 271
Getting resources 277

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 267


 2005, QNX Software Systems Argument lists

Although you can set the initial values of a widget’s resources in


PhAB, you’ll probably need to access them from your code. For
example:

¯ when a dialog appears, you may need to initialize some of the data
it displays by setting resources beforehand

¯ when the user types a value in a PtText widget, you may need the
value in your program, so you’ll have to get resources.

In addition, if you use PtCreateWidget() to instantiate a widget in


your code, you can give an initial value to its resources.
The value for the resource is specified or retrieved using an argument
list.

☞ There are two steps involved in specifying or retrieving resource


values:

¯ Setting up the argument list, using the PtSetArg() macro.

¯ Setting the value, using PtSetResources(), or retrieving the value,


using PtGetResources().

Argument lists
An argument list is an array of PtArg t structures. Each of these
elements identifies a widget resource and a new value for the resource
(or the address of a variable that will be set to the resource’s current
value).
You can use the PtSetArg() macro to initialize each element of the
argument list:

PtSetArg( PtArg t *arg,


long type,
long value,
long len );

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 269


Argument lists  2005, QNX Software Systems

☞ If the values don’t need to be calculated at runtime, you might be able


to use Pt ARG() instead to initialize the argument list. For more
information, see the Photon Library Reference.

The first two arguments to PtSetArg() are the address of the argument
list element, and the name of the resource. The third and fourth
arguments vary, depending on the type of the resource, and on
whether a set or a get operation is being applied. When setting a
resource, the third argument is always used to hold a resource value or
a pointer to a resource’s value.
The fourth argument is used as either a size indicator or a mask,
depending on the type of the value being specified. The possible
resource types are given in the table below:

Type: Description:
Alloc An arbitrarily sized memory object
Array An array
Boolean A bit that’s either on or off
Complex A resource that’s handled in a special way; see below.
Flag A value in which each bit has a different meaning
Function A pointer to a function
Link A linked list
Pointer A pointer to an address that you specify
Scalar A value that can be represented within a single long
String A null-terminated string
Struct A fixed-size data type, usually a structure, float, or
double

For information about the resources defined for each widget, see the
Photon Widget Reference.

270 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Setting resources

☞ Complex resources are special; see their descriptions in the Widget


Reference for instructions for setting and getting them. Widgets that
have complex resources usually have convenience functions to make
it easier to work with them.

Setting resources
Remember that there are two steps involved in setting resource values:

¯ Setting up the argument list, using the PtSetArg() macro.

¯ Setting the value, using PtSetResources().

Argument lists for setting resources


Many of the sections that follow demonstrate setting some resources
for a PtComboBox widget. Note that you can set more than one
resource at a time. To do so, define an argument list of the appropriate
length:

PtArg t args[5];

After initializing the argument list, you’ll actually set the resources.

Scalar resources
When setting a scalar value, you should specify the value as the third
argument to PtSetArg(). The fourth argument isn’t used and should be
set to 0.
For example, to set the border width of the combo box, pass the new
value as the third argument:

PtSetArg(&args[0], Pt ARG BORDER WIDTH, 5, 0);

When you call PtSetResources(), the widget copies the scalar value
into its own internal data structure.

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 271


Setting resources  2005, QNX Software Systems

String resources
Setting a string value is similar to setting a scalar value; you specify
the string as the third argument to the PtSetArg() macro. The fourth
argument isn’t used and should be set to 0.
For example, to set the default text for the combo box, you could
specify a value for the Pt ARG TEXT STRING resource in one
element of the argument list:

PtSetArg(&args[1], Pt ARG TEXT STRING,


"Rectangle", 0);

When you call PtSetResources(), the widget copies the string into its
own internal data structure.
If you need to use international (non-ASCII) characters in a string, do
one of the following:

¯ Define the string in a widget database and use the language editor
to translate the string. See the International Language Support
chapter.

¯ Use ped or some other UTF-compatible editor to edit the


application’s C code. You can then use the compose sequences
described in the International Character Support chapter of the
Photon User’s Guide.

☞ Most pterm-based editors, such as elvis and vedit, aren’t


UTF-compatible.
For more information on ped, see the Photon Installation &
Configuration guide.

¯ Look up the desired symbol in <photon/PkKeyDef.h>, use


wctomb() to convert the character from Unicode to UTF-8, and
then code the hexadecimal digits in your string. For example, the
French word résumé would be coded as
"r\xC3\xA9sum\xC3\xA9" — difficult to read, but it works
with all editors.

272 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Setting resources

For more information on Unicode and UTF-8, see the appendix on


Unicode Multilingual Support.

Alloc resources
Some resources are designed to store an allocated block of memory.
For example, every widget includes a Pt ARG USER DATA resource
that you can use to store any data you want in the widget’s internal
memory. To set this resource, pass a pointer to the data as the third
argument to PtSetArg(). The fourth argument is the size of the block
of memory, in bytes:

my struct user data;

/* Initialize the data */

PtSetArg(&args[2], Pt ARG USER DATA, &user data,


sizeof (user data));

The widget copies the number of bytes given into its internal memory
when you call PtSetResources().

Array resources
When setting an array value, the third argument to PtSetArg() is the
address of the array. The fourth argument is the number of elements
in the array.
For example, the following entry in the argument list can be used to
set up Pt ARG ITEMS, the list of choices for the combo box:

char *cbox items[3] = {"Circle", "Rectangle", "Polygon"};

PtSetArg(&args[3], Pt ARG ITEMS, cbox items, 3);

The widget copies the contents of the array into its own internal data
structure when you call PtSetResources().

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 273


Setting resources  2005, QNX Software Systems

Flag resources
When setting a flag, the third argument to PtSetArg() is a bit field
specifying the value of the bits to be set. The fourth argument is a bit
mask indicating which elements of the bit field should be used.

☞ For the value, use Pt TRUE, Pt FALSE, or a combination of specific


bits and their complements. Don’t use a value of 1, since it contains
just one bit that’s on; that bit might not correspond to the bit you’re
trying to set.

For example, the following argument list specification turns on the


combo box widget’s Pt COMBOBOX STATIC flag (so that the combo
box always displays the list of items):

PtSetArg(&args[4], Pt ARG CBOX FLAGS,


Pt TRUE, Pt COMBOBOX STATIC);

When you call PtSetResources(), the widget uses the bit mask to
determine which bits of its internal flag resource representation to
alter. It takes the bit values from the value specified.

Function resources
When setting a function resource, pass a pointer to the function as the
third argument to PtSetArg(). The fourth argument is ignored; set it to
0.
For example, to specify a drawing function for a PtRaw widget, set
the Pt ARG RAW DRAW F resource as follows:

PtSetArg( &args[0], Pt ARG RAW DRAW F,


&my raw draw fn, 0);

When you call PtSetResources(), the widget copies the pointer into
the resource.

274 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Setting resources

Pointer resources
When setting a pointer resource, the pointer must be given as the third
argument to PtSetArg(). The fourth argument is ignored and should be
set to 0.
When you call PtSetResources(), the widget simply does a shallow
copy of the pointer into the resource.

☞ The widget doesn’t make a copy of the memory referenced by the


pointer; don’t free the memory while the widget is still referencing it.

Link resources
When setting a Link, pass the address of an array of data as the third
argument to PtSetArg(). The fourth argument has some special
meanings:

num append num items (if num is 0, one item is appended)

Pt LINK INSERT
insert the first array element at the beginning of the linked
list
Pt LINK DELETE
remove the first list element that matches the first array
element

The widget copies the data into its internal memory when you call
PtSetResources().

Struct resources
When setting a struct resource, pass the address of the data as the
third argument to PtSetArg(). The fourth argument isn’t used and
should be set to 0.
The widget copies the data into its internal memory when you call
PtSetResources().

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 275


Setting resources  2005, QNX Software Systems

Boolean resources
When setting a Boolean value, you should specify the value as the
third argument to PtSetArg(), using 0 for false, and a nonzero value
for true. The fourth argument isn’t used, and should be set to 0.
For example, to set the protocol for a PtTerminal to ANSI, pass a
nonzero value as the third argument:
PtSetArg(&args[1], Pt ARG TERM PROTOCOL, 1, 0);

When you call PtSetResources(), the widget clears or sets one bit in
its own internal data structure depending on whether or not the value
is zero.

Calling PtSetResources()
Once you’ve set up the argument list, you’re ready to set the
resources. Remember that PtSetArg() doesn’t set the resources; it just
sets up the argument list.
You can use PtSetResources() to set the new values for resources:
int PtSetResources( PtWidget t *widget,
int n args,
PtArg t *args );

The arguments to this function are a pointer to the widget, the number
of entries in the argument list, and the argument list itself.
You can also set resources by passing an argument list to the
PtCreateWidget() function. The rules for specifying values in
argument list elements are the same for both functions. For more
information, see the Creating Widgets in Application Code chapter.
For example, you could set the resources of a combo box, using the
argument list created above. Call PtSetResources() as follows:
PtSetResources (ABW shapes cbox, 5, args);

In response to a change to its resources, a widget may have to


redisplay itself. The PtSetResources() call triggers this change. Any

276 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Getting resources

changes to the appearance of the widget, however, don’t take effect


until control is restored to the Photon event-handling loop. Therefore,
if PtSetResources() is called from within a callback function or an
event-handling function, the change to the widget won’t be visible
until all the callbacks in the callback list and all event handlers have
been executed.

Getting resources
There are two steps involved in retrieving resource values:

¯ Setting up the argument list, using the PtSetArg() macro.

¯ Getting the value, using PtGetResources().

There are two methods of getting resources: one that involves


pointers, and one that doesn’t. The nonpointer method is usually
easier and safer:

¯ Since you’re getting a copy of the value, the chances of


overwriting the original by accident are smaller.

¯ You don’t need to worry about the type of the value (short versus
long).

¯ You have fewer local variables and don’t use pointers to them,
which makes your code easier to read and helps the compiler
generate better code.

The pointer method may be less confusing if you’re getting the values
of several resources at once; you’ll have named pointers to the values
instead of having to remember which element in the argument list
corresponds to which resource.

Not using pointers


If you set the value and len arguments to PtSetArg() to zero,
PtGetResources() returns the resource’s value (converted to long) as
follows:

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 277


Getting resources  2005, QNX Software Systems

Resource type value len


Flags (any C type) Value of the N/A
resource
Scalar (any C type) Value of the N/A
resource
Pointer (any C type) Value of the N/A
resource
String Address of the string N/A
Struct Address of the data N/A
Array Address of the first Number of items in
array item the array
Alloc Address of where N/A
the resource is
stored
Boolean 0 (false) or 1 (true) N/A

Scalar and flag resources (nonpointer method)


To get a scalar or flag resource (of any C type) with the nonpointer
method:

unsigned long getscalar( PtWidget t *widget, long type ) {


/* Get any kind of scalar */
PtArg t arg;
PtSetArg( &arg, type, 0, 0 );
PtGetResources( widget, 1, &arg );
return arg.value;
}

String resources (nonpointer method)


Here’s how to use the nonpointer method to get the value of a string
resource:

const char *getstr2( PtWidget t *widget, long type ) {

278 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Getting resources

PtArg t arg;

PtSetArg( &arg, type, 0, 0 );


PtGetResources( widget, 1, &arg );
return (char*) arg.value;
}

Boolean resources (nonpointer method)


In the nonpointer method to get a boolean, the value (0 or 1) is
returned in value argument to PtSetArg():

int getbool( PtWidget t *widget, long type ) {


PtArg t arg;

PtSetArg( &arg, type, 0, 0 );


PtGetResources( widget, 1, &arg );
return arg.value;
}

Using pointers
When using the pointer method to get a scalar, array, or flag resource,
the widget always gives a pointer to an internal widget data structure.
In the argument list element you set up using PtSetArg(), you must
provide the address of a variable to which the internal data pointer can
be assigned.
The fourth argument isn’t used for most types of resources. For
arrays, it’s the address of a pointer that on return from
PtGetResources() points to the number of entries.
For example, to obtain the contents of the Pt ARG FLAGS resource
(which is a long) for a widget, you must pass the address of a pointer
to a long:

const long *flags;


PtArg t arg[1];

PtSetArg(&arg[0], Pt ARG FLAGS, &flags, 0);


PtGetResources(ABW label, 1, arg);

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 279


Getting resources  2005, QNX Software Systems

!
CAUTION: PtGetResources() returns pointers directly into the
widget’s internal memory. Don’t attempt to modify the resources
directly using these pointers. Such a modification won’t have the
desired effect and will likely corrupt the widget’s behavior. Never free
these pointers either — this will certainly result in a memory
violation or some other fault.
Using const pointers will help avoid these problems.
Changes to the widget’s state may invalidate these pointers; use them
promptly.

If you wish to retrieve the value of a given resource and then modify
that value:
1 Get the resource.
2 Copy the resource to a temporary variable.
3 Modify the temporary variable.
4 Using the modified copy, set the resource.
You can use the value obtained to set the value of another resource of
this or any other widget, as long as you don’t change the original
value.
For example, you can use the following code to obtain
Pt ARG TEXT STRING, the text string displayed in the label widget
named label:
char *str;
PtArg t args[1];

PtSetArg(&args[0], Pt ARG TEXT STRING, &str, 0);


PtGetResources(ABW label, 1, args);

You can then assign this text string to another label named label2:
PtSetArg(&args[0], Pt ARG TEXT STRING, str, 0);
PtSetResources(ABW label2, 1, args);

280 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Getting resources

Scalar and flag resources (pointer method)


If you’re getting scalar or flag resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a pointer to the


appropriate C type.

¯ len isn’t used.

When PtGetResources() is called, the pointer is set to point to the


widget’s internal storage for that resource.
Here are some functions that get a scalar or flag resource, using the
pointer method:

unsigned long getlong( PtWidget t *widget, long type ) {


/* Get a long or long flags */
PtArg t arg; unsigned long const *result;

PtSetArg( &arg, type, &result, 0 );


PtGetResources( widget, 1, &arg );
return *result;
}

unsigned getshort( PtWidget t *widget, long type ) {


/* Get a short or short flags */
PtArg t arg; unsigned short const *result;

PtSetArg( &arg, type, &result, 0 );


PtGetResources( widget, 1, &arg );
return *result;
}

unsigned getbyte( PtWidget t *widget, long type ) {


/* Get a char or char flags */
PtArg t arg; unsigned char const *result;

PtSetArg( &arg, type, &result, 0 );


PtGetResources( widget, 1, &arg );
return *result;
}

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 281


Getting resources  2005, QNX Software Systems

String resources (pointer method)


If you’re getting string resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a char pointer.

¯ len isn’t used.

When PtGetResources() is called, the pointer specified is set to point


to the widget’s internal storage for the string resource. For example:
const char *getstr1( PtWidget t *widget, long type ) {
PtArg t arg; const char *str;

PtSetArg( &arg, type, &str, 0 );


PtGetResources( widget, 1, &arg );
return str;
}

Alloc resources (pointer method)


If you’re getting alloc resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a pointer of the


appropriate type (the type is determined by the data given to the
widget when this resource is set).

¯ len isn’t used.

When PtGetResources() is called, the pointer specified is set to point


to the widget’s internal data.

Array resources (pointer method)


If you’re getting array resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a pointer of the


appropriate C type (the first of the two C types given in the “New
Resources” table).

¯ len is the address of a pointer of the second C type given.

When PtGetResources() is called:

282 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Getting resources

¯ The pointer given by value is set to point to the beginning of the


array in the widget’s internal storage.

¯ The pointer given by len is set to point to the array-item count in


the widget’s internal storage.

Pointer resources (pointer method)


If you’re getting pointer resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a pointer of the


appropriate C type.

¯ len isn’t used.

When PtGetResources() is called, the pointer specified is set to point


to the same data as the widget’s internal pointer. The data is external
to the widget; you might be able to modify it, depending on the
resource.

Link resources (pointer method)


If you’re getting link resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a pointer to a


PtLinkedList t list structure. This structure contains at least:

struct Pt linked list *next


A pointer to the next item in the list.
char data[1] The address of the data stored in the list.

¯ len isn’t used.

When PtGetResources() is called, The pointer given by value is set to


point to the first node of the widget’s internal linked list.

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 283


Getting resources  2005, QNX Software Systems

☞ If you get a callback resource, the value argument to PtSetArg() is the


address of a pointer to a PtCallbackList t structure. For more
information, see “Examining callbacks” in the Creating Widgets in
Application Code chapter.

Struct resources (pointer method)


If you’re getting struct resources using the pointer method:

¯ The value argument to PtSetArg() is the address of a pointer of the


appropriate C type.

¯ len isn’t used.

When PtGetResources() is called, the pointer specified is set to point


to the widget’s internal storage for the struct resource.

Boolean resources (pointer method)


Version 1.13 and earlier

If you’re getting boolean resources using the pointer method in


Photon 1.13 or earlier:

¯ The value argument to PtSetArg() is the address of a pointer to the


C type specified for the resource.

¯ len can be a pointer to a long, or 0.

When PtGetResources() is called, you get a pointer into the widget’s


memory where the bit is stored. If len is a pointer, the address it
points to is set to be the mask. If 0, len is used to store the mask.
You’ll need to use the mask to check the value of the bit.
For example, to get the Pt ARG SHOW ARROWS resource of a
PtScrollbar, passing a pointer for the mask:

PtArg t arg;
const int *bool;
long mask;

PtSetArg( &arg[0], Pt ARG SHOW ARROWS, &bool, &mask );

284 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


 2005, QNX Software Systems Getting resources

PtGetResources (ABW scrollbar, 1, arg);

if ( *bool & *mask ) {


// Arrows are on
}

Here’s how to use len to store the mask:


PtArg t arg;
const int *bool;

PtSetArg( &arg[0], Pt ARG SHOW ARROWS, &bool, 0 );


PtGetResources (ABW scrollbar, 1, arg);

if ( *bool & arg.len ) {


// Arrows are on
}

Version 1.14 and later

The method used in Photon version 1.13 and earlier isn’t suited to
applications that run on different machines because of problems with
big- and little-endian representations. In version 1.14 and later, if
you’re getting boolean resources using the pointer method:
¯ The value argument to PtSetArg() is a pointer to an int.
¯ len isn’t used.
When PtGetResources() is called, the int is set to 1 if the Boolean is
true, or 0 if it’s false.
For example, to get the Pt ARG SHOW ARROWS resource of a
PtScrollbar:
PtArg t arg;
int bool;

PtSetArg( &arg[0], Pt ARG SHOW ARROWS, &bool, 0 );


PtGetResources (ABW scrollbar, 1, arg);

if ( bool ) {
// Arrows are on
}

September 20, 2005 Chapter 11 ¯ Manipulating Resources in Application Code 285


Getting resources  2005, QNX Software Systems

Calling PtGetResources()
Use PtGetResources() to obtain the values of each of the resources
identified in an argument list:

int PtGetResources( PtWidget t *widget,


int n args,
PtArg t *args );

The arguments to this function are the identifier for the widget, the
number of entries in the argument list, and the argument list itself.
PtGetResources() returns 0 on success, or -1 if an error occurs. A
return code of -1 might indicate that you’ve tried to get the value of a
resource that isn’t defined for the widget.

286 Chapter 11 ¯ Manipulating Resources in Application Code September 20, 2005


Chapter 12
Creating Widgets in Application
Code

In this chapter. . .
Creating widgets 289
Ordering widgets 290
Manipulating callbacks in your code 292
Manipulating event handlers in your code 297

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 287


 2005, QNX Software Systems Creating widgets

We recommend that you create your application’s UI in PhAB — it’s


easier than doing it in your code. However, if the interface is
dynamic, you’ll probably have to create parts of it “on the fly.”

Creating widgets
Creating a widget in your application code is a bit more work than
creating it in PhAB. That’s because PhAB looks after a lot of the
physical attributes for you, including size, location, and so on. If you
create the widget in your code, you’ll have to set these resources
yourself.
To create a widget in your code, call PtCreateWidget(). The syntax is
as follows:
PtWidget t *PtCreateWidget(
PtWidgetClassRef t *class,
PtWidget t *parent,
unsigned n args,
PtArg t *args );

The arguments are:

class The type of widget to create (e.g. PtButton)


parent The parent of the new widget. If this is NULL, the new
widget is a child of the default parent, which is the most
recently created container-class widget.
n args The number of elements in the args array.
args An array of settings for the widget’s resources. These
settings are like the ones used for PtSetResources(); see
the Manipulating Resources in Application Code chapter.

You can specify the default parent (used if the parent argument to
PtCreateWidget() is NULL) by calling PtSetParentWidget(). To assign
a widget to a different container, call PtReParentWidget().
Here are a few things to note about widgets created in application
code:

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 289


Ordering widgets  2005, QNX Software Systems

¯ The widget isn’t realized until the container widget is realized. If


the container is already realized, you can call PtRealizeWidget() to
realize the new widget.

¯ If you create a widget in a PhAB module and then destroy the


module, the widget is destroyed, too. The next time the module is
created, it will appear as it was specified in PhAB.

¯ If you save a global pointer to the widget, make sure you reset it to
NULL when the widget is destroyed. This can easily be done in the
widget’s Pt CB DESTROYED callback. Failing to reset the global
pointer (and check it before using it) is a frequent source of
problems with widgets created in code.

Ordering widgets
The order in which widgets are given focus depends on the order in
which they were created or on the widget order specified in PhAB
(see “Ordering widgets” in the Creating Widgets in PhAB chapter).
The backmost widget is the first in the tab order; the frontmost widget
is the last.
If you’re creating widgets programatically, you can creating them in
the order in which you want them to get focus, or you can use these
functions to change the order:

PtWidgetInsert()
Insert a widget in the widget family hierarchy
PtWidgetToBack()
Move a widget behind all its brothers
PtWidgetToFront()
Move a widget in front of all its brothers

Alternatively, you can use a widget’s Pt CB LOST FOCUS callback


(defined by PtBasic) to override the tab order by giving focus to
another widget.

290 Chapter 12 ¯ Creating Widgets in Application Code September 20, 2005


 2005, QNX Software Systems Ordering widgets

In the lost-focus callback, use PtContainerGiveFocus() to give focus


to the desired widget, and return Pt END from the callback to prevent
focus from being given to the original target of the focus change.

☞ The Pt CB LOST FOCUS callback is called a second time as focus is


removed from the widget to go to the new target. To avoid an endless
loop, use a static variable to indicate that this callback has already
redirected focus.

All in the widget family


The following functions can be used to work with the widget family
hierarchy, and may be useful in setting the focus order:

PtChildType() Determine the relationship between two widgets

PtFindFocusChild()
Find the closest focusable child widget
PtFindGuardian()
Find the widget responsible for another widget’s
actions

PtGetParent() Find the nearest widget with the same parent class

PtGetParentWidget()
Return the current default widget parent
PtNextTopLevelWidget()
Get a pointer to the next top-level widget

PtValidParent() Identify a valid parent for a widget

PtWidgetBrotherBehind()
Get the brother behind a widget
PtWidgetBrotherInFront()
Get the brother in front of a widget

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 291


Manipulating callbacks in your code  2005, QNX Software Systems

PtWidgetChildBack()
Get the child that’s farthest back in a container
PtWidgetChildFront()
Get the child at the very front of a container
PtWidgetFamily()
Traverse the widget hierarchy
PtWidgetParent()
Get a widget’s parent
PtWidgetSkip() Skip to a widget in the next hierarchy

PtWidgetTree() Walk the widget tree from front to back

PtWidgetTreeTraverse()
Walk the widget family hierarchy from front to
back

Manipulating callbacks in your code


You can add and remove callbacks in your code as well as from PhAB
— just watch for differences between the two types!

Adding callbacks
An application registers callbacks by manipulating the widget’s
callback resources. The Photon widget classes employ a naming
convention for these resources — they all begin with Pt CB .
Callbacks can be added to the callback list kept by these resources
using PtAddCallbacks() to add several callback functions to the list or
PtAddCallback() to add just one. In either case, the first two
arguments to the function are the widget and the name of the callback
resource to be augmented. The remaining arguments depend on
which function is used.
The third argument to PtAddCallbacks() is an array of callback
records. Each record contains a pointer to a callback function and the

292 Chapter 12 ¯ Creating Widgets in Application Code September 20, 2005


 2005, QNX Software Systems Manipulating callbacks in your code

associated client data pointer that will be passed to the callback


function when it’s invoked. Each of these callback records is copied
to the widget’s internal callback list.
For example, we might want to have the application perform some
action when the user selects (i.e. presses) a button. The PtButton
widget class provides the Pt CB ACTIVATE callback resource for
notifying the application when the button has been pressed. To create
the widget and attach a callback function to this callback resource,
we’d have to use code like this:

{
PtWidget t *button;
int push button cb( PtWidget t *, void *,
PtCallbackInfo t *);
PtCallback t callbacks[] = { {push button cb, NULL} };

...

button = PtCreateWidget(PtButton, window, 0, NULL);


PtAddCallbacks(button, Pt CB ACTIVATE, callbacks, 1);
}

where push button cb is the name of the application function that


would be called when the user presses the button.
When adding only one callback function to the callback list (as in this
case), it’s simpler to use PtAddCallback(). This function takes the
pointer to the callback function as the third argument, and the client
data pointer as the final argument. The above code fragment could be
written more concisely as:

{
PtWidget t *button;
int push button cb( PtWidget t *, void *,
PtCallbackInfo t *);
button = PtCreateWidget(PtButton, window, 0, NULL);
PtAddCallback(button, Pt CB ACTIVATE, push button cb,
NULL);
}

You can also give an array of callback records as the value for the
callback resource when using argument lists in conjunction with

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 293


Manipulating callbacks in your code  2005, QNX Software Systems

PtCreateWidget() or PtSetResources(). Since the callback list is an


array, you should specify the array’s base address as the third
argument to PtSetArg(), and the number of elements as the final
argument. In this case, the callback records are added to the current
callback list, if there is one. This gives us another way to specify the
callback for the above example:

{
PtArg t arg[5];
int push button cb( PtWidget t *, void *,
PtCallbackInfo t *);
PtCallback t callbacks[] = { {push button cb, NULL} };
...
PtSetArg(&args[0], Pt CB ACTIVATE, callbacks, 1);
PtCreateWidget(PtButton, window, 1, arg);
}

Each of these methods has its advantages. PtAddCallback() is of


course simple. PtAddCallbacks() is more efficient when there are
several callbacks. Using PtSetArg() and passing the result to
PtCreateWidget() allows the widget creation and callback list
attachment to be performed atomically.

Callback invocation
When called, the callback function is invoked with the following
parameters:

PtWidget t *widget
The widget that caused the callback function to be called, i.e.
the one on which the action took place.

void *client data


Application-specific data that was associated with the callback
when it was registered with the widget.

294 Chapter 12 ¯ Creating Widgets in Application Code September 20, 2005


 2005, QNX Software Systems Manipulating callbacks in your code

The client data that’s passed to a callback you add from your code
☞ isn’t the same as the apinfo data passed to a PhAB callback.
PtCallbackInfo t *call data
data specific to this invocation of the callback. It relates to the
reason the callback was called and may have data specific to the
callback’s behavior.
The PtCallbackInfo t structure is defined as:
typedef struct Pt callback info {
unsigned long reason;
unsigned long reason subtype;
PhEvent t *event;
void *cbdata;
} PtCallbackInfo t;

The elements of PtCallbackInfo t have the following


meaning:
¯ reason — indicates the reason the callback was called; this is
normally set to the name of the callback resource whose
callback list has been called.
¯ reason subtype — indicates a particular callback type
associated with the reason; for most callbacks, this value is
zero.
¯ event — the Photon event associated with the user action
that resulted in the callback’s being called.
¯ cbdata — call data that is specific to the callback resource
that caused the callback function to be called.
For more information, see the descriptions of the callbacks
defined for each widget in the Widget Reference.

Removing callbacks
You can remove one or more callbacks from a callback list associated
with a widget resource using the PtRemoveCallbacks() and
PtRemoveCallback() functions.

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 295


Manipulating callbacks in your code  2005, QNX Software Systems

!
CAUTION: Don’t try to remove a callback that was added through
PhAB; unexpected behavior may result.

PtRemoveCallbacks() takes an array of callback records as an


argument and removes all the callbacks specified by it from the
callback list. PtRemoveCallback() removes just one callback function
from the callback list. Both functions take the widget as the first
argument and the widget resource as the second argument.
To remove the callback from the button we’ve created above, we
could do this:

int push button cb( PtWidget t *, void *,


PtCallbackInfo t *);
PtCallback t callbacks[] = { {push button cb, NULL} };
PtRemoveCallbacks(button, Pt CB ACTIVATE, callbacks, 1);

or this:

int push button cb( PtWidget t *, void *,


PtCallbackInfo t *);
PtRemoveCallback(button, Pt CB ACTIVATE, push button cb,

Both the callback function pointer and the client data pointer are
important when removing callbacks. Only the first element of the
callback list that has both the same callback function and the same
client data pointer will be removed from the callback list.

Examining callbacks
You can examine the callback list by getting the value of the
appropriate callback list resource. The type of value you get from a
callback list resource is different from the value used to set the
resource. Although this resource is set with an array of callback
records, the value obtained by getting the resource is a pointer to a list
of callback records. The type of the list is PtCallbackList t. Each
element of the list contains a cb member (i.e. the callback record) and
a next pointer (which points to the next element of the list).

296 Chapter 12 ¯ Creating Widgets in Application Code September 20, 2005


 2005, QNX Software Systems Manipulating event handlers in your code

The following example shows how you can traverse through the
Pt CB ACTIVATE callback list for widget to find all instances of a
particular callback function, cb:

...
PtCallbackList t *cl;

PtSetArg(&arg[0], Pt CB ACTIVATE, &cl, 0);


PtGetResources(widget, 1, arg);
for ( ; cl; cl = cl->next )
{
if ( cl->cb.func == cb )
break;
}

Manipulating event handlers in your code


You can add and remove event handlers in your application code as
well as in PhAB — however, there are some differences between the
two types.
The PtWidget widget class provides a special form of callback —
Pt CB RAW. This callback will be called every time a Photon event
that matches a filter mask (provided by the application) is received.
Since all the widget classes in the Photon widget library are
descended from the PtWidget, this callback can be used with any
widget from the Photon widget library.
Whenever a Photon event is received, it’s passed to the appropriate
widget, which handles the event and may consume it. A widget’s
internal event handlers are always invoked before any that you register
in your application. If the widget doesn’t consume the event, it’s then
passed on to the widget’s parent, and so on up the widget family until
it’s consumed.
The widget invokes each event handler that has an event mask
matching an incoming event. Any event handler may consume the
event so that it’s not passed on to the remaining event handlers or to
the widget’s ancestors in the widget family.

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 297


Manipulating event handlers in your code  2005, QNX Software Systems

Adding event handlers


As with callbacks, you can also set or examine event handlers by
performing a set or get directly on the event handler resource (e.g.
Pt CB RAW). The set operation requires an array of event handler
records of type PtRawCallback t. These are similar to the callback
records mentioned above, having event mask, event f , and data fields.
The event mask is a mask of Photon event types indicating which
events will cause the callback function to be invoked. The event f and
data members are the event handler function and client data,
respectively.
A get operation yields a PtRawCallbackList t * list of event
handler records. As with callback lists, the list contains two members:
next and cb. The cb member is an event handler record.
You can add event handlers using either the PtAddEventHandler() or
PtAddEventHandlers() function.
The arguments to PtAddEventHandler() are:

widget Widget to which the event handler should be added.


event mask Event mask specifying which events should cause the
event handler to be called.
event f Event-handling function.
data A pointer to pass to the event handler as client data.

The arguments to PtAddEventHandlers() are:

widget Widget to which the event handlers should be added.


handlers Array of event handler records.
nhandlers Number of event handlers defined in the array.

If you add an event handler to a widget and the widget’s region is not
sensitive to one of the events contained in the event mask, then the
event is added to the set to which the region is sensitive. This is done
with a call to PhRegionChange().

298 Chapter 12 ¯ Creating Widgets in Application Code September 20, 2005


 2005, QNX Software Systems Manipulating event handlers in your code

Removing event handlers


You can remove event handlers by calling either the
PtRemoveEventHandler() or PtRemoveEventHandlers() function.

!
CAUTION: Don’t remove event handlers that were added through
PhAB; unexpected behavior may result.

The parameters to PtRemoveEventHandler() are:

widget Widget from which the event handler should be


removed.

event mask Event mask specifying the events the handler is


responsible for.

event f Event-handling function.

data Client data associated with the handler.

This looks for an event handler with the same signature — i.e. the
same event mask, data and event f — in the widget and removes one
if it’s found.
The parameters to PtRemoveEventHandlers() are:

widget Widget from which the event handlers should be


removed.

handlers Array of event-handler records.

nhandlers Number of event handlers defined in the array.

As with PtRemoveEventHandler(), an event handler is removed only


if it has the exact same signature as one of the event handler
specifications in the array of event handler records.

September 20, 2005 Chapter 12 ¯ Creating Widgets in Application Code 299


Manipulating event handlers in your code  2005, QNX Software Systems

Event handler invocation


When invoked, event handlers receive the same arguments as callback
functions, i.e. the parameters are:

¯ the widget that received the event (widget)

¯ the client data associated with the event handler (client data)

☞ The client data passed to this event handler isn’t the same as the
apinfo data passed to an event handler added through PhAB.

¯ the callback information associated with the particular event (info)

Event handlers return an integer value that the event handler must use
to indicate whether or not further processing should be performed on
the event. If the event handler returns the value Pt END, this indicates
that no further processing is to be performed on the Photon event, and
the event is consumed.
The event member of the info parameter contains a pointer to the
event that caused the event handler to be invoked. You should check
the type member of this event to determine how to deal with the event.
It will be one of the event types specified in the event mask given
when the event handler was added to the widget.
To retrieve the data associated with the particular event, call the
PhGetData() with the pointer to the event as a parameter. This will
return a pointer to a structure with the data specific to that particular
event type. This structure’s type depends on the event type.

300 Chapter 12 ¯ Creating Widgets in Application Code September 20, 2005


Chapter 13
Accessing PhAB Modules from
Code

In this chapter. . .
Creating internal links 304
Using internal links in your code 305
Using widget databases 308

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 301
 2005, QNX Software Systems

You can access any module directly from your application code by
creating an internal link to that module.
An internal link is like a link callback — it lets you specify the
module type, a setup function, and, where appropriate, a location. But
unlike a link callback, which is always associated directly with a
widget callback, an internal link has no association with any widget.
Instead, PhAB will generate a manifest that you use in your
application code to specify which internal link you want to use. PhAB
provides several functions to help you use internal links (discussed
below).
You can use internal links to:

¯ Create a PhAB module within application code.


Using a link callback, you can directly link a widget to a PhAB
application module. But sometimes you need to create the module
from your application code instead. To do that, use an internal link.
Here are some common situations where you should use an
internal link to create a module:
- when your application can display one of two different modules
based on some condition inside the application
- when you need to control the parentage of a module instead of
using the PhAB defaults
- when you want to display a menu when the user presses the
right mouse button.

¯ Access and display picture modules.


You use picture modules primarily to replace the contents of
existing container widgets, such as PtWindow or PtPane.
Note that when you create a picture module using
ApCreateModule(), you must specify the parent container widget.

¯ Open widget databases. For more information, see “Using widget


databases.”

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 303
Creating internal links  2005, QNX Software Systems

Creating internal links


To create an internal link:

1 Choose Internal Links from the Application menu or press F4.


You’ll see the Internal Module Links dialog:
Internal Module Links

Module Links Module Link Info Module Ty pes


< NEW > Dialog
Name: Window
M enu
Location: Default (0,0)
Picture
Setup Function: Other

Called: Pre- Realize Post- Realize

Actions
Apply
Reset

Remov e

Done Cancel

Internal Module Links dialog.

2 Click on the <NEW> option if it isn’t already selected.

3 Choose the type of module you want.

4 Fill in the fields in the Module Link Info section — see below.

5 Click on Apply, then click on Done. If the module you


specified in the Name field doesn’t exist, PhAB will ask
whether it should create that module.

☞ You can create only one internal link per module.

The fields in the Internal Module Links dialog include:

304 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
 2005, QNX Software Systems Using internal links in your code

¯ Name — Contains the name of the module. To select from a list of


existing modules, click on the icon next to this field.

¯ Location — Determines where the module will appear; see


“Location dialog” in the Working with Modules chapter.

¯ Setup Function — Specifies the function that will be called when


the module is realized (optional). To edit the function, click on the
icon next to this field.
For more information, see “Module setup functions” in the
Working with Code chapter.

¯ Called — Determines whether the setup function is called before


the module is realized, after the module is realized, or both.

¯ Apply — Applies any changes.

¯ Reset — Restores the internal link information to its original state.

¯ Remove — Deletes the selected internal link from the Module


Links list.

Using internal links in your code


Manifests
For every internal link defined in your application, PhAB generates a
manifest so you can identify and access the link.
Since PhAB derives the manifest name from the module name, each
module can have only one internal link. This may appear limiting, but
PhAB provides module-related functions (see below) that let you
customize a module’s setup function and location from within your
application code.
To create the manifest name, PhAB takes the module’s name and adds
ABM as a prefix. So, for example, if you create an internal link to a
module named mydialog, PhAB creates the manifest ABM mydialog.

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 305
Using internal links in your code  2005, QNX Software Systems

API
The manifest is used by the following PhAB API functions:

ApCreateModule()
Lets you manually create modules designed within PhAB.
A module created with this function behaves exactly as if it
were linked directly with a link callback. For example, if you
define a location and a setup function for the internal link, the
module will appear at that location and the setup function will
be called. Furthermore, widget callbacks, hotkeys, and so on
will become active.
ApModuleFunction()
Lets you change the setup function associated with an internal
link.
ApModuleLocation()
Lets you change the display location associated with an internal
link.
ApModuleParent()
Lets you change the parent of a window module associated with
an internal link. This function applies only to internal links for
window modules.
ApOpenDBase()
Lets you open the module associated with an internal link as a
widget database.

For more info on the above functions, see the Photon Library
Reference.

Example — displaying a menu


Here’s how you can display a menu module when the user presses the
right mouse button while pointing at a widget:

306 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
 2005, QNX Software Systems Using internal links in your code

1 In PhAB, create the menu module. Give it a name, such as


my menu.

2 Create an internal link to the menu module, as described above.


For a popup menu, you’ll usually want the module to be
positioned relative to the widget or relative to the pointer.

3 Select the widget to be associated with the menu. Make sure it


has Pt MENUABLE set and Pt ALL BUTTONS cleared in its
Pt ARG FLAGS.

4 Generate the code for your application. PhAB creates a


manifest for the internal link. In this example, it’s called
ABM my menu.

5 Every widget that’s a descendant of PtBasic has a


Pt CB MENU resource that’s a list of callbacks invoked when
you press the right mouse button while pointing at the widget.
Edit this resource, and create a callback function like this:
int
text menu cb( PtWidget t *widget, ApInfo t *apinfo, PtCallbackInfo t *cbinfo )

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

ApCreateModule (ABM my menu, widget, cbinfo);

return( Pt CONTINUE );

The widget passed to ApCreateModule() is used if the menu is


to be positioned relative to the widget; the cbinfo argument is
used if the menu is to be positioned relative to the pointer.

6 Compile, link, and run your application. When you press the
right mouse button over the widget, your menu should appear.

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 307
Using widget databases  2005, QNX Software Systems

Using widget databases


Picture modules have two purposes:

¯ to let an application replace the contents of any container widget

¯ to serve as widget databases

If you plan to use a widget several times within your application, a


widget database lets you design the widget just once. It also saves you
from a lot of coding. All you have to do is preset the widget’s
resources and then, using PhAB’s widget-database API functions,
create a copy of the widget wherever you’d normally create the
widget within your code.
Here’s an example of a widget database — it’s the one that PhAB uses
for its own interface.

308 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
 2005, QNX Software Systems Using widget databases

abdbase Test Pict

Wind Othr Test


Close Button Dlg Pict
Menu Icon

123456789012
Trash

ol

DLG PICT CODE Sav ing...

WIND OTHR CNCL


e
MENU ICON DONE

tag M en u
resource
or
name

HotKey: Ctrl Shift Alt


n
Event Mask:

Widget database used for PhAB’s interface.

Creating a database
To create a widget database:

1 Create a picture module within your application.

2 Create an internal link to the picture module.

3 Create the widgets that you’ll need to access in your application


code.
For example, let’s say you need to create a certain icon many
times in your application. By creating the icon inside the

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 309
Using widget databases  2005, QNX Software Systems

picture module, you can create as many copies of the icon as


you need at run time.

Preattaching callbacks
Besides being able to preset all of a widget’s resources in the database
module, you can also preattach its callbacks. When you create the
widget dynamically, any callbacks you attached will also be created.
By presetting the resources and callbacks of a database widget, you
can easily reduce the code required to dynamically create the widget
to a single line.

☞ Preattached callbacks work only with modules and functions that are
part of your executable. If your application opens an external file as a
widget database, the PhAB library won’t be able to find the code to
attach to the callback.

Assigning unique instance names


Assign each widget in a widget database an instance name — this lets
you refer to the widgets when using database-related API functions.

Creating a dynamic database


You can also create a widget database that you can change
dynamically. To do this, open an external widget database — that is,
one that isn’t bound into your executable — with ApOpenDBaseFile()
instead of ApOpenDBase(). ApOpenDBaseFile() lets you access a
module file directly and open it as a database.
Once you’ve opened the module file, you can copy the widgets from
that file to your application’s internal database and save the resulting
database to a new file that you can reopen later. The Photon Desktop
Manager (PDM) takes this approach to maintain the icons in its
quick-launch folders.

310 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
 2005, QNX Software Systems Using widget databases

Widget-database functions
PhAB provides several support functions to let you open a widget
database and copy its widgets into modules — you can copy the
widgets as often as needed. PhAB also provides convenience
functions to let you copy widgets between databases, create widgets,
delete widgets, and save widget databases.

ApOpenDBase()
ApCloseDBase()
These let you open and close a widget database.
To ensure that the database is always available, you
typically use ApOpenDBase() in the application’s
initialization function.
ApOpenDBaseFile()
ApSaveDBaseFile()
These let you open external module files as
databases within your application.
ApAddClass() This function lets you indicate which widget
classes you’re likely to encounter when you call
ApOpenDBaseFile(). When you link your
application, only those widgets it needs are linked
into it. If you access widgets that aren’t in your
application because they’re in an external database,
you must add them to your internal class table so
that they can be linked in at compile time.
ApCreateWidget()
ApCreateWidgetFamily()
These create widgets from the widget database.
ApCreateWidget() creates a single widget only,
regardless of the widget’s class.
For a noncontainer-class widget,
ApCreateWidgetFamily() creates a single widget;
for a container-class widget, it creates all the
widgets within the container.

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 311
Using widget databases  2005, QNX Software Systems

ApCreateWidget() and ApCreateWidgetFamily()


put the new widget(s) in the current parent. To
make sure the correct widget is the current parent,
call PtSetParentWidget() before calling either of
these functions.

Don’t use the manifests generated for the widget database’s picture
☞ module. Instead, use the widget pointers returned by the
ApCreateWidget() function.
ApCopyWidget()
Lets you copy a widget from one widget database
to another. Typically, you use this only when
you’re dynamically creating and saving widget
databases within your application.

ApDeleteWidget()
Deletes a widget from a widget database.

ApGetBitmapRes()
ApGetImageRes()
These let you achieve very basic animation.
Essentially, they let you pull out bitmap or
image-resource data from a widget and use this
data to set resources of a widget already displayed
in your application.

If you use a widget database to create widgets that have PhImage t


☞ data attached to them, you shouldn’t close the database with
ApCloseDBase() until after those widgets are destroyed. (Closing the
database frees the memory used by the image.) If you must close the
database, make sure to copy the image data within your application
code and to reset the image data resource to point to your new copy.
For more information, see the “Animation” section
in the chapter on Drawing.

312 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
 2005, QNX Software Systems Using widget databases

ApFreeBitmapRes()
This function frees a bitmap resource structure
returned by ApGetBitmapRes(). It doesn’t free the
bitmap planes or colors because they point back
into the widget database.

ApGetTextRes() This lets you extract text strings from a widget


database. It’s useful for multilingual applications,
as the text is automatically translated if the
language support is enabled. For more information,
see the appendix on International Language
Support.

For more info on widget database functions, see the Photon Library
Reference.

September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 313
Chapter 14
International Language Support

In this chapter. . .
Application design considerations 317
Generating a language database 324
Language editor 324
Running your application 330
Distributing your application 332

September 20, 2005 Chapter 14 ¯ International Language Support 315


 2005, QNX Software Systems Application design considerations

PhAB has builtin support for applications that need to be translated


into other languages. By keeping a few design considerations in mind,
and then following a few simple steps, your application can very
easily be translated into other languages without the need to
recompile or rebuild your application:

1 PhAB generates a database of all the text strings used by your


application.

2 This text database is used by PhAB’s language editor to allow


you to translate each text string into another language.

3 The translated text strings are saved in a translation file, and are
shipped with your application.

4 To run your application in another language, simply set an


environment variable before starting the application. When
PhAB’s API builds the application windows, dialogs and other
modules, it replaces the text strings with the new translations.

It’s that simple.

Application design considerations


This section provides a few design considerations to assist you in
creating a language-independent application. You should keep these
ideas in mind as you are designing and implementing your
application, since modifying the application after it’s complete is
more difficult.

Size of text-based widgets


Typically, when you design an application, you lay out the window
using widgets that have the default application text already preset. For
example, if you had a Done button at the bottom of a dialog window,
the button itself would be only large enough to hold the text string
“Done”. You would also place the Done button based on its current
size. This works well in an application that doesn’t require
translation, but causes many problems for a language-independent

September 20, 2005 Chapter 14 ¯ International Language Support 317


Application design considerations  2005, QNX Software Systems

application. What would happen if the translated text were 12


characters instead of the default of 4 characters?

¯ The translated button could become much larger. In this case, the
button may be so wide that it writes on top of other widgets in the
window. This would cause the application to look ugly or poorly
designed.
or

¯ The text could be truncated within the default size. In this case, the
translated text would be unreadable, and the user wouldn’t know
what the button does.

For example, these buttons are too small to accommodate translated


text:

Done Cancel

The solution is simple. Make the button larger to accommodate


longer translated text strings. Here’s an example:

Done Cancel

Justification
In addition to making text-based widgets wider to accommodate
translated text, you should give some thought to the justification of
text, based on the widget’s usage. For example, in a simple text entry
field, it’s quite common to place a label to the left side of the field. If
you make the label wider to allow for translation, the label itself
moves to the far left:

318 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Application design considerations

Name

This problem is easily solved by setting the label’s horizontal


alignment to be right-justified. This allows for longer translated text
strings, and still keeps a tight alignment with the text entry field:

Name

Another common labeling method is to place a label centered above


or within the border of a box. Usually the text is centered by placing it
in the desired position based on its current text:

Box Title

When the text is later translated, it’s either too short or too long, and
the box label looks lopsided. The simple solution is to make the box
title much wider than necessary, and set the horizontal alignment to be
centered.

September 20, 2005 Chapter 14 ¯ International Language Support 319


Application design considerations  2005, QNX Software Systems

Box Title

There are probably many other cases similar to this but the important
point is to think about how the translated text will effect the look of
the application. A lot of aesthetics can be maintained simply by
making text-based widgets wider and setting an appropriate
justification.

Font height
The fonts for some languages, such as Japanese or Chinese, are only
readable at large point sizes. For these fonts, the minimum size may
be 14 points or even larger. If you’ve designed your entire application
using a 10 point Helvetica font you’ll have lots of problems when all
your text-based widgets are stretched 4 or more pixels taller to
accommodate the larger fonts. If your application needs to be
translated to other languages, look into the font requirements before
you begin, and use this minimum font size in the default language
built into the application.
If you really want to use the smaller font sizes for your default
application text, you can borrow a tip from the previous section. You
can make the height of widget larger and set the vertical alignment to
center. However, this may not work well for text input fields, and you
should keep this consideration in mind.

320 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Application design considerations

Hard-coded strings
Another major area for consideration is with informational, warning,
error or any textual messages that are displayed in popup dialog
windows or other points within the application. Examples could be
PtAskQuestion() or the PtMessage widget. The most common way
to handle text messages is to embed the text strings in the application
code. For example:

PtAskQuestion( ABW base, NULL, "File has changed. Save it?",


"helv14", "&Yes", "&No", "&Cancel", 1 );

While this is quick to code, it’s impossible to translate without


rewriting the application code, recompiling, and so on. Essentially,
you need to create a complete new version of the application for each
language supported. A much better method is to take advantage of
PhAB’s widget databases. Using a widget database, you can put all
your text messages in a single (or multiple) database and give each
message a unique name. To retrieve the text at runtime, call
ApGetTextRes() (see the Photon Library Reference for details). In the
above example, it would become:

PtAskQuestion( ABW base, NULL, ApGetTextRes( textdb, "@msg001"),


"helv14",
ApGetTextRes( textdb, "@msgyes" ),
ApGetTextRes( textdb, "@msgno"),
ApGetTextRes( textdb, "@msgcancel", 1 );

This method allows the application to have no predefined text-based


messages within it, and it can be easily translated. In addition,
because the text strings are put into a widget database, PhAB
automatically takes care of including the message texts when it
generates the application’s text string database. This is more
convenient than simply using an external text file and designing some
other method for translating this file.

September 20, 2005 Chapter 14 ¯ International Language Support 321


Application design considerations  2005, QNX Software Systems

Use of @ in instance names


By default, PhAB ignores widgets that have no instance name or have
the instance set to the class name. This means if you place a label
within a window and change the text to something appropriate, PhAB
skips this widget when it generates code for your application. This is
because PhAB assumes the label is constant and the application
doesn’t require access to it. However, when it comes to translating
your application to another language, this label becomes very
important.
To differentiate between widgets that are important for translation but
not for code generation, PhAB recognizes a special character when
placed in the first position of the instance name. This special character
is the @ character. This means you can give a label the instance name
of @label1, and PhAB will recognize this label when generating the
text language database, but skip over it when generating code.

Class : PtLabel

Widget Instance Name F9 F10

@label1

Horz Alignment Pt _CENTER


Vert Alignment Pt _CENTER

This sounds fine, except PhAB also requires that all instance names
be unique. This rule must be adhered to so that PhAB knows which
text string to replace at run time. Unfortunately, dreaming up
potentially hundreds of unique instance names that you don’t really
care about can be a lot of work. To simplify this task, PhAB lets you
specify a single @ character for the instance name, and PhAB appends
an internal sequence number to the end. This eliminates the need to
keep track of all constant text strings that require instance names just
for translation.
If you want to group translation text strings (say, by module), you can
give them all the same instance name, and PhAB will append a
sequence number to make the name unique. For example, if you

322 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Application design considerations

assign the name @base to several widgets, PhAB generates @base,


@base0, @base1, ... as instance names.

Bilingual applications
Sometimes it’s necessary to design an application to be bilingual.
This means two different languages are displayed in every text string.
While this can be done, it’s usually difficult for the user to read and
understand.
PhAB allows you to use another approach. You can create the
application in one language and provide the ability to flip to the other
language within application control. This is done via a PhAB API
function named ApSetTranslation(). This function (which is described
in the Photon Library Reference) changes the current translation file
for the application immediately, such that all future dialogs, windows,
and so on are drawn using the new translation file.

☞ Any existing modules and widgets aren’t translated, only new ones. If
you want immediate feedback, you need to recreate the modules. This
is easy for dialogs, but more difficult for the base window; remember
that destroying the base window exits the application. One way to
translate the contents of the base window is to put them in a picture
module, which can be recreated.

Common strings
If you have several applications to translate, you can reduce the work
by sharing the common text strings and translating them separately.
To do this:
1 Create a standalone application that contains a single picture
module (widget database) of the common text strings.
2 Use the PhAB Language Editor to translate the strings.
3 Once the database is created and translated, access it from
another application by calling ApAppendTranslation()
(described in the Photon Library Reference.

September 20, 2005 Chapter 14 ¯ International Language Support 323


Generating a language database  2005, QNX Software Systems

Generating a language database


This is the easy part. The most important aspect to this step is to know
when to generate the text string database. Ideally, you want to do this
when all application development is complete. This is because the
run-time translation mechanism is hinged on the widget’s instance
name. If you generate your database mid-way through the
development and do the translations, it’s quite likely that a lot of
widgets will be changed or deleted, and translations may be deleted or
the time wasted.
One exception to this would be bilingual applications. In this case,
you might want to generate and translate the application continuously
so that the application’s translations can be tested throughout the
development.
To generate an application’s language database:

1 Select the Application menu.

2 Select Languages/Generate Language Database. This pops up a


progress dialog, and begins generating the database
immediately.

3 Click on Done when the generation is complete.

The database has now been generated and is ready for use with the
PhAB Language Editor. The name of the database is app.ldb, where
app is the name of the executable file for the application (which is
typically the same as the name of the application, unless you’ve used
the Save As command to rename the application). The language
database is placed in the application’s directory (where the
abapp.dfn file is found).

Language editor
After the database has been generated, you can use PhAB’s Language
Editor to translate the default text strings to another language. The
Language Editor is designed to work both as a stand-alone application

324 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Language editor

that you can distribute with your application, or as an integrated part


of PhAB itself.

PhAB Language Editor


Language Database

/home/stever/phab/lang/lang.ldb
Translations
German

Open New Delete

PhAB Language Editor.

Starting the Language Editor within PhAB


When you are developing an application within PhAB, you can run
the Language Editor using the current application’s language database
quite easily:

1 Select the Application Menu.

2 Select Languages/Run Language Editor.

This starts the Language Editor using the current application’s


language database. At this point, you can proceed to create a new
translation file or edit an existing one.

September 20, 2005 Chapter 14 ¯ International Language Support 325


Language editor  2005, QNX Software Systems

Starting the Language Editor as a stand-alone


application
If you plan to allow your application to be translated at a customer
site, you’ll need to include the following files with your application:

¯ /qnx4/phtk/appbuilder/phablang

¯ /qnx4/phtk/appbuilder/languages.def

☞ The languages.def file must be in the same directory as the


phablang editor.

¯ your application’s language database file, xxx.ldb

To start at the client site, you can:

¯ type /qnx4/phtk/appbuilder/phablang &


or

¯ create an entry in the Desktop Manager to run


/qnx4/phtk/appbuilder/phablang (assuming the customer
is running the full desktop environment).

Once phablang is started:

1 Click on the Open Folder icon

to bring up the file selector.

2 Using the file selector, find the application’s xxx.ldb file.

3 Open the xxx.ldb file.

Creating a new translation file


To create a new translation file:

326 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Language editor

1 Click on the New button located at the bottom of the window.


The Language Selection dialog is displayed:

Language File Name


Language Selection
Belgian French
Canadian English
Danish
Dutch
French

Add Cancel

Language Selection dialog.

2 Choose the desired language from the list of supported


language file types.
3 Click on Add.
4 At this point you’re asked to reconfirm your selection. Click on
Yes.

The Language Selection dialog closes, and you should now see the
newly created translation file in the list of available translations.

Editing an existing translation file


To edit a translation file in the Translations list:
1 Click on the desired language from the list.
2 Click on the Open button.
The Text Translation Editor dialog appears. This editor displays all
the text strings available for translation in the current language
database.

September 20, 2005 Chapter 14 ¯ International Language Support 327


Language editor  2005, QNX Software Systems

Translating the text


To translate a text string:

1 Click on the text string you want to translate. The selected text
string is displayed in the text areas at the bottom of the window:
Default Text Translation
My Application Meine Anwendung

Sav e & Close Cancel

Default Text the default text bound into the application


Translation the current translation (if any) for the text
string. This is the area you use to type in the
new translation.


¯ If you need to type characters that don’t appear on your
keyboard, you can use the compose sequences listed in the
International Character Support chapter of the Photon User’s
Guide.
¯ You don’t have to translate every string. If a translation isn’t
available, the default text is used.

2 Once you change the translated string, a green check mark and
red X appear above the Translation area:

3 Click on the green check mark to accept your changes (the


shortcut is Ctrl – Enter).

4 Click on the red X to cancel your changes.

Repeat the above steps for all the text strings you need to translate.
When you’re finished, click on the Save & Close button.

328 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Language editor

☞ The clipboard buttons aren’t implemented at this time.

Hotkeys
One problem with translating an application is that the hotkey
assignments no longer match up if the translated string doesn’t
include the accelerator key value. For this reason, PhAB adds the
accelerator key strings to the language database too.
When translating the text string, the translator can also change the
accelerator key. If the key used in the hotkey isn’t a function key (i.e.
the key code is less than 0xF000), PhAB automatically changes the
hotkey to match the accelerator key.
For example, suppose your application has a button labeled Cancel.
You’d set the button’s Pt ARG ACCEL KEY to be C, and arrange for
Alt – C to invoke Pt CB HOTKEY.
When you generate the language database, you’ll find that it includes
the button’s label and its accelerator key. If you translate the
application into French, the button’s label would become Annuler,
so the hotkey Alt – C is no longer appropriate. Just translate the
button’s Pt ARG ACCEL KEY to be A, and the hotkey automatically
becomes Alt – A when you run the application in French.

☞ You’ll need to make sure there are no duplicate accelerator keys. If it


does happen by accident, only the first key defined is accepted.

Help resources
If you use the Photon Helpviewer for your application help and you
plan on providing multiple language help files for your application,
the translator can also translate the help topic paths to point to the
correct positions within the corresponding help files.

September 20, 2005 Chapter 14 ¯ International Language Support 329


Running your application  2005, QNX Software Systems

Running your application


After the language database is fully translated, the last step is to run
the application.
When you create the translation files, they’re placed in the same
directory as your application’s abapp.dfn file. You can think of
these as the working versions of the files. When you run your
application from PhAB, these are the versions you’ll use.
When you run your application outside of PhAB, it looks for the
translation files as follows:

1 In the directories listed in the ABLPATH environment variable,


if defined. This list takes the form:
dir:dir:dir:dir

Unlike the PATH environment variable, the current directory


must be indicated by a period, not a space. A space indicates
the directory where the executable is.

2 In the same directory as the executable, if the ABLPATH


environment variable isn’t defined.

You can think of these as the production versions of the translation


files.
In order for the PhAB API to know which translation file you want to
use, you must set the ABLANG environment variable to one of the
values below:

Language: Value:
Belgian French fr BE
Canadian English en CA
Canadian French fr CA

continued. . .

330 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Running your application

Language: Value:
Danish da DK
Dutch nl NL
French fr FR
German de DE
Italian it IT
Japanese ja JP
Norwegian no NO
Polish pl PL
Portuguese pt PT
Slovak sk SK
Spanish es ES
Swedish se SE
Swiss French fr CH
Swiss German de CH
UK English en GB
USA English en US

☞ This list is current at the time this document was written, but may
have since been updated. For the latest version, see the file:
/qnx4/phtk/appbuilder/languages.def

For example, to run an application in German (as spoken in


Germany), you would do the following:
$ export ABLANG=de DE
$ myapplication

September 20, 2005 Chapter 14 ¯ International Language Support 331


Distributing your application  2005, QNX Software Systems

☞ The application looks for the best match. For example, if the language
extension specified is fr CA, the search is as follows:

1 Exact match (e.g. fr CA).

2 General match (e.g. fr).

3 Wildcard match (e.g. fr*).

If no translation is found, the original text in the application is used.

The export command could be put in the user’s login profile so that
the application will run in each user’s preferred language. For more
information, see the section “PhAB multilingual applications” in the
Unicode Multilingual Support chapter of the Installation &
Configuration guide.

Distributing your application


When you ship your application to the customer site, you must make
sure to include the translation files in your distribution list. For
example, if your application is named myapp, and you have
translation files for French and German, you would need to include
the myapp.fr FR and myapp.de DE files with the application.
These files must be located:

¯ in the directories listed in the ABLPATH environment variable, if


defined. This list takes the form:
dir:dir:dir:dir

Unlike the PATH environment variable, the current directory must


be indicated by a period, not a space. A space indicates the
directory where the executable is.

¯ in the same directory as the executable, if ABLPATH isn’t defined

If you want each customer to be able to translate the application,


you’ll also need to distribute:

332 Chapter 14 ¯ International Language Support September 20, 2005


 2005, QNX Software Systems Distributing your application

¯ the language editor (phablang), which can be placed in the


/usr/bin/photon directory

¯ the language definition file (languages.def), which must be


installed in the same directory as the editor

¯ the application’s language database (myapp.ldb)

The language database and the translation files that the customer
creates should be in:

¯ one of the directories listed in the ABLPATH environment


variable, if defined

¯ the same directory as the executable, if ABLPATH isn’t defined

September 20, 2005 Chapter 14 ¯ International Language Support 333


Chapter 15
Context-Sensitive Help

In this chapter. . .
Creating help text 337
Referring to help topics 341
Connecting help to widgets 343
Accessing help from your code 345

September 20, 2005 Chapter 15 ¯ Context-Sensitive Help 335


 2005, QNX Software Systems Creating help text

Creating help text


To create help text to be read by the Photon Helpviewer, you’ll need
two types of files:

¯ the actual help files

¯ table-of-contents files

Help files
The help files are written in HTML, and have .html as an extension.
The Helpviewer supports the following tags (with attributes):

Element Tags Attributes


Comment <!-- comment -->
Document <html>...</html>
Head <head>...</head>
Title <title>...</title>
Link <link> href=url, rel=string
Body <body>...</body>
Heading 1 <h1>...</h1> id=string,
align={left,center,right}
Heading 2 <h2>...</h2> id=string,
align={left,center,right}
Heading 3 <h3>...</h3> id=string,
align={left,center,right}
Heading 4 <h4>...</h4> id=string,
align={left,center,right}
Heading 5 <h5>...</h5> id=string,
align={left,center,right}

continued. . .

September 20, 2005 Chapter 15 ¯ Context-Sensitive Help 337


Creating help text  2005, QNX Software Systems

Element Tags Attributes


Heading 6 <h6>...</h6> id=string,
align={left,center,right}
Rule <hr> id=string
Paragraph <p>...[</p>] id=string
Linebreak <br> id=string
Image <img> src=url,
align={top,middle,bottom},
alt=string, id=string (See
note below)
Anchor <a>...</a> href=url, name=string,
id=string
Preformatted <pre>...</pre> id=string
Blockquote <blockquote>...</blockquote> id=string
Address <address>...</address> id=string
Note <note>...</note> src=url, id=string
Definition list <dl>...</dl> compact, id=string
Term <dt>...[</dt>] id=string
Description <dd>...[</dd>] id=string
Ordered list <ol>...</ol> id=string
Unordered list <ul>...</ul> id=string
List item <li>...[</li>] id=string
Emphasis <em>...</em> id=string
Strong <strong>...</strong> id=string
Code <code>...</code> id=string
Sample <samp>...</samp> id=string

continued. . .

338 Chapter 15 ¯ Context-Sensitive Help September 20, 2005


 2005, QNX Software Systems Creating help text

Element Tags Attributes


Keyboard <kbd>...</kbd> id=string
Variable <var>...</var> id=string
Definition <dfn>...</dfn> id=string
Citation <cite>...</cite> id=string
Teletype <tt>...</tt> id=string
Bold <b>...</b> id=string
Italic <i>...</i> id=string
Underlined <u>...</u> id=string
Table <table>...</table> border,
align={left,center,right},
id=string
Table heading <th>...[</th>] align={left,center,right},
id=string
Table data <td>...[</td>] align={left,center,right},
id=string
Table row <tr>...[</tr>] id=string

☞ The Helpviewer supports only GIF and BMP images.

The Helpviewer also supports the standard HTML1/ISO entities for


characters, plus:

Entity: Meaning: Rendered as:


&nbsp; Nonbreaking space Space
&emsp; Em-space Space
&ensp; En-space Space

continued. . .

September 20, 2005 Chapter 15 ¯ Context-Sensitive Help 339


Creating help text  2005, QNX Software Systems

Entity: Meaning: Rendered as:


&mdash; Em-dash Dash (-)
&ndash; En-dash Dash (-)
&ldquo; Left double quote “
&rdquo; Right double quote ”
&lsquo; Left single quote ‘
&rsquo; Right single quote ’
&trade; Trademark TM

Table-of-content files
Table-of-contents (TOC) files define the list of products that have help
information, and the hierarchy of topics for each product. They have
.toc as a file extension.
All these have to be under the /usr/help/product directory. Each
product has a level-1 TOC file, and a directory with everything else.
For example, Photon help includes:

photon.toc
photon/

The photon.toc file consists of the following line:

1|Photon microGUI|./photon/bookset.html

where:

1 is the level in the topic hierarchy

| delimits fields

Photon microGUI
is a topic title

340 Chapter 15 ¯ Context-Sensitive Help September 20, 2005


 2005, QNX Software Systems Referring to help topics

./photon/bookset.html
is the Universal Resource Locator (URL) of the bookset
description

☞ Don’t use the vertical bar (|) in topic titles, because it’s used as a
delimiter in the TOC files.

The photon directory contains a TOC file and a directory for each
book. For example, it includes:
prog guide.toc
prog guide/

The prog guide.toc file is similar to photon.toc:


2|Programmer’s Guide|./prog guide/about.html

The prog guide directory contains the HTML files, and a


book.toc file that identifies the topic titles in the HTML files:

3|About This Guide|about.html#ABOUTTHISGUIDE


4|Assumptions|#id3
4|Changes and corrections|#ChangesAndCorrections
3|Introduction|intro.html#id1
4|Photon Application Builder - PhAB|#PhABApplications
6|Get immediate results|#id3
...

The part of the URL following the # is an anchor defined in the


HTML.

Referring to help topics


The Helpviewer understands two distinct ways of specifying the
location of the HTML help text to be displayed:

Universal Resource Locator (URL)


Specifies the filesystem path of the help-text file. It
specifies this path in the standard HTML way, except

September 20, 2005 Chapter 15 ¯ Context-Sensitive Help 341


Referring to help topics  2005, QNX Software Systems

that all files must reside on the local network. Here’s a


sample URL:

/usr/help/product/photon/run inst/pdm.html

URLs are case-sensitive. These URLs are restricted in scope to the


☞ help files; they can’t be used to access the web.

topic path Composed of the concatenated topic titles that are


defined in the current topic tree. For example, here’s
the equivalent topic path to the above URL:

/Photon microGUI/Installation & Configuration/pdm

For the Helpviewer, the topic path is case-insensitive


(unlike other HTML browsers) and may contain the
wildcard characters * or ?, where * matches a string
and ? matches a character. The first matching topic is
selected.
A topic tree used by the Helpviewer must have at least
three hierarchical levels: the top level is known as the
bookshelf, the second level as the book set, and the
third level as the book. A book may contain further
levels of chapters and sections.
Entries in a bookshelf or book set should not contain
any HTML, only .toc entries for the next level; help
text should only be found in books.

342 Chapter 15 ¯ Context-Sensitive Help September 20, 2005


 2005, QNX Software Systems Connecting help to widgets

Connecting help to widgets


You can display help information for a widget in the Helpviewer or in
a help balloon. You can even use both methods in an application. For
example, you could use a balloon for short explanations and the
Helpviewer for more detailed help.
No matter which method you choose, you need to do the following in
each of your application’s windows:

1 Set Ph WM HELP in the Flags: Managed


(Pt ARG WINDOW MANAGED FLAGS) resource.

2 Set Ph WM RENDER HELP in the Flags: Render


(Pt ARG WINDOW RENDER FLAGS) resource. This will add
a ? icon to the window frame. The user can click on it, and then
click on a widget, and the help information will be displayed.
If using the ? icon isn’t suitable for your application, see “Help
without the ? icon” later in this chapter.

For more information, see the Window Management chapter.

Displaying help in the Helpviewer


To use the Helpviewer to display help information for a widget, do the
following:

1 Optionally, specify the Help Root


(Pt ARG WINDOW HELP ROOT) resource for each window
in your application. This allows you to specify relative topic
paths for widgets inside the window.

☞ Use a topic path, not a URL.


The topic root should start with a slash (/), and should be the
top of all topics for the window, usually taken from a TOC file
in the /usr/help/product directory. For example:
/Photon microGUI/User’s Guide

September 20, 2005 Chapter 15 ¯ Context-Sensitive Help 343


Connecting help to widgets  2005, QNX Software Systems

2 For each widget in the window, fill in the Help Topic


(Pt ARG HELP TOPIC) resource. If you specified a topic root
for the window, this topic path can be relative to the window’s
topic root. For example:
Introduction

When the user clicks on the ? icon and selects the widget, the help
information is displayed in the Helpviewer.

☞ If you get an error message about a bad link when you ask for help for
a widget, make sure that the topic path is correct.

Displaying help in a balloon


To use a balloon to display help information for a widget:

1 Put the text you want displayed in the balloon into the widget’s
Help Topic (Pt ARG HELP TOPIC) resource.

2 Set the Pt INTERNAL HELP flag in the widget’s Extended Flags


(Pt ARG EFLAGS) resource.

When the user clicks on the ? icon, and selects the widget, the help
information appears in a balloon.

Help without the ? icon


In many applications the ? icon in the window frame isn’t suitable.
However, you may still want to use the Photon Helpviewer for
displaying help. For example:

¯ For touch screens, the window’s ? icon may be too small.

¯ You may want the mouse pointer to change to the Help pointer
when a key is pressed.

To get the mouse pointer to change to the Help pointer, forward the
Ph WM HELP event to the window manager. The following code
would be in a callback attached to a PtButton widget labeled Help:

344 Chapter 15 ¯ Context-Sensitive Help September 20, 2005


 2005, QNX Software Systems Accessing help from your code

int
help cb( PtWidget t *widget, ApInfo t *apinfo, PtCallbackInfo t *cbinfo )
{
PhWindowEvent t winev;

memset( &winev, 0, sizeof(winev) );


winev.event f = Ph WM HELP;
winev.rid = PtWidgetRid( window );
PtForwardWindowEvent( &winev );

return( Pt CONTINUE );
}

☞ The window must have Ph WM HELP set in the Managed Flags


(Pt ARG WINDOW MANAGED FLAGS) resource. You must also fill
in the Help Topic (Pt ARG HELP TOPIC) resource for the widgets
that have help, as outlined above.

Accessing help from your code


Use the following functions (described in the Photon Library
Reference) to access help from your application’s code — you don’t
need them if you’re using the method described in “Connecting help
to widgets”:

PxHelpUrl() Display help for the URL.

PxHelpUrlRoot()
Set a URL root.

PxHelpTopic() Display help for a topic path.

PxHelpTopicRoot()
Set a topic root.
PxHelpTopicTree()
Display help for the topic tree.

PxHelpSearch() Search for a string.

September 20, 2005 Chapter 15 ¯ Context-Sensitive Help 345


Accessing help from your code  2005, QNX Software Systems

PxHelpQuit() Exit the Helpviewer.

☞ PxHelpUrlRoot() and PxHelpTopicRoot() don’t save the passed


string, so don’t free it until you’re finished using the help root.

346 Chapter 15 ¯ Context-Sensitive Help September 20, 2005


Chapter 16
Interprocess Communication and
Lengthy Operations

In this chapter. . .
Sending QNX messages 350
Receiving QNX messages 351
Photon pulses 359
Processing signals 373
Other I/O mechanisms 375
Lengthy operations 376

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 347


 2005, QNX Software Systems

The QNX and Neutrino operating systems support various methods of


interprocess communication (IPC), including:

¯ messages

¯ proxies (QNX)

¯ pulses (Neutrino)

¯ signals

¯ interrupts

These methods can be used in a Photon application, as long as you’re


careful. The Photon main event-handling loop that your application
calls is responsible for handling Photon events so that widgets update
themselves and your callback functions are called.
This simple event-driven model of programming used with the Photon
widget library presents some challenges for the application developer
because the event-handling loop performs an unconditional Receive()
to obtain events from Photon. This means your application has to be
careful if it needs to call Receive(), or Photon events might go astray
and the user interface might not be updated.
If you need to:

¯ respond to other QNX messages in your application

¯ perform I/O using another mechanism (such as reading from a


pipe)

¯ process signals

¯ respond to proxies and pulses

you’ll need a way to hook your application code into the


event-handling loop. Similarly, you may want to be able to add
time-outs to your application and associate callback functions with
them.
If one of your callback functions takes a long time to execute, events
won’t be dispatched during that interval and the application will

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 349


Sending QNX messages  2005, QNX Software Systems

appear to be “hung” as far as the user is concerned. You should


develop a strategy for handling lengthy operations within your
application.

Sending QNX messages


A Photon application can use Send() to pass messages to another
process, but the other process needs to Reply() promptly, as Photon
events aren’t processed while the application is blocked.
As an example, here’s a callback that extracts a string from a text
widget, sends it to another process with ID proc b, and displays the
reply in the same text widget:
/* Callback that sends a message to another process */
/* AppBuilder Photon Code Lib */
/* Version 1.13A */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/kernel.h> // Needed for Send()

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
send msg to b( PtWidget t *widget,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

PtArg t args[1];
char *a message;

/* eliminate ’unreferenced’ warnings */

350 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Receiving QNX messages

widget = widget, apinfo = apinfo, cbinfo = cbinfo;

// Get the string from the text widget.

PtSetArg (&args[0], Pt ARG TEXT STRING, 0, 0);


PtGetResources (ABW msg text, 1, &args);

// Send the string to another process.

a message = (char *)args[0].value;


if ( Send (proc b, a message, rcv msg,
msg size, msg size) == -1)
{
perror ("Send to B failed");
exit (-1);
}

// Remember the UI is "hung" until the other


// process replies!

// Display the reply in the same text widget.

PtSetArg (&args[0], Pt ARG TEXT STRING, rcv msg, 0);


PtSetResources (ABW msg text, 1, &args);

return( Pt CONTINUE );

The application’s initialization function determines proc b by calling


qnx name locate() as described in the Watcom C Library Reference.
For more information on messages, see the QNX System Architecture
guide.

Receiving QNX messages


To obtain events from Photon, the widget library performs an
unconditional Receive(), placing the received message in the event
buffer for the application context. If the message isn’t a Photon event,
it will be discarded unless you register an input handling procedure
(or input handler) in your application.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 351


Receiving QNX messages  2005, QNX Software Systems

☞ Don’t call Receive() with a process ID of 0 anywhere else in your


application. If you do, Photon events won’t be processed properly and
the user interface won’t be updated.
You can call Receive() for a specific function, but this isn’t a good
idea. Remember that your application and its interface will be
blocked until that process sends a message. It’s better to use an input
handler as described in this section.

An input handler is responsible for handling messages received by the


application from a particular process ID (PID). When you register the
handler with the widget library, you identify the PID the input handler
is associated with.
You can define more than one input handler in your application for a
PID, but only the last one registered is called by the widget library
when a message is received from that process.
You can register a nonspecific input handler by specifying a value of
zero for the PID. This handler is called when the application receives
any non-Photon messages that don’t have an input handler specifically
associated with the sender’s PID.

Adding an input handler


To register an input handler, call PtAppAddInput() when you initialize
the application. The syntax is given below; for more information, see
the Photon Library Reference.

PtInputId t *PtAppAddInput(
PtAppContext t app context,
pid t pid,
PtInputCallbackProc t input func,
void *data );

The arguments are:

app context The address of the application context, a structure


that manages all the data associated with this

352 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Receiving QNX messages

application. For Photon 1.1x, this must be specified


as NULL, so that the default context is used.

pid The ID of the process whose messages this handler


is to deal with, or 0 if the handler is for messages
from all processes.

input func Your input handler.

data Extra data to be passed to the input handler.

PtAppAddInput() returns a pointer to an input-handler ID, which


you’ll need if you want to remove the input handler later.
The prototype for an input handler is as follows:

int input proc( void *data,


pid t rcvid,
void *msg,
size t msglen );

The arguments are:

data A pointer to any extra data you want to pass to the input
handler.

rcvid The ID of the process that sent the message:


¯ In case of real processes under Neutrino, the input
function gets the rcvid — which is the value that
you’ll need for replying, just like the PID under
QNX 4. To retrieve the ID of the process, use
PtGetRcvidPid().
¯ Under QNX 4, the rcvid is the same as the PID, and
PtGetRcvidPid() is a macro that returns its argument:
#define PtGetRcvidPid( pid ) (pid)

msg A pointer to the message sent.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 353


Receiving QNX messages  2005, QNX Software Systems

msglen The size of the message buffer.

You can also declare the input handler to be of type


PtInputCallbackProcF t to take advantage of the prototype
checking done by the compiler.

☞ If your input handler changes the display, it should call PtFlush() to


make sure the display is updated.

Removing an input handler


To remove an input handler:

¯ Have it return something other than Pt CONTINUE.


Or

¯ Call PtAppRemoveInput(), passing it the application context


(NULL in Photon 1.1x) and the ID returned by PtAppAddInput().

Message buffer size


As described above, arguments to your input function include:

msg A pointer to an event buffer that was used to receive the


message.

msglen The size of the buffer.

This buffer might not be large enough to hold the entire message. One
way of handling this is to have the first two bytes of the message
indicate the message type and from that determine how big the
message should be. Once you know the message size, you can:

¯ Reread the entire message. Under QNX 4, this can be done by


calling Readmsg(). Under Neutrino, this can be done by calling
MsgReadv().
Or

354 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Receiving QNX messages

¯ Copy the part you’ve already received into a new buffer. Get the
rest of the message (by calling Readmsg() under QNX 4, or
MsgReadv() under Neutrino). Add the rest of the message to the
first part.

Alternatively, you can set the event buffer to be the size of the largest
message your application will receive (if known). This can be done by
calling PtResizeEventMsg(). You’d typically call this before you
expect to receive any messages.

☞ PtResizeEventMsg() won’t reduce the message buffer beyond a


certain minimum size. This is so that the widget library will continue
to function.

Example — logging error messages


The following code fragment shows how a nonspecific input handler
may be used to respond to error-logging messages from any process.
When one of these messages is received, the application displays the
message’s contents in a multiline text widget. (This example assumes
log message is declared elsewhere.)

int input proc(void *client data, pid t pid, void *msg,


size t msglen)
{
struct log message *log = (struct log message *)msg;

/* Only process log messages */


if (log->type == LOG MSG)
{
PtWidget t *text = (PtWidget t *)client data;
struct log message header;
int msg offset = offsetof(struct log message, msg);
int log msglen;
int status;

/* See if our entire header is in the buffer --


it should be */
if (msglen < msg offset)
{
/* Read in the whole header */
if (Readmsg(pid, 0, &header, msg offset) == -1)
{

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 355


Receiving QNX messages  2005, QNX Software Systems

status = errno;
Reply(pid, &status, sizeof(status));
return 0; /* bail out */
}
log = &header;
}

log msglen = msg offset+log->msg len;

/* See if the whole message is in the buffer */

if (msglen < log msglen)


{
struct log message *log msg =
(struct log message *)alloca(log msglen);

/* Read the remainder of the message into


space on the stack */

if (log msg == NULL || Readmsg(pid, 0, log msg,


log msglen) == -1)
{
status = errno;
Reply(pid, &status, sizeof(status));
return 0; /* bail out */
}
log = log msg;
}

add msg(text, log);


status = 0;
Reply(pid, &status, sizeof(status));
}

return Pt CONTINUE;
}

main(int argc, char *argv[])


{
union {
struct log message msg;
char msgbuf[1<<10];
} startup msg;
PtWidget t *window, *text;
PhDim t dim;
PtArg t arg[2];
int nargs;
int name;
PtInputId t *id;

356 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Receiving QNX messages

if ((name = qnx name attach(0, "logger")) == -1)


exit(EXIT FAILURE);

nargs = 0;
PtSetArg(&arg[nargs], Pt ARG WINDOW TITLE, "Error Log",
0); nargs++;
if ((window = PtAppInit(NULL, &argc, argv, nargs,
arg)) == NULL)
{
qnx name detach(0, name);
exit(EXIT FAILURE);
}
dim.w = 320;
dim.h = 240;
nargs = 0;
PtSetArg(&arg[nargs], Pt ARG DIM, &dim, 0); nargs++;
text = PtCreateWidget(PtMultiText, window, nargs, arg);

strcpy(startup msg.msg.msg, "Started error log");


startup msg.msg.msg len = strlen(startup msg.msg.msg);
startup msg.msg.msg severity = MSG INFO;
add msg(text, &startup msg.msg);

/* Set an input proc to receive from anybody */


id = PtAppAddInput(NULL, 0, input proc, text);

PtRealizeWidget(window);

PtMainLoop();
}

This application registers the input proc() function as an input handler


for handling non-Photon messages from any other process.
The input proc() function first checks the message type of the
incoming message. If the input handler isn’t responsible for this type
of message, it returns immediately. This is important because any
other nonspecific input handlers that were registered will be called as
well, and only one of them should respond to a given message.
If the type of message received is a log message, the function makes
sure that Photon has read the entire message into the Photon event
buffer. This can be determined by looking at the message length
provided as the msglen to the input handler. If part of the message
isn’t in the event buffer, a message buffer is allocated and Readmsg()
is called to get the whole message. The input proc() function then

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 357


Receiving QNX messages  2005, QNX Software Systems

calls add msg() to add the message to the text widget and replies to
the message.
When input proc() is complete, it returns the value Pt CONTINUE.
This instructs the Photon widget library not to remove the input
handler.

Example — replying to sin ver commands


Here’s an input handler that replies to messages sent by the sin ver
command:

#include <errno.h>
#include <sys/kernel.h>
#include <sys/psinfo.h>
#include <sys/sys msg.h>

typedef struct {
struct sysmsg hdr hdr;
} message t;

typedef struct {
struct sysmsg hdr reply hdr;
struct sysmsg version reply version;
} reply t;

/* For a PhAB app do the following two lines from the application
* initialization function.
* For a non-PhAB app do the following two lines from main() before
* calling PtMainLoop().
*/

/* Register as a process that has versions to report; sin ver will


* then send us version messages.
*/

qnx pflags( PPF SERVER, PPF SERVER, NULL, NULL);

/* Tell the main loop to call input function() when a non-photon


* message arrives.
*/
PtAppAddInput(NULL, 0, input function, NULL);

/*
* And now to handle the version request message from sin ver ...
*/

358 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

int
input function(void *data, pid t rcvid, void *msg, size t size)
{
message t *vmsg = (message t *) msg;
reply t reply;

if (vmsg->hdr.type == SYSMSG &&


vmsg->hdr.subtype == SYSMSG SUBTYPE VERSION) {
reply.hdr.status = EOK;
strcpy(reply.version.name, "My App");
strcpy(reply.version.date, DATE );
reply.version.version = 123; /* = 1.23 (i.e. version times 100) */
reply.version.letter = ’B’; /* will be 1.23B */
reply.version.more = 0; /* no more versions to report */
Reply(rcvid, &reply, sizeof(reply));
} else {
/* don’t recognize this message */
}

return(Pt CONTINUE);
}

Photon pulses
In addition to synchronous message-passing, Photon supports an
asynchronous method of communication called a pulse. A process
that wants to notify another process but doesn’t want to wait for a
reply can use a Photon pulse. For example, a server can use a pulse to
contact a client process in a situation where sending a message would
leave both SEND-blocked (and hence deadlocked).
The implementation of Photon pulses depends on the platform your
application uses — they were made to be portable.

Under QNX 4, a Photon pulse uses a proxy.


QNX 4 Under Neutrino, a Photon pulse uses Neutrino pulses.
In a future version of Photon for Neutrino, the functions may generate
Neutrino
either a Neutrino pulse or a realtime signal, depending on whether
your application is using a channel when you call PtPulseArmPid().

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 359


Photon pulses  2005, QNX Software Systems

Signals are cheaper — they don’t require a channel — but they don’t
obey the priorities of pulses.
If you want to make sure that it will be a pulse, call
PtChannelCreate() at the beginning of your application.

A Photon pulse is identified by a negative PID that can be used as the


pid argument to PtAppAddInput(). This PID is local to your
application. If you want another process to send pulses to you, you
must “arm” the pulse using PtPulseArmPid() or PtPulseArmFd().
This creates a PtPulseMsg t object that can be sent to the other
process in a message. The other process will then be able to send
pulses using the PtPulseDeliver() function.

In QNX 4, the PtPulseMsg t object is a pid t containing the PID


QNX 4 of the (virtual) proxy.
In Neutrino, PtPulseMsg t is a sigevent structure.
Neutrino In Neutrino, the bits in msg.sigev value.sival int that correspond to
NOTIFY COND MASK are clear, but can be set by the application.
For more information, see ionotify() in the Neutrino Library
Reference.

Let’s look at the code you’ll need to write to support pulses in a:

¯ Photon application that receives pulses

¯ Photon application that delivers pulses

¯ non-Photon application that delivers pulses

Photon application that receives a pulse


It’s the recipient of a Photon pulse that has to do the most preparation.
It has to:

1 Create the pulse.

360 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

2 Arm the pulse.

3 Send the pulse message to the process that will deliver it.

4 Register an input handler for the pulse message.

5 Deliver the pulse to itself, if necessary.

6 Disarm the pulse.

7 Destroy the pulse when it’s no longer needed.

The sections below discuss each step, followed by an example.

☞ Before exiting, the recipient process should tell the delivering process
to stop sending pulses.

Creating a pulse
To create a Photon pulse, call PtAppCreatePulse():

pid t PtAppCreatePulse( PtAppContext t app,


int priority );

The arguments are:

app The address of the application context, a structure that


manages all the data associated with this application. For
Photon 1.1x, this must be specified as NULL, so that the
default context is used.

priority The priority of the pulse. If this is -1, the priority of the
calling program is used.

PtAppCreatePulse() returns a pulse process ID, which is negative but


never -1. This is the receiver’s end of the pulse.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 361


Photon pulses  2005, QNX Software Systems

Arming a pulse
It might seem odd to arm the pulse and then send the pulse message to
the process that’s going to deliver it back to the application, but
arming it sets up a virtual proxy under QNX 4 if the other process is
on another node.

☞ There’s nothing wrong with having more than one process deliver the
same pulse, although the recipient won’t be able to tell which process
sent it.

The method of arming a pulse depends on how you’re going to send


the pulse message to the process that will be delivering it:

¯ If you’re using the QNX Sendfd() function or the Neutrino


MsgSendv() function, or if you have a file descriptor for the
process, call PtPulseArmFd()

¯ Otherwise, call PtPulseArmPid()

The prototype for PtPulseArmFd() is:

PtPulseMsgId t *PtPulseArmFd( PtAppContext t app,


pid t pulse,
int fd,
PtPulseMsg t *msg );

The arguments are:

app A pointer to the current application context (NULL in


Photon 1.1x).

pulse The pulse created by PtAppCreatePulse().

fd The file descriptor associated with the QNX I/O manager


or Neutrino resource manager.

msg A pointer to a pulse message that this function creates.


This is the deliverer’s end of the pulse, and we’ll need to
send it to that process, as described below.

362 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

This function returns a pointer to a pulse message ID, which you’ll


need later to disarm the pulse.
The prototype for PtPulseArmPid() is:
PtPulseMsgId t *PtPulseArmPid( PtAppContext t app,
pid t pulse,
pid t pid,
PtPulseMsg t *msg);

The parameters are similar to those for PtPulseArmFd(), except that


instead of the fd, you’ll pass:

¯ the ID of the process that will deliver the pulse if the process is on
the same node as the pulse recipient
or

¯ the virtual-circuit ID, if the process is on another node.

Sending the pulse message to the deliverer


The method you use to send the pulse message depends on the
process that will deliver the pulse:

¯ For a QNX I/O manager, there are several methods:


// If you’re dealing with Dev:
dev arm (fd, pulsemsg, DEV EVENT INPUT);

Or
// Create your own message format:
msg.pulsemsg = pulsemsg;
Sendfd (fd, &msg, &rmsg,
sizeof (msg), sizeof (rmsg));

Or
char buf[15];

sprintf (buf, "PROXY=%d", pulsemsg);


write (fd, buf, strlen(buf)+1);

¯ For a Neutrino resource manager:

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 363


Photon pulses  2005, QNX Software Systems

ionotify (fd, NOTIFY ACTION ARM, NOTIFY COND INPUT,


&pulsemsg);

¯ For any other type of QNX process:


// Create your own message format:
msg.pulsemsg = pulsemsg;
Send (pid, &msg, &rmsg,
sizeof (msg), sizeof (rmsg));

¯ For any other type of Neutrino process:


// Create your own message format:
msg.pulsemsg = pulsemsg;
MsgSendv (channel id, &msg, msg parts, &rmsg, rmsg parts);

Registering an input handler


Registering an input handler for the pulse is similar to registering one
for a message; see “Adding an input handler” earlier in this chapter.
Pass the pulse ID returned by PtAppCreatePulse() as the pid
parameter to PtAppAddInput().
The rcvid argument for the input handler won’t necessarily have the
same value as the pulse ID:

In QNX 4, it’s a proxy ID.


QNX 4 In Neutrino, it matches the pulse ID on the bits defined by
NOTIFY DATA MASK (see ionotify() in the Neutrino Library
Neutrino Reference), but the other bits will be taken from the Neutrino pulse or
signal that was received.

364 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

Delivering a pulse to yourself


If the application needs to send a pulse to itself, it can call
PtAppPulseTrigger():
int PtAppPulseTrigger( PtAppContext t app,
pid t pulse );

The parameters for this function are the application context (NULL in
Photon 1.1x), and the pulse ID returned by PtAppCreatePulse().

Disarming a pulse
When the pulse is no longer to be delivered by a process currently
doing so, you should call PtPulseDisarm() to clean up any resources
(such as a virtual proxy) allocated for the pulse:
void PtPulseDisarm( PtPulseMsgId t *mid );

The parameter to this function is the pulse message ID returned by


PtPulseArmFd() or PtPulseArmPid().
The pulse can be armed for delivery from another process, if
necessary.

Destroying a pulse
When your application no longer needs the pulse, it can be destroyed
by calling PtAppDeletePulse():
int PtAppDeletePulse( PtAppContext t app,
pid t pulse pid );

The parameters are the application context (NULL in Photon 1.1x),


and the pulse ID returned by PtAppCreatePulse().

Example
This is a goofy little application that receives Photon pulses; every
time it gets a pulse, it simply toggles the fill color of the base window.
First of all, here’s the application’s header file. It defines the global
variables and the structure for the messages sent from this application
to the pulse deliverer:

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 365


Photon pulses  2005, QNX Software Systems

/* Header "globals.h" for pulse recipient Application */

// Message types:

#define PULSE MSG 0


#define STOP PULSING 1

typedef struct my msg struct {


int msg type;
PtPulseMsg t id;
} MyMsg;

extern pid t pulse deliverer, pulse;


extern PtPulseMsgId t *pulse msg id;

Here’s the input handler for the pulse, and the application’s
initialization function:
/* Pulse recipient */
/* AppBuilder Photon Code Lib */
/* Version 1.13A */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/name.h>
#include <sys/kernel.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

/* Application Options string */


const char ApOptions[] =
AB OPTIONS ""; /* Add your options in the "" */

pid t pulse deliverer, pulse;


PtInputId t *input ID;
PtPulseMsgId t *pulse msg id;
PtPulseMsg t pulse msg;
int pulse on = 0;

366 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

PtInputCallbackProcF t pulse input proc;

int pulse input proc (void *client data, pid t pid,


void *msg, size t msglen)
{
PtArg t args[1];

// This pulse handler simply toggles the fill color


// for the base window.

if (pulse on) {
pulse on = 0;
PtSetArg (&args[0], Pt ARG FILL COLOR, Pg GREY, 0);
} else {
pulse on = 1;
PtSetArg (&args[0], Pt ARG FILL COLOR, Pg RED, 0);
}
PtSetResources (ABW base, 1, args);

return (Pt CONTINUE);


}

int
init app( int argc, char *argv[] )

MyMsg smsg;

/* eliminate ’unreferenced’ warnings */


argc = argc, argv = argv;

pulse deliverer = qnx name locate ( 0, "PulseDeliverer",


0, NULL);
if (pulse deliverer == -1)
{
perror ("Couldn’t find PulseDeliverer");
exit (EXIT FAILURE);
}

// Set up the pulse and arm it.

pulse = PtAppCreatePulse (NULL, -1);


pulse msg id = PtPulseArmPid ( NULL, pulse,
pulse deliverer,
&pulse msg );

// Send the pulse message to the process that


// will deliver it to us.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 367


Photon pulses  2005, QNX Software Systems

smsg.msg type = PULSE MSG;


smsg.id = pulse msg;
Send (pulse deliverer, &smsg, NULL,
sizeof (smsg), 0);

// Register the input handler for the pulse.

input ID = PtAppAddInput ( NULL, pulse, pulse input proc,


NULL);
return( Pt CONTINUE );
}

Here’s the callback that exits the application:

/* Callback that exits the pulse recipient */


/* AppBuilder Photon Code Lib */
/* Version 1.13A */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/kernel.h> // We need this for Send()

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
quit callback( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
MyMsg smsg;

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

// Tell the pulse deliverer to stop.

368 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

smsg.msg type = STOP PULSING;


smsg.id = 0;

Send (pulse deliverer, &smsg, NULL,


sizeof (smsg), 0);

// Disarm and destroy the pulse.

PtPulseDisarm (pulse msg id);


PtAppDeletePulse (NULL, pulse);

exit (EXIT SUCCESS);


return( Pt CONTINUE );
}

Photon application that delivers a pulse


A Photon application that’s going to deliver a pulse must:

¯ Have an input handler for messages from the application that’s


going to receive the pulses.

¯ Deliver the pulse as appropriate.

There’s an example after the descriptions of these steps.

Registering an input handler


The input handler for messages from the pulse recipient is created as
described in “Receiving QNX messages” earlier in this chapter. It will
need to handle messages that:

¯ contain the pulse message

¯ tell the deliverer to stop sending pulses

Save the rcvid from the message that contains the pulse message —
you’ll need it to deliver the pulse.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 369


Photon pulses  2005, QNX Software Systems

Delivering the pulse


A Photon application delivers a pulse by calling PtPulseDeliver():
int PtPulseDeliver( pid t rcvid,
PtPulseMsg t const *pulse );

The arguments are:

rcvid The ID of the process that’s to receive the pulse.

pulse A pointer to the pulse message created when the recipient


of the pulse called PtPulseArmFd() or PtPulseArmPid().

Example
This application is the Photon counterpart to the example given earlier
for the pulse recipient. It has a PtButton widget with a callback that
delivers a pulse. This button is disabled when the recipient tells this
application to stop delivering pulses.
The header file, globals.h defines the same message structure,
MyMsg and message types. Here’s the input handler for messages sent
by the pulse recipient, and the deliverer’s initialization function:
/* Pulse deliverer */
/* AppBuilder Photon Code Lib */
/* Version 1.13A */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/kernel.h> // We need this for Send()
#include <sys/name.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"

370 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Photon pulses

#include "proto.h"

/* Application Options string */


const char ApOptions[] =
AB OPTIONS ""; /* Add your options in the "" */

pid t pulse recipient;


PtPulseMsg t pulse msg;
PtInputId t *input id;

PtInputCallbackProcF t input func;

int input func ( void *data, pid t pid,


void *msg, size t msglen )
{
MyMsg received msg;
PtArg t args[1];

// Reply promptly! Remember the other process is


// SEND-blocked, so its UI is "hung", until you do.

if ( Reply (pid, NULL, 0) == -1)


{
perror ("Reply failed");
exit (-1);
}

received msg = *(MyMsg *)msg;

switch (received msg.msg type) {


case PULSE MSG:

// Save the pulse message and the pid of the


// process we’re going to deliver the pulse to.

pulse msg = received msg.id;


pulse recipient = pid;
break;

case STOP PULSING:

// Disable the button used to send pulses.

PtSetArg (&args[0], Pt ARG FLAGS,


Pt GHOST | !Pt SELECTABLE,
Pt GHOST | Pt SELECTABLE);
PtSetResources (ABW pulse button, 1, &args);
break;
}

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 371


Photon pulses  2005, QNX Software Systems

return (Pt CONTINUE);


}

int
init app( int argc, char *argv[] )

/* eliminate ’unreferenced’ warnings */


argc = argc, argv = argv;

if ( qnx name attach ( 0, "PulseDeliverer" ) == -1)


{
perror ("Couldn’t register myself as PulseDeliverer");
exit (EXIT FAILURE);
}

// Register an input handler for messages sent to us

input id = PtAppAddInput ( NULL, 0, input func, NULL);

return( Pt CONTINUE );
}

Finally, here’s the callback that delivers the pulse:

int
send pulse( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

PtPulseDeliver (pulse recipient, &pulse msg);

return( Pt CONTINUE );
}

☞ When you deliver a pulse by calling PtPulseDeliver(), it doesn’t


matter if the application is to run on QNX 4 or Neutrino — the code’s
the same.

372 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Processing signals

Non-Photon application that delivers a pulse


A non-Photon application that delivers a pulse is similar to a Photon
one, except that the non-Photon application needs to include
<photon/PtPulseDeliver.h>.
This header file includes a macro version of PtPulseDeliver() that
invokes the appropriate QNX or Neutrino functions. The application
doesn’t need to know which OS it’s running on, nor does it need to be
linked with the Photon libraries.

Processing signals
If your application needs to process signals, you’ll need to set up a
signal handler. The problem is that you can’t call Photon functions
from a signal handler because the widget library isn’t signal-safe or
reentrant.
To get around this problem, the Photon library includes a signal
handler. You register a signal-processing function, and Photon calls it
after

¯ Photon’s signal handler returns


AND

¯ all processing for the current widget is complete

!
CAUTION: By handling signals in this way, you’re not getting strict
realtime performance, since your signal-processing function isn’t
called right away.

Adding a signal-processing function


To add a signal-processing function, use the PtAppAddSignalProc()
function. You typically call this in

¯ your application’s initialization function


Or

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 373


Processing signals  2005, QNX Software Systems

¯ the setup function for a window

You’ll need to include <signal.h>.


The syntax for PtAppAddSignalProc() is as follows:

int PtAppAddSignalProc( PtAppContext t app,


sigset t const *set,
PtSignalProc t func,
void *data);

The arguments are as follows:

app The address of the application context, a structure that


manages all the data associated with this application. For
Photon 1.1x, this must be specified as NULL, so that the
default context is used.

set A pointer to the set of signals that should cause the


signal-processing function to be called. Use the
sigemptyset() and sigaddset() functions to build this set. See
the Watcom C Library Reference for more information.

func The signal-processing function.

data Any data to be passed to the function.

PtAppAddSignalProc() returns 0 on success, or -1 if an error occurs.


Your signal-processing function has the following prototype:

int signalProcFunctions (int signum


void *data);

The arguments are:

signum The number of the signal to be processed.

data The data parameter specified in the call to


PtAppAddSignalProc().

374 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Other I/O mechanisms

If you want the signal handler to remain installed, return


Pt CONTINUE. To remove it for the current signal, return Pt END (if
the function was registered for other signals, it’s still called if they’re
raised).

Removing a signal-processing function


To remove a signal-processing function:

¯ Call PtAppRemoveSignal() to remove one or all occurrences of a


(signal-processing function, data) pair.

¯ Return Pt END from the signal-processing function. If the function


was registered for more than one signal, it remains installed for
signals other than the one just processed.

!
CAUTION:
There’s another function, PtAppRemoveSignalProc() that removes all
the signal-processing functions for a given set of signals, but we don’t
recommend using it because it will remove handlers used internally
by the libraries.

Other I/O mechanisms


If your application needs to perform I/O such as reading from or
writing to a pipe, you should add an fd handler. An fd handler is a
function that’s called by the main event loop when a given file
descriptor (fd) is ready for input or output:

¯ To add an fd handler to your application, call PtAppAddFd() or


PtAppAddFdPri().

¯ To change the mode that’s of intereset to the fd handler, call


PtAppSetFdMode()

¯ To remove an fd handler, return Pt END from it or call


PtAppRemoveFd().

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 375


Lengthy operations  2005, QNX Software Systems

These functions are described in the Photon Library Reference.

☞ If your fd handler changes the display, it should call PtFlush() to


make sure the display is updated.

Lengthy operations
When you have to perform an operation that will take a long time to
execute, it’s not a good idea to implement the operation as a simple
callback. During the time the callback is executing, the widgets in
your application won’t repair damage and they won’t respond to user
inputs at all. You should develop a strategy for handling lengthy
operations within your application that involves returning from your
callback as quickly as possible.
Returning from your callback allows the widgets to continue to
update themselves visually. It also gives some visual feedback if the
user attempts to do anything. If you don’t want the user to be able to
perform any UI operations during this time, you should deactivate the
menu and command buttons. You can do this by setting the
Pt BLOCKED flag in the application window widget’s
Pt ARG FLAGS resource.
You might consider one of several different mechanisms for dealing
with lengthy operations.
If the operation can be easily broken down into small chunks, you
may wish to have a function that keeps track of the current state and
executes one small chunk of the operation at a time. You can then set
up a timer widget and attach it to a callback that invokes the function
whenever the timer goes off. Or you may call the function from within
a work procedure. These methods are especially effective for iterative
operations where the function may be executed once per iteration.
Operations that aren’t easily decomposed are harder to deal with. In
difficult cases (e.g. an operation that may take up to several minutes
or more to complete), you can use PtBkgdHandlerProcess() within a
loop, or spawn another process in the callback and have the other

376 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

process return its results to the application by sending it messages. In


this case, it’s very important to be able to monitor the operation’s
progress and give the user visual feedback.

☞ It’s safe to call PtBkgdHandlerProcess() in callbacks, work


procedures, and input procedures, but not in a widget’s Draw method
or a PtRaw widget’s drawing function.

The following functions process Photon events:

¯ PtAskQuestion()

¯ PtBkgdHandlerProcess()

¯ PtFileSelection()

¯ PtProcessEvent()

¯ PtSpawnWait()

Another difficult situation to deal with is when you wish to have your
program prompt the user for information before continuing. This is
usually handled by popping up a dialog for the user to enter the
required information. If you don’t want the user to be able to select
any other operations until the information has been provided, you
should create the dialog as a modal dialog. A modal dialog doesn’t
allow user input to go to any of the other widgets in the application.
To use a modal dialog to prompt for information, you have to provide
your own event-handling loop within the callback function.

Work procedures
A work procedure is run whenever there are no messages for your
application to respond to. In every iteration of the Photon
event-handling loop, this procedure is called if no messages have
arrived (rather than block on a Receive() waiting for more messages).
This procedure will be run very frequently, so it should be as short as
possible.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 377


Lengthy operations  2005, QNX Software Systems

☞ If your work procedure changes the display, it should call PtFlush() to


make sure the display is updated.

A work procedure is a callback function that takes a single void *


parameter, client data. This client data is data that you associate with
the work procedure when you register it with the widget library. You
should create a data structure for the work procedure that contains all
its state information and provide this as the client data.
You register, or add, a work procedure using the
PtAppAddWorkProc():
PtWorkProcId t *PtAppAddWorkProc(
PtAppContext t app context,
PtWorkProc t work func,
void *data );

The parameters are:

¯ app context — the address of the application context, a structure


that manages all the data associated with this application. For
Photon 1.1x, this must be specified as NULL, so that the default
context is used.

¯ func — the work procedure callback function

¯ client data — the data to be passed to the function when it’s


invoked.

PtAppAddWorkProc() returns a pointer to a PtWorkProcId t


structure that identifies the work procedure.
To remove a a work procedure when it’s no longer needed, call
PtAppRemoveWorkProc():
void PtAppRemoveWorkProc(
PtAppContext t app context,
PtWorkProcId t *WorkProc id );

passing it the same application context and the pointer returned by


PtAppAddWorkProc().

378 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

A practical example of the use of work procedures would be too long


to cover here, so we’ve provided a simple iterative example. The work
procedure counts to a large number, updating a label to reflect its
progress on a periodic basis.

#include <Pt.h>

typedef struct workDialog {


PtWidget t *widget;
PtWidget t *label;
PtWidget t *ok button;
} WorkDialog t;

typedef struct countdownClosure {


WorkDialog t *dialog;
int value;
int maxvalue;
int done;
PtWorkProcId t *work id;
} CountdownClosure t;

WorkDialog t *create working dialog(PtWidget t *parent)


{
PhDim t dim;
PtArg t arg[3];
int nargs;
PtWidget t *window, *group;
WorkDialog t *dialog =
(WorkDialog t *)malloc(sizeof(WorkDialog t));

if (dialog)
{
nargs = 0;
PtSetArg(&arg[nargs], Pt ARG WIN PARENT, parent, 0);
nargs++;
PtSetParentWidget(NULL);
dialog->widget = window =
PtCreateWidget(PtWindow, parent, nargs, arg);

nargs = 0;
PtSetArg(&arg[nargs], Pt ARG GROUP ORIENTATION,
Pt GROUP VERTICAL, 0); nargs++;
PtSetArg(&arg[nargs], Pt ARG GROUP VERT ALIGN,
Pt GROUP VERT CENTER, 0); nargs++;
group = PtCreateWidget(PtGroup, window, nargs, arg);

nargs = 0;
dim.w = 200;
dim.h = 100;

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 379


Lengthy operations  2005, QNX Software Systems

PtSetArg(&arg[nargs], Pt ARG DIM, &dim, 0); nargs++;


PtSetArg(&arg[nargs], Pt ARG TEXT STRING,
"Counter: ", 0); nargs++;
dialog->label = PtCreateWidget(PtLabel, group,
nargs, arg);

PtCreateWidget(PtSeparator, group, 0, NULL);

nargs = 0;
PtSetArg(&arg[nargs], Pt ARG TEXT STRING, "Stop", 0);
nargs++;
dialog->ok button = PtCreateWidget(PtButton, group,
1, arg);
}
return dialog;
}

int done(PtWidget t *w, void *client,


PtCallbackInfo t *call)
{
CountdownClosure t *closure =
(CountdownClosure t *)client;

call = call;

if (!closure->done) {
PtAppRemoveWorkProc(NULL, closure->work id);
}
PtDestroyWidget(closure->dialog->widget);
free(closure->dialog);
free(closure);
return (Pt CONTINUE);
}

int
count cb(void *data)
{
CountdownClosure t *closure =
(CountdownClosure t *)data;
char buf[64];
PtArg t arg[1];
int finished = 0;

if ( closure->value++ == 0 || closure->value %
1000 == 0 )
{
sprintf(buf, "Counter: %d", closure->value);
PtSetArg(&arg[0], Pt ARG TEXT STRING, buf, 0);
PtSetResources(closure->dialog->label, 1, arg);
}

380 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

if ( closure->value == closure->maxvalue )
{
closure->done = finished = 1;
PtSetArg(&arg[0], Pt ARG TEXT STRING, "Done", 0);
PtSetResources(closure->dialog->ok button, 1,
arg);
}

return finished ? Pt END : Pt CONTINUE;


}

int push button cb(PtWidget t *w, void *client,


PtCallbackInfo t *call)
{
PtWidget t *parent = (PtWidget t *)client;
WorkDialog t *dialog;

w = w; call = call;

dialog = create working dialog(parent);

if (dialog)
{
CountdownClosure t *closure =
(CountdownClosure t *)
malloc(sizeof(CountdownClosure t));

if (closure)
{
PtWorkProcId t *id;
PtArg t arg[3];

closure->dialog = dialog;
closure->value = 0;
closure->maxvalue = 200000;
closure->done = 0;
closure->work id = id =
PtAppAddWorkProc(NULL, count cb, closure);

PtAddCallback(dialog->ok button, Pt CB ACTIVATE,


done, closure);
PtRealizeWidget(dialog->widget);
}
}
return (Pt CONTINUE);
}

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


{

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 381


Lengthy operations  2005, QNX Software Systems

PhDim t dim;
PtArg t arg[4];
PtWidget t *window;
PtCallback t callbacks[] = {{push button cb, NULL}};

dim.w = 200;
dim.h = 100;
PtSetArg(&arg[0], Pt ARG DIM, &dim, 0);
if ((window = PtAppInit(NULL, &argc, argv, 1, arg))
== NULL) exit(1);

callbacks[0].data = window;
PtSetArg(&arg[0], Pt ARG TEXT STRING, "Count Down...", 0);
PtSetArg(&arg[1], Pt ARG TEXT FONT, "helv14B", 0);
PtSetArg(&arg[2], Pt CB ACTIVATE, callbacks,
sizeof(callbacks)/sizeof(PtCallback t));
PtCreateWidget(PtButton, window, 3, arg);

PtRealizeWidget(window);

PtMainLoop();
return (EXIT SUCCESS);
}

When the pushbutton is pressed, the callback attached to it creates a


working dialog and adds a work procedure, passing a closure
containing all the information needed to perform the countdown and
to clean up when it’s done.
The closure contains a pointer to the dialog, the current counter, and
the value to count to. When the value is reached, the work procedure
changes the label on the dialog’s button and attaches a callback that
will tear down the entire dialog when the button is pressed. Upon
such completion, the work procedure returns Pt END in order to get
removed.
The done() function is called if the user stops the work procedure, or
if it has completed. This function destroys the dialog associated with
the work procedure and removes the work procedure if it was stopped
by the user (i.e. it did not run to completion).
If you run this example, you may discover one of the other features of
work procedures — they preempt one another. When you add a new
work procedure, it preempts all others. The new work procedure will
be the only one run until it has completed or is removed. After that,

382 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

the work procedure that was previously running resumes. This is


illustrated in the above example if the user presses the Count Down...
button before a countdown is finished. A new countdown dialog is
created, and that countdown runs to the exclusion of the first until it’s
done.
The granularity for this preemption is at the function call level. When
the callback function for a work procedure returns, that work
procedure may be preempted by another work procedure.

Timers
If you wish to schedule your own operations at particular time
intervals, or if you just want to implement a time-out or trigger an
event at a particular time, you may want to have a timer-based
callback function. The easiest way to provide this is to make use of
the PtTimer widget. See the Widget Reference for more information.

☞ When you create a PtTimer widget in PhAB, it appears as a black


box. The box doesn’t appear when you run the application; it’s just a
placeholder.
PtTimer is easy to use, but doesn’t give accurate timer events. In
particular, it doesn’t guarantee a constant repeat rate; since the
repetition is handled by rearming the timer for each event, any delays
in handling the events accumulate. Kernel timers guarantee an
accurate repeat rate even if your application can’t keep up with them.

Modal dialogs
To create a modal dialog, you have to create a new PtWindow widget,
normally as a child of the main application window.
To activate the modal dialog, you have to realize the dialog widget
and block all the other window widgets in the application. To block a
widget, set the Pt BLOCKED flag in the widget’s Pt ARG FLAGS
resource. This affects the widget and all its descendants that aren’t
windows.

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 383


Lengthy operations  2005, QNX Software Systems

After the modal dialog has been activated, you process Photon events
by repeatedly calling PtProcessEvent() until a termination condition
is met.
When the operation associated with the modal dialog is completed or
aborted, you have to dismiss the dialog. To do so:

1 Unblock any window widgets that you blocked when you


created the dialog.

2 Destroy or unrealize the dialog itself.

To unblock a widget, clear its Pt BLOCKED flag.


We can easily change our previous example of work procedures so
that its progress dialog behaves as a modal dialog. A flag is added to
the callback closure to indicate that the work has been completed or
aborted. The done() callback is altered to set this flag rather than free
the closure:

int done(PtWidget t *w, void *client,


PtCallbackInfo t *call)
{
CountdownClosure t *closure =
(CountdownClosure t *)client;

call = call;

if (!closure->done) {
PtAppRemoveWorkProc(NULL, closure->work id);
}
PtDestroyWidget(closure->dialog->widget);
free(closure->dialog);

// New: Mark the dialog as destroyed instead of


// destroying the closure structure. This signals the
// end of the PtProcessEvent() loop.
closure->destroyed = 1;
return (Pt CONTINUE);
}

Here’s a little routine that we’ll use to block or unblock the windows
in the application:

void BlockWindows( int block, PtWidget t *leave alone )

384 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

{
PtWidget t *widget;
PtArg t args;

// This function blocks all top-level widgets that


// are windows, except for the given widget.
PtSetArg( &args, Pt ARG FLAGS, block ? Pt BLOCKED : 0,
Pt BLOCKED );
widget = NULL;
while( NULL != (widget = PtNextTopLevelWidget( widget )))
{
if ((widget != leave alone) &&
(PtWidgetIsClass( widget, PtWindow )))
PtSetResources( widget, 1, &args );
}
}

PtNextTopLevelWidget() is a function that gets a pointer to the next


top-level widget. For more information, see the Photon Library
Reference.
All that remains at this point is to change the push button cb()
callback function so that it finds which widgets to block and blocks
them before realizing the progress dialog.
After the progress dialog is realized, it loops until the termination flag
in the closure has been set, processing Photon events on each iteration
of the loop. Once the work has terminated, the closure is then freed
and all the blocked widgets are unblocked.
Here’s the new version of the push button cb() callback function:
int push button cb(PtWidget t *w, void *client,
PtCallbackInfo t *call)
{
PtWidget t *parent = (PtWidget t *)client;
WorkDialog t *dialog;

// New: The count for PtModalStart() / PtModalEnd()


int count;

w = w; call = call;

dialog = create working dialog(parent);

if (dialog)
{

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 385


Lengthy operations  2005, QNX Software Systems

CountdownClosure t *closure =
(CountdownClosure t *)
malloc(sizeof(CountdownClosure t));

if (closure)
{
PtWorkProcId t *id;
PtArg t arg[3];

closure->dialog = dialog;
closure->value = 0;
closure->maxvalue = 200000;
closure->done = 0;

// New: Initialize the destroyed flag


closure->destroyed = 0;
closure->work id = id =
PtAppAddWorkProc(NULL, count cb, closure);

PtAddCallback(dialog->ok button, Pt CB ACTIVATE,


done, closure);
PtRealizeWidget(dialog->widget);

// New: Block all the windows except the dialog,


// process events until the dialog is closed,
// and then unblock all the windows.

BlockWindows (1, dialog->widget);

count = PtModalStart();
while( !closure->destroyed) {
PtProcessEvent();
}
PtModalEnd( count );
free (closure);

BlockWindows (0, dialog->widget);

}
}
return (Pt CONTINUE);
}

Here’s the new version of the whole program:

#include <Pt.h>

typedef struct workDialog {


PtWidget t *widget;

386 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

PtWidget t *label;
PtWidget t *ok button;
} WorkDialog t;

typedef struct countdownClosure {


WorkDialog t *dialog;
int value;
int maxvalue;
int done;
// New: a flag that indicates when the dialog
// is destroyed
int destroyed;
PtWorkProcId t *work id;
} CountdownClosure t;

void BlockWindows( int block, PtWidget t *leave alone )


{
PtWidget t *widget;
PtArg t args;

// This function blocks all top-level widgets that


// are windows, except for the given widget.
PtSetArg( &args, Pt ARG FLAGS, block ? Pt BLOCKED : 0,
Pt BLOCKED );
widget = NULL;
while( NULL != (widget = PtNextTopLevelWidget( widget )))
{
if ((widget != leave alone) &&
(PtWidgetIsClass( widget, PtWindow )))
PtSetResources( widget, 1, &args );
}
}

WorkDialog t *create working dialog(PtWidget t *parent)


{
PhDim t dim;
PtArg t arg[3];
int nargs;
PtWidget t *window, *group;
WorkDialog t *dialog =
(WorkDialog t *)malloc(sizeof(WorkDialog t));

if (dialog)
{
nargs = 0;
PtSetArg(&arg[nargs], Pt ARG WIN PARENT, parent, 0);
nargs++;
PtSetParentWidget(NULL);
dialog->widget = window =
PtCreateWidget(PtWindow, parent, nargs, arg);

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 387


Lengthy operations  2005, QNX Software Systems

nargs = 0;
PtSetArg(&arg[nargs], Pt ARG GROUP ORIENTATION,
Pt GROUP VERTICAL, 0); nargs++;
PtSetArg(&arg[nargs], Pt ARG GROUP VERT ALIGN,
Pt GROUP VERT CENTER, 0); nargs++;
group = PtCreateWidget(PtGroup, window, nargs, arg);

nargs = 0;
dim.w = 200;
dim.h = 100;
PtSetArg(&arg[nargs], Pt ARG DIM, &dim, 0); nargs++;
PtSetArg(&arg[nargs], Pt ARG TEXT STRING,
"Counter: ", 0); nargs++;
dialog->label = PtCreateWidget(PtLabel, group,
nargs, arg);

PtCreateWidget(PtSeparator, group, 0, NULL);

nargs = 0;
PtSetArg(&arg[nargs], Pt ARG TEXT STRING, "Stop", 0);
nargs++;
dialog->ok button = PtCreateWidget(PtButton, group,
1, arg);
}
return dialog;
}

int done(PtWidget t *w, void *client,


PtCallbackInfo t *call)
{
CountdownClosure t *closure =
(CountdownClosure t *)client;

call = call;

if (!closure->done) {
PtAppRemoveWorkProc(NULL, closure->work id);
}
PtDestroyWidget(closure->dialog->widget);
free(closure->dialog);

// New: Mark the dialog as destroyed instead of


// destroying the closure structure. This signals the
// end of the PtProcessEvent() loop.
closure->destroyed = 1;
return (Pt CONTINUE);
}

int

388 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

count cb(void *data)


{
CountdownClosure t *closure =
(CountdownClosure t *)data;
char buf[64];
PtArg t arg[1];
int finished = 0;

if ( closure->value++ == 0 || closure->value %
1000 == 0 )
{
sprintf(buf, "Counter: %d", closure->value);
PtSetArg(&arg[0], Pt ARG TEXT STRING, buf, 0);
PtSetResources(closure->dialog->label, 1, arg);
}

if ( closure->value == closure->maxvalue )
{
closure->done = finished = 1;
PtSetArg(&arg[0], Pt ARG TEXT STRING, "Done", 0);
PtSetResources(closure->dialog->ok button, 1,
arg);
}

return finished ? Pt END : Pt CONTINUE;


}

int push button cb(PtWidget t *w, void *client,


PtCallbackInfo t *call)
{
PtWidget t *parent = (PtWidget t *)client;
WorkDialog t *dialog;

// New: The count for PtModalStart() / PtModalEnd()


int count;

w = w; call = call;

dialog = create working dialog(parent);

if (dialog)
{
CountdownClosure t *closure =
(CountdownClosure t *)
malloc(sizeof(CountdownClosure t));

if (closure)
{
PtWorkProcId t *id;
PtArg t arg[3];

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 389


Lengthy operations  2005, QNX Software Systems

closure->dialog = dialog;
closure->value = 0;
closure->maxvalue = 200000;
closure->done = 0;

// New: Initialize the destroyed flag


closure->destroyed = 0;
closure->work id = id =
PtAppAddWorkProc(NULL, count cb, closure);

PtAddCallback(dialog->ok button, Pt CB ACTIVATE,


done, closure);
PtRealizeWidget(dialog->widget);

// New: Block all the windows except the dialog,


// process events until the dialog is closed,
// and then unblock all the windows.

BlockWindows (1, dialog->widget);

count = PtModalStart();
while( !closure->destroyed) {
PtProcessEvent();
}
PtModalEnd( count );
free (closure);

BlockWindows (0, dialog->widget);

}
}
return (Pt CONTINUE);
}

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


{
PhDim t dim;
PtArg t arg[4];
PtWidget t *window;
PtCallback t callbacks[] = {{push button cb, NULL
}
};

dim.w = 200;
dim.h = 100;
PtSetArg(&arg[0], Pt ARG DIM, &dim, 0);
if ((window = PtAppInit(NULL, &argc, argv, 1, arg))
== NULL) exit(1);

390 Chapter 16 ¯ Interprocess Communication and Lengthy Operations September 20,


2005
 2005, QNX Software Systems Lengthy operations

callbacks[0].data = window;
PtSetArg(&arg[0], Pt ARG TEXT STRING, "Count Down...", 0);
PtSetArg(&arg[1], Pt ARG TEXT FONT, "helv14B", 0);
PtSetArg(&arg[2], Pt CB ACTIVATE, callbacks,
sizeof(callbacks)/sizeof(PtCallback t));
PtCreateWidget(PtButton, window, 3, arg);

PtRealizeWidget(window);

PtMainLoop();
return (EXIT SUCCESS);
}

September 20, 2005Chapter 16 ¯ Interprocess Communication and Lengthy Operations 391


Chapter 17
Raw Drawing and Animation

In this chapter. . .
PtRaw widget 395
Color 403
Arcs, ellipses, polygons, and rectangles 403
Lines, pixels, and pixel arrays 411
Text 411
Bitmaps 412
Images 413
Animation 419

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 393


 2005, QNX Software Systems PtRaw widget

PtRaw widget
The routines in Photon’s Pg library are the lowest-level drawing
functions. They’re used by the widget library to draw the widgets.
You can use the Pg functions from a Photon application, but your
application will need to:

¯ handle any interaction with the user

¯ determine when the drawing is damaged (for example, when it’s


uncovered, or when the user moves the window)

¯ repair the drawing whenever it’s damaged

☞ You should use widgets whenever possible because they do all of the
above themselves.

If your application must do its own drawing, you should use the
PtRaw widget. It does the following:

1 Tells the application what has been damaged.

2 Flushes the drawing buffer almost whenever necessary. (You


should flush the buffer explicitly; for example, before a blitting
operation. Blitting shifts a rectangular area of your drawing by
some distance; you want your drawing to be up-to-date before
this happens.)

To create a PtRaw widget in PhAB, click on its icon in the widget bar:

Position it where you want your drawing to appear.


You can provide up to four functions for the PtRaw widget. They’re
called in the order given below when the widget is realized, and are
then called as necessary:

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 395


PtRaw widget  2005, QNX Software Systems

Pt ARG RAW INIT F


An initialization function that’s called before the widget’s
extent is calculated.
Pt ARG RAW EXTENT F
If provided, this is used to calculate the widget’s extent when
the widget is moved or resized.
Pt ARG RAW CONNECT F
Called as the last stage in realizing the widget, just before any
required regions are created.
Pt ARG RAW DRAW F
Does the drawing.

Most of the time you’ll need to specify only the drawing function (see
below). You can use PhAB’s function editor (described in the Editing
Resources and Callbacks in PhAB chapter) to edit these resources —
but you must give the raw widget a unique instance name first. You
can also set these resources in your application’s code; for more
information, see “Function resources” in the Manipulating Resources
in Application Code chapter.
For information on PtRaw’s resources, see the Photon Widget
Reference.

Raw drawing function


When you create a PtRaw widget in PhAB and edit its
Pt ARG RAW DRAW F function, you’ll see default code like this:
void my raw draw fn( PtWidget t *widget,
PhTile t *damage )
{
PtSuperClassDraw( PtBasic, widget, damage );
}

The call to PtSuperClassDraw() (described in the Building Custom


Widgets guide) invokes PtBasic’s draw function, which draws the
raw widget’s borders, fills the widget, and so on, as specified by its

396 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems PtRaw widget

resources. The raw widget can do all this by itself, but using
PtSuperClassDraw() reduces the complexity of the raw drawing
function.
There are several things to consider in the raw drawing function:
¯ You’ll need to know the raw widget’s canvas.
¯ The origin for the drawing primitives is the top left corner of the
canvas of the raw widget’s parent, not the raw widget itself. You’ll
need to translate the coordinates.
¯ The raw widget can draw beyond its canvas, but it’s not a good
idea. You should set up clipping in the drawing function.
¯ The drawing function is passed a list of damaged areas that can be
used to speed up repairs.
¯ For raw widgets whose contents change dynamically, you can
define a model that describes what to draw.
These are described below, followed by some examples of simple
drawing functions.

☞ Don’t call PtBkgdHandlerProcess() in a PtRaw widget’s drawing


function.
Don’t change any other widget in any way (creating, destroying,
setting resources, and so on) in a raw widget’s drawing function. It’s
safe to get resources from other widgets.
Don’t call the drawing function directly from your program. Instead,
damage the widget by calling PtDamageWidget(), and let the library
call the drawing function.

Determining the raw widget canvas


You can determine the raw widget’s canvas by calling
PtBasicWidgetCanvas() as follows:
PhRect t raw canvas;

PtBasicWidgetCanvas (widget, &raw canvas);

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 397


PtRaw widget  2005, QNX Software Systems

You’ll need this canvas to perform any required translations and


clipping.

Translating coordinates
The origin for the drawing primitives is the upper left corner of the
raw widget’s parent’s canvas. You’ll probably find it easier to use the
upper left corner of the raw widget’s canvas as the origin.
Once you’ve determined the raw widget’s canvas, you can do one of
the following:

¯ Add the coordinates of the upper left corner of the raw widget’s
canvas to any coordinates passed to the drawing primitives. For
example, to draw an ellipse centered at (80, 60) relative to the raw
widget’s canvas:
PhPoint t c1 = { 80, 60 };
PhPoint t r = { 72, 52 };

c1.x += raw canvas.ul.x;


c1.y += raw canvas.ul.y;
PgSetFillColor(Pg YELLOW);
PgDrawEllipse ( &c1, &r, Pg DRAW FILL );

This is the preferred method.

¯ You can set the translation by calling


PgSetTranslation(), passing to it the upper left corner of the raw
widget’s canvas:
PhPoint t c1 = { 80, 60 };
PhPoint t r = { 72, 52 };

PgSetTranslation (&raw canvas.ul, Pg RELATIVE);

PgSetFillColor(Pg YELLOW);
PgDrawEllipse ( &c1, &r, Pg DRAW FILL );

398 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems PtRaw widget

☞ Be sure to restore the old translation before leaving the raw widget’s
drawing function. Here’s one way to do it:
/* Restore the translation by subtracting the
coordinates of the raw widget’s canvas. */

raw canvas.ul.x *= -1;


raw canvas.ul.y *= -1;
PgSetTranslation (&raw canvas.ul, Pg RELATIVE);

Clipping
As mentioned above, it’s possible to draw beyond the raw widget’s
extent in its drawing function, but it’s not a good thing to do:

¯ It can mess up the rest of your application’s interface.

¯ If the raw drawing beyond the raw widget’s extent is damaged but
the raw widget itself isn’t, the raw widget’s drawing function isn’t
called, so the damage won’t be repaired.

It’s possible to write the drawing function so that clipping isn’t


needed, but it can make your code more complicated. For example, if
you try to write text that extends beyond the raw widget’s canvas, you
might need to draw partial letters. You’ll also have to consider what
happens if the user changes the size of the raw widget.
It’s much easier to use PtClipAdd() (described in the Building Custom
Widgets guide) to set the clipping area to be the raw widget’s canvas
and let the graphics driver restrict the drawing:

PtClipAdd ( widget, &raw canvas);

Before leaving the drawing function, call PtClipRemove() (also


described in Building Custom Widgets) to reset the clipping area:

PtClipRemove ();

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 399


PtRaw widget  2005, QNX Software Systems

Using damage tiles


If your raw widget’s drawing function takes a lot of time, you might
not want to redraw the entire canvas when a small portion of it has
been damaged. You can speed up the repairs by using the drawing
function’s damage argument.
The damage argument is a pointer to a linked list of PhTile t
structures, each of which includes these members:

rect A PhRect t structure that defines the damaged area.

next A pointer to the next tile in the list.

The damaged areas are relative to the raw widget’s parent. At least
one of them intersects the raw widget, but some of them might not.
If there’s more than one tile in the linked list, the first one covers the
entire area covered by the rest. Either use the first tile and ignore the
rest, or ignore the first and use the rest:
void rawDrawFunction (PtWidget t *widget,
PhTile t *damage)
{
if (damage-> != NULL) {

// If there’s more than one tile, skip the first.

damage = damage->next;
}

while (damage != NULL) {

// Examine ’damage’ to see if any drawing


// needs doing:
// damage->rect.ul.x, damage->rect.ul.y,
// damage->rect.lr.x, damage->rect.lr.y

.
.
.
damage = damage->next; // Go on the the next tile.
}
}

400 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems PtRaw widget

Using a model for more complex drawing


If the contents of the raw widget are static, you can call the Pg
drawing primitives directly from the raw drawing function. If the
contents are dynamic, you’ll need to define a data structure or model
that describes them.
The structure of the model depends on your application; the raw
drawing function must be able to traverse the model and draw the
required graphics. Use the raw widget’s Pt ARG USER DATA
resource to save a pointer to the model.

Examples of simple PtRaw drawing functions


This drawing function draws a couple of ellipses, one of which is
clipped:

void my raw draw fn( PtWidget t *widget,


PhTile t *damage )
{
PhRect t raw canvas;
PhPoint t c1 = { 80, 60 };
PhPoint t c2 = { 30, 210 };
PhPoint t r = { 72, 52 };

PtSuperClassDraw( PtBasic, widget, damage );


PtBasicWidgetCanvas(widget, &raw canvas);

/* Set the clipping area to be the raw widget’s


canvas. */

PtClipAdd ( widget, &raw canvas);

/* Draw the ellipses. */

c1.x += raw canvas.ul.x;


c1.y += raw canvas.ul.y;
PgSetFillColor(Pg YELLOW);
PgDrawEllipse ( &c1, &r, Pg DRAW FILL );

c2.x += raw canvas.ul.x;


c2.y += raw canvas.ul.y;
PgSetFillColor(Pg RED);
PgDrawEllipse ( &c2, &r, Pg DRAW FILL );

/* Reset the clipping area. */

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 401


PtRaw widget  2005, QNX Software Systems

PtClipRemove ();
}

This function is the same, but it sets the translation:

void my raw draw fn( PtWidget t *widget,


PhTile t *damage )
{
PhRect t raw canvas;
PhPoint t c1 = { 80, 60 };
PhPoint t c2 = { 30, 210 };
PhPoint t r = { 72, 52 };

PtSuperClassDraw( PtBasic, widget, damage );


PtBasicWidgetCanvas(widget, &raw canvas);

/* Set the clipping area to be the raw widget’s


canvas. */

PtClipAdd ( widget, &raw canvas);

/* Set the translation so that drawing operations


are relative to the raw widget’s canvas. */

PgSetTranslation (&raw canvas.ul, Pg RELATIVE);

/* Draw the ellipses. */

PgSetFillColor(Pg YELLOW);
PgDrawEllipse ( &c1, &r, Pg DRAW FILL );

PgSetFillColor(Pg RED);
PgDrawEllipse ( &c2, &r, Pg DRAW FILL );

/* Restore the translation by subtracting the


coordinates of the raw widget’s canvas. */

raw canvas.ul.x *= -1;


raw canvas.ul.y *= -1;
PgSetTranslation (&raw canvas.ul, Pg RELATIVE);

/* Reset the clipping area. */

PtClipRemove ();
}

402 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Arcs, ellipses, polygons, and rectangles

Color
Colors are specified in Photon with the PgColor t type, a 32-bit
Red-Green-Blue (RGB) representation:

Reserved Red Green Blue


0000 0000 rrrr rrrr gggg gggg bbbb bbbb

Macros for the most commonly used colors are defined in


<photon/Pg.h>.
Although PgColor t uses 32 bits, only 24 bits are used per color.
This representation is called true color. Photon is a true-color
windowing system; it uses this 24-bit RGB representation internally.
Most graphics cards currently use true color (24 bits) or high color
(16 bits). However, some graphics drivers will take advantage the
palette on older palette-based cards.

Arcs, ellipses, polygons, and rectangles


Photon supports several simple, dual-purpose draw primitives:

¯ arcs

¯ ellipses

¯ polygons

¯ rectangles

¯ rounded rectangles

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 403


Arcs, ellipses, polygons, and rectangles  2005, QNX Software Systems

☞ Don’t use these drawing primitives in an interface that uses widgets;


widgets redisplay themselves when damaged, so anything drawn on
top of them will disappear. To display arcs, lines, etc. in an interface:

¯ Create a PtRaw widget and call the primitives in its draw function.
See the section on the PtRaw widget earlier in this chapter.

¯ Use the corresponding PtArc, PtLine, etc. widget. For more


information, see the Photon Widget Reference.

By using each primitive’s flags, you can easily draw an outline


(stroke), draw the filled “inside” (fill), or draw both as a filled outline.
The current fill and stroke state are used.

To: Set flags to:


Fill the primitive with the fill state Pg DRAW FILL
Outline the primitive with the stroke Pg DRAW STROKE
state
Fill the primitive with the fill state, Pg DRAW FILL STROKE
then outline it with the stroke state

Rectangles
Rectangles are drawn using the current graphics context with the
PgDrawIRect() and PgDrawRect() functions.
PgDrawRect() uses a PhRect t structure for the rectangle
coordinates, while PgDrawIRect() lets you specify the coordinates
individually.
The following example draws a blue, filled rectangle with no border:
void DrawFillRect( void )
{
PgSetFillColor( Pg BLUE );
PgDrawIRect( 8, 8, 152, 112, Pg DRAW FILL );

404 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Arcs, ellipses, polygons, and rectangles

The above function DrawFillRect() could also be written using


PgDrawRect():

void DrawFillRect( void )


{
PhRect t rect = {
{ 8, 8 }, { 152, 112 }
};

PgSetFillColor( Pg BLUE );
PgDrawRect( &rect, Pg DRAW FILL );
}

Use whichever method seems more natural for the code you’re
writing.
The following example will draw a white, unfilled rectangle border
against a black background:

void DrawStrokeRect( void )


{
PgSetStrokeColor( Pg WHITE );
PgDrawIRect( 8, 8, 152, 112, Pg DRAW STROKE );
}

Now we’ll fill the rectangle with blue:

void DrawFillStrokeRect( void )


{
PgSetFillColor( Pg BLUE );
PgSetStrokeColor( Pg WHITE );
PgDrawIRect( 8, 8, 152, 112, Pg DRAW FILL STROKE );
}

Rounded rectangles
Rounded rectangles are programmed almost the same way as
rectangles. You use PgDrawRoundRect(), with a PhPoint t
parameter to indicate, in pixels, the roundness of the rectangle

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 405


Arcs, ellipses, polygons, and rectangles  2005, QNX Software Systems

corners. The radii PhPoint t will be truncated to the rectangle’s


sides.
The following example will draw a black rounded rectangle with five
pixels worth of rounding at the corners:

void DrawStrokeRoundRect( void )


{
PhRect t rect = {
{ 20, 20 },
{ 100, 100 }
};
PhPoint t radii = { 5, 5 };

PgSetStrokeColor( Pg BLACK );
PgDrawRoundRect( &rect, &radii, Pg DRAW STROKE );
}

Beveled boxes
A beveled box is a special type of rectangle. If you set flags to
Pg DRAW FILL, the area of the beveled box is filled with the fill state.
If you set flags to Pg DRAW STROKE, the top and left edges are
drawn with the stroke state and the bottom and left edges are drawn
with an extra color that’s passed as one of the parameters. There’s
also a parameter to let you set the “depth” of the bevel.
The following example will draw a beveled box filled with dark grey,
with a green and red bevel four pixels wide:

void DrawBevelBox( void )


{
PhRect t r = { 8, 8, 152, 112 };
PgSetFillColor( Pg DGREY );
PgSetStrokeColor( Pg RED );
PgDrawBevelBox( &r, Pg GREEN, 4, Pg DRAW FILL STROKE );
}

406 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Arcs, ellipses, polygons, and rectangles

Polygons
You can create polygons by specifying an array of PhPoint t points.
If you use Pg CLOSED as part of the flags, the last point is
automatically connected to the first point, closing the polygon. You
can also specify points relative to the first point (using
Pg POLY RELATIVE).
The following example will draw a blue-filled hexagon with a white
outline:

void DrawFillStrokePoly( void )


{
PhPoint t start point = { 0, 0 };
int num points = 6;
PhPoint t points[6] = {
{ 32,21 }, { 50,30 }, { 50,50 },
{ 32,59 }, { 15,50 }, { 15,30 }
};

PgSetFillColor( Pg BLUE );
PgSetStrokeColor( Pg WHITE );
PgDrawPolygon( points, num points, start point,
Pg DRAW FILL STROKE | Pg CLOSED );
}

Overlapping polygons
Polygons that overlap themselves are filled using the so-called
even-odd rule: if an area overlaps an odd number of times, it isn’t
filled. Another way of looking at this is to draw a horizontal line
across the polygon. As you travel along this line and cross the first
line, you’re inside the polygon; as you cross the second line, you’re
outside. As an example, consider a simple polygon:

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 407


Arcs, ellipses, polygons, and rectangles  2005, QNX Software Systems

Filling a simple polygon.

This rule can be extended for more complicated polygons:

¯ When you cross an odd number of lines, you’re inside the polygon,
so the area is filled.

¯ When you cross an even number of lines, you’re outside the


polygon, so the area isn’t filled

Filling an overlapping polygon.

408 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Arcs, ellipses, polygons, and rectangles

☞ The even-odd rule applies to both the PgDrawPolygon() and


PgDrawPolygonmx() functions.

Arcs, circles, chords, and pies


The PgDrawArc() function can be used for drawing:

¯ arcs

¯ circles

¯ ellipses

¯ elliptical arcs

¯ chords

¯ pie slices

The start and end angles of arc segments are specified in binary
gradations (bi-grads), with 65536 bi-grads in a complete circle.
To draw a full circle or ellipse, specify the same value in bi-grads for
the start and end angles. For example:

void DrawFullCurves( void )


{
PhPoint t circle center = { 150, 150 },
ellipse center = { 150, 300 };
PhPoint t circle radii = { 100, 100 },
ellipse radii = { 100, 50 };

// Draw a white, unfilled circle.


PgSetStrokeColor( Pg WHITE );
PgDrawArc( &circle center, &circle radii, 0, 0,
Pg DRAW STROKE | Pg ARC );

// Draw an ellipse with a white outline, filled


// with black.
PgSetFillColor( Pg BLACK );
PgDrawArc( &ellipse center, &ellipse radii, 0, 0,
Pg DRAW FILL STROKE | Pg ARC );
}

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 409


Arcs, ellipses, polygons, and rectangles  2005, QNX Software Systems

To draw a chord (a curve with the end points connected by a straight


line), add Pg ARC CHORD to the flags parameter. For example:

void DrawChord( void )


{
PhPoint t center = { 150, 150 };
PhPoint t radii = { 100, 50 };

// Draw an elliptical chord with a white outline,


// filled with black. The arc is drawn from 0 degrees
// through to 45 degrees (0x2000 bi-grads).
PgSetStrokeColor( Pg WHITE );
PgSetFillColor( Pg BLACK );
PgDrawArc( &center, &radii, 0, 0x2000,
Pg DRAW FILL STROKE | Pg ARC CHORD );
}

Similarly, to draw a pie section or curve, add Pg ARC PIE or Pg ARC


to the flags. For example:

void DrawPieCurve( void )


{
PhPoint t pie center = { 150, 150 },
arc center = { 150, 300 };
PhPoint t pie radii = { 100, 50 },
arc radii = { 50, 100 };

// Draw an elliptical pie with a white outline,


// filled with black.
PgSetStrokeColor( Pg WHITE );
PgSetFillColor( Pg BLACK );
PgDrawArc( &pie center, &pie radii, 0, 0x2000,
Pg DRAW FILL STROKE | Pg ARC PIE );

// Draw a black arc.


PgSetStrokeColor( Pg BLACK );
PgDrawArc( &arc center, &arc radii, 0, 0x2000,
Pg DRAW STROKE | Pg ARC );
}

410 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Lines, pixels, and pixel arrays

Lines, pixels, and pixel arrays


Lines and pixels are drawn using the current stroke state (color,
thickness, etc.).
The following example will draw red, green, and blue lines:
void DrawLines( void )
{
PgSetStrokeColor( Pg RED );
PgDrawILine( 8, 8, 152, 8 );
PgSetStrokeColor( Pg GREEN );
PgDrawILine( 8, 8, 152, 60 );
PgSetStrokeColor( Pg BLUE );
PgDrawILine( 8, 8, 152, 112 );
}

Text
Text is drawn using the current text state. If you set flags to
Pg BACK FILL, the text’s extent is filled with the fill state. If you
define an underline with PgSetUnderline(), the underline is drawn
under the text and on top of the backfill.
For example, to print white text in 18-point Helvetica:
void DrawSimpleText( void )
{
char *s = "Hello World!";
PhPoint t p = { 8, 30 };

PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgDrawText( s, strlen( s ), &p, 0 );
}

To print white text on a blue background:


void DrawBackFillText( void )
{
char *s = "Hello World!";
PhPoint t p = { 8, 30 };

PgSetFont( "helv18" );

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 411


Bitmaps  2005, QNX Software Systems

PgSetTextColor( Pg WHITE );
PgSetFillColor( Pg BLUE );
PgDrawText( s, strlen( s ), &p, Pg BACK FILL );
}

To print white text with a red underline:


void DrawUnderlineText( void )
{
char *s = "Hello World!";
PhPoint t p = { 8, 30 };

PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgSetUnderline( Pg RED, Pg TRANSPARENT, 0 );
PgDrawText( s, strlen( s ), &p, 0 );
PgSetUnderline( Pg TRANSPARENT, Pg TRANSPARENT, 0 );
}

To print white text with a red underline on a blue background:


void DrawBackFillUnderlineText( void )
{
char *s = "Hello World!";
PhPoint t p = { 8, 30 };

PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgSetFillColor( Pg BLUE );
PgSetUnderline( Pg RED, Pg TRANSPARENT, 0 );
PgDrawText( s, strlen( s ), &p, Pg BACK FILL );
PgSetUnderline( Pg TRANSPARENT, Pg TRANSPARENT, 0 );
}

Bitmaps
Bitmaps are drawn using the current text state. If you set flags to
Pg BACK FILL, the blank pixels in the image are drawn using the
current fill state.
The following example:
void DrawSimpleBitmap( void )
{

412 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Images

PhPoint t p = { 8, 8 };

PgSetTextColor( Pg WHITE );
PgDrawBitmap( TestBitmap, 0, &p, &TestBitmapSize,
TestBitmapBPL, 0 );
}

will draw the bitmap against a transparent background.


The following example:

void DrawBackFillBitmap( void )


{
PhPoint t p = { 8, 8 };

PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgSetFillColor( Pg BLUE );
PgDrawBitmap( TestBitmap, Pg BACK FILL, &p,
&TestBitmapSize, TestBitmapBPL, 0 );
}

will draw the bitmap against a blue background.

Images
Photon supports these main types of images:

direct color Consisting of:


¯ image data — a matrix of colors (but not
necessarily of type PgColor t). Each element
in the matrix is the color of a single pixel.
Direct-color images have a type that starts with
Pg IMAGE DIRECT .

palette-based Consisting of:


¯ a palette — an array of type PgColor t
¯ image data — a matrix whose elements are
offsets into the palette.

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 413


Images  2005, QNX Software Systems

Palette-based images have a type that starts with


Pg IMAGE PALETTE .

gradient color Colors are algorithmically generated as a gradient


between two given colors.

You can define any image by its pixel size, bytes per line, image data,
and format. Images can be stored in structures of type PhImage t
(described in the Photon Library Reference). The type field of this
data structure identifies the type of image.

Palette-based images
Palette-based images provide a fast, compact method for drawing
images. Before drawing a palette-based image, you must set either a
hard palette or soft palette to define the colors for the image.
Setting a hard palette changes the physical palette. All colors set with
a PgSetFillColor() function will be chosen from this palette. Other
processes will continue to choose colors from Photon’s global palette
and may appear incorrect. When you release the hard palette, the
other processes will return to normal without being redrawn. You
should always release the hard palette when your window loses focus.
Setting a soft palette lets you redefine how colors are interpreted for
the given draw context without changing the physical palette. All
colors in the soft palette will be mapped to the physical palette.

☞ If your physical palette uses more colors than your graphics card
supports, some colors will be dropped, and the image won’t look as
nice.

The image data (either bytes or nibbles) is an index into the current
palette. For example:

PgColor t ImagePalette[256];
char *ImageData;
PhPoint t ImageSize;
int ImageBPL;

414 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Images

void DrawYourImage( PhPoint t pos )


{
PgSetPalette( ImagePalette, 0, 0, 256,
Pg PALSET SOFT );
PgDrawImage( ImageData, Pg IMAGE PALETTE BYTE, pos,
ImageSize, ImageBPL, 0 );
}

Direct-color images
With direct-color images, every pixel can be any color. But compared
to palette-based images, the image data is larger and the image may
take longer to draw. You can choose from several types of direct-color
images, listed in the description of PhImage t in the Photon Library
Reference; each has a different image-pixel size and color accuracy.

Gradient-color images
With gradient-color images, colors are algorithmically generated as a
gradient between two given colors.

Creating images
To create a PhImage t structure:

¯ Call PxLoadImage() to load an image from disk.


Or

¯ Call ApGetImageRes() to load an image from a PhAB widget


database.
Or

¯ Get the value of the Pt ARG LABEL DATA resource of a PtLabel


or PtButton widget.
Or

¯ Allocate it and fill in the members by hand.

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 415


Images  2005, QNX Software Systems

Caching images
The image tag and palette tag members of the PhImage t structure
are used for caching images when dealing with remote processes via
phrelay (for example, when using phindows).
These tags are cyclic-redundancy checks (CRCs) for the image data
and the palette, and can be computed by PxCRC(). If these tags are
nonzero, phindows and phditto cache the images. Before sending
an image, phrelay sends its tag. If phindows finds the same tag in
its cache, it uses the image in the cache. This scheme reduces the
amount of data transmitted.

☞ You don’t need to fill in the tags if the images don’t need to be saved
in the cache. For example, set the tags to 0 if you’re displaying
animation by displaying images, and the images never repeat.

PxLoadImage() and ApGetImageRes() set the tags automatically.


PhAB generates the tags for any images generated through it (for
example, in the pixmap editor).

Transparency in images
If you want parts of an image to be transparent, you’ll need to create a
transparency mask for it. The transparency mask is stored in the
mask bm member of the PhImage t structure. It’s a bitmap that
corresponds to the image data; each bit represents a pixel:

If the bit is: The corresponding pixel is:


0 Transparent
1 Whatever color is specified in the image data

The mask bpl member of the PhImage t structure specifies the


number of bytes per line for the transparency mask.

416 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Images

For palette-based images, you can build a transparency mask by


calling PhMakeTransBitmap(). For other types of images, you must
build the transparency mask manually.

Displaying images
There are various ways to display an image:

¯ If the image is stored in a PhImage t structure, call


PgDrawPhImagemx().

¯ If the image isn’t stored in a PhImage t data structure, call


PgDrawImage() or PgDrawImagemx().
To draw the image repeatedly, call PgDrawRepImage() or
PgDrawRepImagemx()

¯ If the image isn’t stored in a PhImage t structure and has a


transparency mask, call PgDrawTImage() or PgDrawTImagemx().

¯ Set the Pt ARG LABEL DATA resource for a PtLabel or


PtButton widget (which use PgDrawPhImagemx() internally).

PgDrawPhImagemx() places the address of the image into the


drawing buffer in your application’s data space. When the drawing
buffer is flushed, the entire image is copied to the graphics driver.
You can speed up the drawing by using shared memory. Call
PgShmemCreate() to allocate the image data buffer:

my image->image = PgShmemCreate( size, NULL );

If you do this, the image data isn’t copied to the graphics driver.

☞ The images created and returned by ApGetImageRes() and


PxLoadImage() aren’t in shared memory.

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 417


Images  2005, QNX Software Systems

Releasing images
The PhImage t structure includes a flags member that can make it
easier to release the memory used by an image. These flags indicate
which members you would like to release:
¯ Ph RELEASE IMAGE
¯ Ph RELEASE PALETTE
¯ Ph RELEASE TRANSPARENCY MASK
¯ Ph RELEASE GHOST BITMAP
Calling PhReleaseImage() with an image will free any resources that
have the corresponding bit set in the image flags.

☞ ¯ PhReleaseImage() doesn’t free the PhImage t structure itself,


just the allocated members of it.

¯ PhReleaseImage() correctly frees memory allocated with


PgShmemCreate().

The flags for images created by ApGetImageRes() and


PxLoadImage() aren’t set. If you want PhReleaseImage() to free the
allocated members, you’ll have to set the flags yourself:
my image->flags = Ph RELEASE IMAGE |
Ph RELEASE PALETTE |
Ph RELEASE TRANSPARENCY MASK |
Ph RELEASE GHOST BITMAP;

If the image is stored in a widget, the allocated members of images


are automatically freed when an new image is specified or the widget
is destroyed, provided that:
¯ the appropriate bits in the flags member of the PhImage t
structure are set before the image is added to the widget
and
¯ Pt FREE MEMORY is set in the widget’s Pt ARG FLAGS resource.

418 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Animation

Animation
This section describes how you can create simple animation. There
are two basic steps:
¯ creating a series of “snapshots” of the object in motion
¯ cycling through the snapshots

☞ It’s better to use images for animation than bitmaps, as images aren’t
transparent (provided you haven’t created a transparency mask). This
means that the background doesn’t need to be redrawn when
replacing one image with another. As a result, there’s no flicker when
you use images. For other methods of eliminating flicker, see
“Flickerless animation”, below.

It’s also possible to create animation by using a PtRaw widget and the
Photon drawing primitives. See “PtRaw widget”, earlier in this
chapter.

Creating a series of snapshots


To animate an image you’ll need a series of snapshots of it in motion.
For example, you can use a PtLabel widget for animation. Create
one PtLabel widget where you want the animation to appear, and
create another PtLabel widget for each snapshot. You can store
these snapshots in a widget database or a file.

Using a widget database


As described in “Widget databases” in the Accessing PhAB Modules
from Code chapter, you can use a picture module as a widget
database. To use one for animation, do the following in PhAB:
1 Create a picture module to use as widget database.
2 Create an internal link to the picture module.
3 Create the snapshots of the object in motion. Use the same
widget type as you use where the animation is to appear. Give
each snapshot a unique instance name.

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 419


Animation  2005, QNX Software Systems

In your application’s initialization function, open the database by


calling ApOpenDBase(). Then, load the images with the
ApGetImageRes() function. For example,

/* global data */
PhImage t *images[4];
ApDBase t *database;
int cur image = -1,
num images = 4;

int
app init( int argc, char *argv[])

{
int i;
char image name[15];

/* eliminate ’unreferenced’ warnings */


argc = argc, argv = argv;

database = ApOpenDBase (ABM image db);

for (i = 0; i < num images; i++)


{
sprintf (image name, "image%d", i);
images[i] = ApGetImageRes (database, image name);
}

return (PT CONTINUE);


}

☞ Don’t close the database while you’re still using the images in it.

Using a file
You can also load the snapshots from a file into a PhImage t
structure, by using the PxLoadImage() function. This function
supports a number of formats, including GIF, PCX, JPG, BMP, TGA,
PNG and TIFF. For a complete list, see the <PxImage.h> file.

420 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Animation

☞ The code for only the formats you choose is loaded into your
application. Define PX IMAGE MODULES, followed by the formats
you want before including the <PxImage.h> file. For example, the
following code causes the code for PCX and BMP formats to be
loaded:

#define PX IMAGE MODULES


#define PX PCX SUPPORT
#define PX BMP SUPPORT

#include <PxImage.h>

Cycling through the snapshots


No matter where you get the images, the animation is the same:

1 Create a PtTimer widget in your application. PhAB displays it


as a black box; it won’t appear when you run your application.

2 Specify the initial (Pt ARG TIMER INITIAL) and repeat


(Pt ARG TIMER REPEAT) timer intervals.

3 Create an activate (Pt CB TIMER ACTIVATE) callback for the


timer. In the callback, determine the next image to be
displayed, and copy it into the destination widget.

For example, the callback for the timer could be as follows:

/* Display the next image for our animation example. */


/* AppBuilder Photon Code Lib */
/* Version 1.11 */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 421


Animation  2005, QNX Software Systems

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
display image( PtWidget t *widget,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PtArg t args[1];

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

cur image++;
if (cur image >= num images)
{
cur image=0;
}

PtSetArg (&args[0], Pt ARG LABEL DATA,


images[cur image],
sizeof (* (images[cur image])));
PtSetResources (ABW base image, 1, args);

PtFlush ();

return( Pt CONTINUE );

ABW base image is the widget name of the PtLabel widget in which
the animation appears.

Flickerless animation
There are two ways to eliminate flicker in animation:

¯ Create a PtDBContainer and make all the widgets in the area in


which the animation will appear children of the double-buffered
container.
Or

422 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


 2005, QNX Software Systems Animation

¯ Use the PmMem...() memory-context functions to build the image


in memory, and display it when complete.

PtDBContainer
When you do animation in a child of a double-buffered container, the
PtDBContainer renders the drawing into an image in memory. The
resulting image is rendered on the screen as a solid rectangular image.
There’s no need to draw the background first, so there’s no flicker.

☞ PtRaw (like any other widget) can be a child of PtDBContainer.


This means that you can have flicker-free animation even when using
the Photon drawing primitives.

The PtDBContainer widget creates an image. You can specify the


type by setting the Pt ARG DB IMAGE TYPE resource:

Pg IMAGE DIRECT 888


Optimize for speed.

Pg IMAGE PALETTE BYTE


Optimize for size.

PmMem... functions
The PtDBContainer widget uses the PmMem... functions to draw an
image in memory. You can call these functions directly if you’d rather
not use the double-buffered container:

PmMemCreateMC()
Create a memory context

PmMemFlush()
Flush a memory context to its bitmap

PmMemReleaseMC()
Release a memory context

September 20, 2005 Chapter 17 ¯ Raw Drawing and Animation 423


Animation  2005, QNX Software Systems

PmMemSetChunkSize()
Set the increment for growing a memory context’s draw buffer
PmMemSetMaxBufSize()
Set the maximum size of a memory context’s draw buffer
PmMemSetType()
Set the type of a memory context

PmMemStart()
Make a memory context active

PmMemStop()
Deactivate a memory context

Start by creating a memory context:

PmMemoryContext t * PmMemCreateMC(
PhImage t *image,
PhDim t *dim,
PhPoint t *translation );

The image structure must at least specify the type and size members.
The image data buffer is optional, but if you want it in shared
memory, you must provide it. The image type must be either
Pg IMAGE DIRECT 888 or Pg IMAGE PALETTE BYTE.
Once you’ve created the memory context:

¯ Call PmMemStart() to set the current draw context to the memory


context.

¯ Call PmMemStop() when finished your drawing, to return to the


default draw context.

¯ Call PmMemFlush() to get the resulting image.

When you no longer need the memory context, call


PmMemReleaseMC().

424 Chapter 17 ¯ Raw Drawing and Animation September 20, 2005


Chapter 18
Fonts

In this chapter. . .
Font names 427

September 20, 2005 Chapter 18 ¯ Fonts 425


 2005, QNX Software Systems Font names

This chapter describes how to work with fonts in a Photon application.

Font names
It’s possible — and common — to hard-code all references to fonts in
a Photon application. But there’s a more flexible approach where
applications can choose the best match from whatever fonts are
available. That way, there isn’t a problem if a particular font is
eventually renamed, removed, or replaced.
To specify a font in the Photon API, you always use a stem name. For
example, the following call to PtAskQuestion() uses the stem name
helv14 to specify 14-point Helvetica:

PtAskQuestion (base wgt, NULL,


"File has not been saved. Save it?",
"helv14", "&Save", "&Discard",
"&Cancel", 1);

If you’re using QNX 4.25, you’ll find the available stem names listed
in /qnx4/photon/font/fontdir. If you’re using QNX Neutrino
2, look in /nto/photon/font/fontdir.
Alternately, if you have a $HOME/.photon directory, check in
$HOME/.photon/font/fontdir. Photon creates this local file
only when needed, such as when you run the fontcfg utility to
create your own personal font configuration. Until the local file is
created, Photon uses the global file.
The above example takes a shortcut by using a hard-coded stem name
(helv14).And, like any shortcut, this approach has tradeoffs. First,
stem names are subject to change. More importantly, all versions of
Photon up to and including 1.13 have only 16 characters available for
the stem name. This isn’t always enough to give each font a unique
stem. Photon 1.14 for QNX Neutrino has 80 characters
To get around these problems, use PfQueryFonts() to provide the
information needed to build your stem name. This function queries
the Photon Font Server, and protects you from future changes.

September 20, 2005 Chapter 18 ¯ Fonts 427


Font names  2005, QNX Software Systems

Using PfQueryFonts()
Let’s start with the parameters to PfQueryFonts() — then we’ll look at
a code sample that extracts the stem name from the data returned by
the function.
The function itself looks like this:

PfQueryFonts (long symbol,


unsigned flags,
FontDetails list[],
int n );

The arguments are:

symbol A key for searching the Photon Font Manager. The


function looks for fonts that include this symbol and
discards those that don’t have it.
For instance, a Unicode space symbol (0x0020) is
available in almost any font. Specifying an é symbol
(Unicode 0x00c9), on the other hand, narrows down the
font choices considerably. And, of course, specifying a
Japanese character selects only Japanese fonts.
To include all available fonts, use
PHFONT ALL SYMBOLS.

flags Provides another way to narrow down your search.


Available values:
¯ PHFONT SCALABLE — these fonts use a series of
vectors to describe each character, making it possible
to display the font in a variety of sizes.
¯ PHFONT BITMAP — these fonts store genuine pictures
of their characters.
¯ PHFONT PROP — these fonts are proportional. For
example, in a proportional font, W is wider than i.
¯ PHFONT FIXED — these fonts make all characters the
same width.

428 Chapter 18 ¯ Fonts September 20, 2005


 2005, QNX Software Systems Font names

¯ PHFONT ALL FONTS

list[] An array that the Photon Font Manager fills in for you.
You need to declare a FontDetails structure, which is
described below.

n The number of elements available in the list array.

If PfQueryFonts() is successful, it returns the number of fonts


available that matched your selection criteria. Otherwise, it returns -1.

☞ If n is 0 and list is NULL, PfQueryFonts() returns the number of


matching fonts but doesn’t try to fill in the list. You can use this
feature to determine the number of items to allocate for the list.

FontDetails structure
Once you’ve got the list of fonts, you’ll need to tear apart the
FontDetails structure for each. That way, you can find both the
font you need and the string to use as a stem name.
The FontDetails structure is defined in <photon/Pf.h>, and is
defined as:

typedef struct {
FontDescription desc;
FontName stem;
short losize;
short hisize;
unsigned short flags;
} FontDetails;

For our purposes, the desc and stem elements the most useful, but let’s
review them all.

desc The full descriptive name of the font; for example,


Helvetica or Charter. Note the use of capitals.
Assigned by the foundry that built the font, this name is
universal across operating environments (e.g. X, Photon).

September 20, 2005 Chapter 18 ¯ Fonts 429


Font names  2005, QNX Software Systems

stem The short form. This provides a part of the stem name used
by the Photon API calls. For example, helv and char
correspond to Helvetica and Charter.

losize The minimum available point size for the font, say 4.

hisize The largest size the font has available. If both losize and
hisize are 0, the font is scalable.

flags Available values:


¯ PHFONT INFO FIXED — a fixed-width font.
¯ PHFONT INFO PROP — a proportional font.
¯ PHFONT INFO PLAIN — the font is neither bold nor
italic.
¯ PHFONT INFO BOLD
¯ PHFONT INFO ITALIC

Example
Now that we’ve looked at the pieces involved, it’s fairly simple to
follow the steps needed to build up the correct stem name for a given
font.
Keep these things in mind:

¯ Use a character buffer to gradually build up the stem name.

¯ Search for a font based on the decription (desc) member of its


FontDetails entry, not on the stem.

You’ll probably want to do this work in the initialization function for


your application, or perhaps in the base window setup function. Once
you’ve constructed the stem name, keep the string in a global variable.
You can then use it as needed.
Here’s a sample application-initialization function:
/***************************
*** global variables ***
***************************/

430 Chapter 18 ¯ Fonts September 20, 2005


 2005, QNX Software Systems Font names

char GcaCharter14Bold [MAX FONT TAG + 1];


/* Remember: there’s no point in having a larger
buffer than the stem name’s size (plus 1 to
allow for a NULL-terminated string */

int
fcnAppInit( int argc, char *argv[] )

{
/* Local variables */
FontDetails tsFontList [nFONTLIST SIZE];
short sCurrFont = 0;
char caBuff[20];

/* Get a description of the available fonts */

if (PfQueryFonts (PHFONT ALL SYMBOLS,


PHFONT ALL FONTS, tsFontList,
nFONTLIST SIZE) == -1)
{
perror ("PfQueryFonts() failed: ");
return (Pt CONTINUE);
}

/* Search among them for the font that matches our


specifications */

for (sCurrFont = 0;
sCurrFont < nFONTLIST SIZE; sCurrFont++)
{
if ( !strcmp (tsFontList[sCurrFont].desc,
"Charter") )
break; /* we’ve found it */
}

/* Overrun check */
if (sCurrFont == nFONTLIST SIZE)
{
/* check for a partial match */
for (sCurrFont = 0;
sCurrFont < nFONTLIST SIZE;
sCurrFont++)
{
if ( !strncmp (tsFontList[sCurrFont].desc,
"Charter",
strlen ("Charter") ) )
break; /* found a partial match */
}

September 20, 2005 Chapter 18 ¯ Fonts 431


Font names  2005, QNX Software Systems

if (sCurrFont == nFONTLIST SIZE)


{
printf ("Charter not in %d fonts checked.\n",
sCurrFont);
return (Pt CONTINUE);
}
else
printf ("Using partial match -- ’Charter’.\n");
}

/* Does it have bold? */


if (!(tsFontList[sCurrFont].flags & PHFONT INFO BOLD))
{
printf ("Charter not available in bold font.\n");
return (Pt CONTINUE);
}

/* Is 14-point available? */
if ( !( (tsFontList[sCurrFont].losize ==
tsFontList[sCurrFont].hisize == 0)
/* proportional font -- it can be shown in
14-point*/

||

( (tsFontList[sCurrFont].losize <= 14 )
&&
(tsFontList[sCurrFont].hisize >= 14 ) ) ) )
/* 14-point fits between smallest and
largest available size */

{
printf ("Charter not available in 14-point.\n");
return (Pt CONTINUE);
}

/* Build up the stem name */


strncpy (GcaCharter14Bold,
tsFontList[sCurrFont].stem,
MAX FONT TAG);

if (GcaCharter14Bold[0] == ’\x0’)
{
printf ("Charter font stem name was blank.\n");
return (Pt CONTINUE);
}

432 Chapter 18 ¯ Fonts September 20, 2005


 2005, QNX Software Systems Font names

strcat (GcaCharter14Bold, itoa (14, caBuff, 10) );


strcat (GcaCharter14Bold, "b");
strcat (GcaCharter14Bold, ""); /* note the NULL termination */

/* You can now use GcaCharter14Bold as an argument to


PtAskQuestion(), etc. */

/* Eliminate ’unreferenced’ warnings */


argc = argc, argv = argv;

return( Pt CONTINUE );

For the above code to work, you must declare the following
information in the application’s global header file. To do this, use
PhAB’s Startup Info/Modules dialog (accessed from the Application
menu).
/*********************************
*** user-defined constants ***
*********************************/
#define nFONTLIST SIZE 100 /* an arbitrary choice of size */

/***************************
*** global variables ***
***************************/

extern char GcaCharter14Bold [];

Remember to define this header before you start adding callbacks and
setup functions – that way, it will be automatically included as a
#define. If you forget, you’ll have to go back and add the statement
manually.
And last of all, here’s a sample callback that uses our stem name
string:
int
fcnbase btn showdlg ActivateCB( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

/* This callback is used to launch a dialog box with the


intent of exercising the global variable GcaCharter14Bold */
{

September 20, 2005 Chapter 18 ¯ Fonts 433


Font names  2005, QNX Software Systems

PtAskQuestion
(ABW base, "Font Demonstration",
"This sentence is in 14-pt. Charter bold",
GcaCharter14Bold, "OK", NULL, NULL, 1);

/* Eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

return( Pt CONTINUE );
}

434 Chapter 18 ¯ Fonts September 20, 2005


Chapter 19
Printing

In this chapter. . .
What’s in a print context? 438
Creating a print context 446
Modifying a print context 446
Starting printing 452
Drawing the desired widgets 455
Suspending and resuming printing 461
Closing printing 461
Multiple print sessions 462
Freeing the print context 462
Example 463

September 20, 2005 Chapter 19 ¯ Printing 435


 2005, QNX Software Systems

Printing and drawing are the same in Photon — the difference


depends on the draw context, a data structure that defines where the
draw stream flows:
¯ by default, to the graphics driver for drawing on the screen
¯ to a memory context (or MC) for storing images in memory for
later use
¯ to a print context (or PC) for printing. This is a data structure of
type PpPrintContext t (see the description below).
To print in Photon:
1 Create a print context by calling PpPrintCreatePC().
2 Set up the print context
¯ programmatically via PpPrintSetPC()
¯ automatically via the PtPrintSel widget
or
¯ interactively via the printer properties application (launched
by the PtPrintSel widget if the user requests it).
3 Initialize the current print job by calling PpPrintOpen().
4 Any time after PpPrintOpen() is called, make the print context
“active” by calling PpPrintStart(). When a print context is
active, anything that’s drawn via Pg* calls, including widgets,
is directed to the file opened by the print context during the
PpPrintOpen() call.
5 Insert page breaks, as required, by calling PpPrintNewPage().
6 The print context can be made inactive without terminating the
current print job by calling PpPrintStop(), or by calling
PpPrintStart() with a different print context. To resume the
print job from where you left off, call PpPrintStart().
7 Complete the print job by calling PpPrintClose().
8 When your application doesn’t need to print anything else, call
PpPrintReleasePC() to free the print context.

September 20, 2005 Chapter 19 ¯ Printing 437


What’s in a print context?  2005, QNX Software Systems

What’s in a print context?


A print context includes a number of members that control how
printing is to be done.

☞ Don’t use the members of a print context directly. Use


PpPrintGetPC() to extract members, and PpPrintSetPC() to change
them.

The possible values and meanings for the members of a print context
are defined in /usr/photon/print/printers — see “Setting up
the printer definition file” in the Printing Support chapter of the
Photon Installation and Configuration guide.
Here’s an overview of what’s in a print context:

Pp PC NAME The name of the printer (e.g. R&D main


printer).

Pp PC LOCATION
The location of the printer (e.g. By board room
#2).

Pp PC DEVICE Usually the spooler to use (e.g.


/dev/spool/Ph.main deskjet).
If you’re sending the print job directly to a printer
(such as /dev/par1), set Pp PC FILENAME to the
name of the printer (e.g. /dev/par1) and
Pp PC DRIVER to the name of the Photon print
driver that produces output the printer will
recognize.
If both the device and filename members are set,
the output goes to the destination identified by the
filename.

Pp PC DRIVER The driver application to launch if printing to file


(if a filename is specified). For example, Pp.pcl.
For information about the available print drivers,

438 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems What’s in a print context?

see the Applications and Utilities chapter of the


Photon Installation & Configuration guide.

Pp PC NONPRINT MARGINS
A rectangle that specifies (in 1/1000ths of an inch)
the nonprintable margins of the printer.

Pp PC PROP APP
The application to launch to adjust the printer
properties portion of the print context.

Pp PC PREVIEW APP
The application to launch to preview the print job,
usually /usr/photon/bin/preview.

Pp PC FILENAME
If this member is specified, the final output of the
print job is placed in this file.
If a driver is also specified, a temporary file is used
to hold the raw Photon draw stream until
PpPrintClose() is called, at which time the driver
is launched to process the temporary file into
printer-ready format in the file specified. The
temporary file is removed.
If no driver is provided, the raw Photon draw
stream is written to the specified file. This .phs
(Photon Stream) file can be sent to any spooler
that accepts the Photon draw stream, or can be
given directly to any of the Photon print drivers to
produce output in the proper format for a specific
printer.

Pp PC COMMENT
This comment doesn’t appear in the printed output
produced by the printer; it exists in the draw
context and the Photon stream files.

September 20, 2005 Chapter 19 ¯ Printing 439


What’s in a print context?  2005, QNX Software Systems

Pp PC DATE The date the print job was started. It’s filled in
when the print job is initialized. See
PpPrintOpen() and PpPrintStart().

Pp PC USER ID The user creating the print job. It’s filled in when
the print job is initialized. See PpPrintOpen() and
PpPrintStart().
Pp PC PAGE RANGE
The range of pages to be printed. This information
should be used by the application when producing
the printed output. Only those pages requested
should be printed. Any pages printed will appear
in the output (i.e. the drivers don’t look at the page
range when processing the Photon draw stream).
The page range is just a string. The application
must parse it to determine which pages should be
printed. For example:

Page range Meaning


NULL Print all
"all" Print all
"selection" Print the selected items
"1,3-6,8,10-" Print pages 1, 3 through 6, 8,
and 10 to the end of data.

Pp PC SOURCE OFFSET
The origin for the print job. For example, if a
widget you want to print is at (50,50) but you
would like it to appear in the upper left corner of
the page, the source offset should be set to (50,50).

440 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems What’s in a print context?

Pp PC SOURCE SIZE
The dimension of the source, in pixels. This size is
used for clipping and for any scaling that may be
applied. Setting Pp PC SOURCE SIZE to 612 ¢
792 yields scaling that makes a 72-point font
approximately 1″ high when printed.
Pp PC SOURCE RESOLUTION
Specified in x and y dots per inch, this is a hint that
helps the print drivers do the best scaling possible.
Pp PC SOURCE COLORS
The number of bitplanes per source pixel. If this is
n, you’ll have 2 to the power of n colors. For
example, a value of 8 means 256 colors.

Pp PC SCALE The scale to use in x and y:


¯ 0 — maintain aspect
¯ positive — scale as a percentage of page size
(1/10th percent). For example, 1000 = 100%.
¯ negative — scale as a percentage of source size
(1/10th percent). This is useful when printing
to a bitmap file, where there’s no “page size.”

If x and y scales are both 0, the source is scaled as large as possible to


☞ fit the page and still maintain its x and y aspect ratio. Most scaling can
be done by adjusting the source size and leaving the scaling at 0, 0.
Pp PC MARGINS
A rectangle that specifies the margins to apply to
the pages, specified in 1/1000ths of an inch:
¯ ul.x — left margin
¯ ul.y — top margin
¯ lr.x — right margin
¯ lr.y — bottom margin

September 20, 2005 Chapter 19 ¯ Printing 441


What’s in a print context?  2005, QNX Software Systems

The orientation of the page doesn’t affect the


margins.
Pp PC INTENSITY
A value between 0 and 100,000 (0 to 100% in
1/1000 percent). A printer’s default intensity is
50%.
Pp PC PRINTER RESOLUTION
Specified in x and y dots per inch, this is a hint that
helps the print drivers do the best scaling possible.
Pp PC PAPER SIZE
The dimension of the paper in 1/1000ths of an
inch. This size is used for clipping and for any
scaling that may be applied.
Pp PC COLLATING MODE
Dictates the order of pages that are printed in print
jobs that are printing more than one copy, and may
include:
¯ don’t care
¯ 1-2-3, 1-2-3, ...
¯ 1-1-1, 2-2-2, ...
¯ 3-2-1, 3-2-1, ... (not implemented yet)
Pp PC DITHERING
Specifies the dithering, as a value in the range 0
through 100. Possible meanings include:
¯ don’t care
¯ none
¯ coarse
¯ fine
¯ line art
¯ error diffusion

442 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems What’s in a print context?

¯ half toning

Pp PC COPIES The number of copies to produce.

Pp PC ORIENTATION
Portrait or landscape

Pp PC DUPLEX Specifies whether or not double-sided printing is


to be done.
Pp PC PAPER TYPE
This is in the range 0 through 100. Possible
meanings include:
¯ don’t care
¯ normal quality
¯ high quality
¯ draft quality
¯ transparency
¯ envelope
¯ T-shirt (reversed image)
Pp PC PAPER SOURCE
Possible meanings:
¯ don’t care
¯ automatic
¯ upper tray
¯ lower tray
¯ manual feed
¯ envelope
¯ envelope (manual feed)

Pp PC INKTYPE Possible meanings:


¯ don’t care

September 20, 2005 Chapter 19 ¯ Printing 443


What’s in a print context?  2005, QNX Software Systems

¯ normal
¯ black & white cartridge
¯ color cartridge
¯ neon ink
¯ T-shirt ink
Pp PC COLOR MODE
Possible meanings:
¯ black & white
¯ grayscale
¯ color
Pp PC DO PREVIEW
If nonzero, the preview application is launched
rather submitting the job to a spooler or launching
a driver.
Pp PC JOB NAME
The name of the print job for identification
purposes
Pp PC CONTROL (r/o)
The control structure for the print context
(PpPCControl t), which is used internally for
print-context control. See below.

The Pp PC CONTROL member can’t be set with PpPrintSetPC().


Pp PC CONTROL control structure


The control structure has at least the following members:

ulong t changed[4]
Indicates which portions of the context have been
modified. There are 32 modifiable attributes of a print

444 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems What’s in a print context?

context; each attribute corresponds to a bit in a long.


There are four long entries, each representing a level of
control:
¯ PRINTER GLOBAL — modified according to the
global printer file
¯ PRINTER LOCAL — modified according to the local
printer file
¯ INITIAL PC — modified by the application.
¯ INTERACTIVE PC — modified according to user
input.
Each entry indicates which context attributes were
modified by that level of control. For example:

if( control->changed[PRINTER GLOBAL] &


(1<<Pp PC NAME) )
printf( "Print name has been changed according\
to global printer spec file\n");

ulong t emitted
Indicates which of the changed print context attributes
have already been written to the destination or temporary
file. For example:

if( control->emitted & (1<<Pp PC SOURCE OFFSET) )


printf( "source offset has been emitted\n");

ulong t locked
Indicates which context attributes are locked. Locked
attributes are displayed as ghosted controls by the printer
properties application, and PpPrintSetPC() won’t let you
change them.

September 20, 2005 Chapter 19 ¯ Printing 445


Creating a print context  2005, QNX Software Systems

int fd This is the file descriptor for the current print job’s
working file. The working file isn’t opened until the print
job is opened by PpPrintOpen(). This is -1 if no files are
currently open.

char *tmp target


The temporary working file that will be used if printing to
a file (i.e. Pp PC FILENAME is specified) and a driver is
defined, or if do preview is set.
char do preview
If this is nonzero, the application specified in the print
context’s Pp PC PREVIEW APP member is launched
when the print job is finished (that is, when
PpPrintClose() is called).

Creating a print context


The first step to printing in Photon is to create a print context by
calling PpPrintCreatePC():

PpPrintContext t *pc;

pc = PpPrintCreatePC();

!
CAUTION: Never access the fields in a print context directly; use
PpPrintGetPC() and PpPrintSetPC().

Modifying a print context


Once the print context is created, you must set it up properly for your
printer and the options (orientation, paper size, etc.) you want to use.
This can be done by any of the following:

¯ calling the PtPrintSelection() convenience function

¯ using the PtPrintSel widget

446 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Modifying a print context

¯ calling the PpPrintSetPC() function. This function lets you set


parameters in the print context manually.

Calling PtPrintSelection()
PtPrintSelection() is a convenience function that makes it easy to
choose a printer for the print context. It creates a modal dialog for
printing that incorporates a PtPrintSel widget and 3 buttons:

Select Printer
Select a Printer

Printer: Lexmark Tech Pubs Properties...

Location: Tech Pubs Print to File

Print Range Copies


All Pages Number Of Copies:
Pages
Collate M ethod:
Selection

Print Prev iew Cancel

Dialog created by PtPrintSelection().

To create a print selection dialog, you can use the function:

PtPrintSelection( PtWidget t *parent,


PhPoint t *pos,
const char *title,
PpPrintContext t *context,
unsigned flags );

The arguments are:

parent Parent of the print selector dialog, possibly the


application window. It can be NULL (see below).

September 20, 2005 Chapter 19 ¯ Printing 447


Modifying a print context  2005, QNX Software Systems

pos Position of the print selector dialog relative to parent.


This can be NULL (see below).

title Title of the print selector dialog. If this is NULL, the


string Select Printer is used.

context A pointer to a created print context, which must have


been created with PpPrintCreatePC(). This is a
mandatory parameter.

flags Flags for the PtPrintSel widget:


¯ Pt PRINTSEL ALL PANES — show all the dialog’s
panes
¯ Pt PRINTSEL PROP APP — enable the properties
button
¯ Pt PRINTSEL NO PAGE RANGE — disable page
range selection
¯ Pt PRINTSEL NO SELECT RANGE — disable the
selection range
¯ Pt PRINTSEL NO COPIES — disable the copies frame
¯ Pt PRINTSEL NO COLLATE — disable the collate
buttons
¯ Pt PRINTSEL DFLT LOOK — the default look, seen
above
For example, if you wanted only the printer selection
pane and a properties button, specify:
action = PtPrintSelection( window, NULL,
"Demo Print Selector",
pc, Pt PRINTSEL PROP APP );

If you want all the panes but want to disable the copies
pane:
action = PtPrintSelection( window, NULL,
"Demo Print Selector", pc,
Pt PRINTSEL PROP APP |

448 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Modifying a print context

Pt PRINTSEL ALL PANES |


Pt PRINTSEL NO COPIES );

The parent and pos parameters determine where the dialog is to


appear:

parent pos Position of dialog


NULL NULL Center of the screen
NULL Non-NULL pos relative to the screen
Non-NULL NULL Center of parent
Non-NULL Non-NULL pos relative to parent

PtPrintSelection() takes a created print context and creates a dialog to


allow the selection of a printer. The print context is modified
depending on the options you’ve chosen from the dialog, such as the
printer, or via the properties application. PtPrintSelection() returns a
value indicating which button (Print, Preview or Cancel) was selected:

¯ Pt PRINTSEL PRINT
¯ Pt PRINTSEL PREVIEW
¯ Pt PRINTSEL CANCEL

The print context that you passed is filled with the options selected
from the dialog. If PtPrintSelection() returns Pt PRINTSEL PREVIEW
or Pt PRINTSEL PRINT, you should begin the printing process — the
print context will be set up for the selected printer:
action = PtPrintSelection(window, NULL,
"Demo Print Selector",
pc, Pt PRINTSEL DFLT LOOK);
if (action != Pt PRINTSEL CANCEL)
{
// start printing
}

September 20, 2005 Chapter 19 ¯ Printing 449


Modifying a print context  2005, QNX Software Systems

Using the PtPrintSel widget


The PtPrintSel widget lets you create a custom dialog for printing.
Select a Printer

Printer: Lexmark Tech Pubs Properties...

Location: Tech Pubs Print to File

Print Range Copies


All Pages Number Of Copies:
Pages
Collate M ethod:
Selection

A PtPrintSel widget.

The widget has a resource for a print context,


Pt ARG PRINT CONTEXT, that you must set to one you’ve created
with PpPrintCreatePC():
PtSetArg(&args[0], Pt ARG PRINT CONTEXT, pc, 0);
// Set some other resources...
printsel = PtCreateWidget(PtPrintSel, window, nargs, args);

The widget automatically handles all aspects of selecting a printer and


also runs the properties application to modify elements in the print
context. When you’re finished selecting the printer, you can get the
modified print context by using PtGetResources() to get the widget’s
print-context resource:
// The user has finished configuring the print session.

PtSetArg(&args[0], Pt ARG PRINT CONTEXT, &pc, 0);


PtGetResources(printsel, 1, args);

450 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Modifying a print context

Calling PpPrintSetPC()
You can also use PpPrintSetPC() directly instead of, or in addition to,
using the PtPrintSel widget or PtPrintSelection(). After creating a
print context, you must select a printer:

¯ To select the default printer, don’t set the Pp PC NAME field. Then
call:
err = PpPrintOpen(pc);
if (err == -1)
// check errno
// succeeded

This loads the print context with the values found in your
$HOME/.photon/print/config and
/usr/photon/print/printers files for the default printer
defined in your $HOME/.photon/print/default file.
¯ To select a specific printer, set the Pp PC NAME field to the
printer’s name and then call PpPrintOpen(). For example:
PpPrintSetPC( pc, INITIAL PC, 0, Pp PC NAME, "My printer" );
err = PpPrintOpen( pc );
if (err == -1)
// check errno
// succeeded

This loads the print context with the values found in your
$HOME/.photon/print/config and
/usr/photon/print/printers files for the printer named My
printer.

☞ Don’t set Pp PC DEVICE or Pp PC DRIVER for either method —


they’re set for you.

To override any default options in the print context, set them with
PpPrintSetPC() before calling PpPrintOpen(). Specify either
INITIAL PC or INTERACTIVE PC as the mod level argument to
PpPrintSetPC(). These levels take precedence over local
(PRINTER LOCAL) and global (PRINTER GLOBAL) options. For
example:

September 20, 2005 Chapter 19 ¯ Printing 451


Starting printing  2005, QNX Software Systems

// Create a print context before this:


short orientation = 1; // For landscape. Assume the default
// is 0 - portrait
int err;

...
// Set the name of the printer if you’re using method 2.

// Now set the orientation.


PpPrintSetPC( pc, INITIAL PC, 0, Pp PC ORIENTATION,
&orientation );
err = PpPrintOpen( pc );
if (err == -1)
// check errno

// Continue with printing. Your orientation option


// has been preserved

For more information, see PpPrintSetPC() in the Photon Library


Reference.

Starting printing
If you’re using an application that needs to know anything about the
print context, you can use PpPrintGetPC() to get the appropriate
information. For example, you may need to know the size of the
margins, or the selected orientation (in order to orient your widgets
properly). For an example, see the printing application prdemo.
Before printing, you must set the source size, which determines how
the information is printed. For example:

¯ If you want a widget to fill the page, set your source size to equal
the widget’s dimensions.
¯ If you want a font to be printed with the proper dimensions (a
72-point font should be 1″ high), you should set the source size to
612 ¢ 792 for a 8.5″ ¢ 11″ page. This is calculated by knowing
that a point is 1/72 of an inch, so the width of a page is:
72 points/inch ¢ 8.5 inches = 612 points

When setting the source size, take the nonprintable area of the printer
into account. All printers have a margin around the page that they

452 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Starting printing

won’t print on, even if the page margins are set to 0. Therefore, the
size set above is actually a bit larger than the size of a page, and the
font will be scaled down to fit on the printable part of the page.
In the following example, the page size and nonprintable area are
taken into account to give the proper source size and text height. Try
this, and measure the output to prove the font is 1″ high from ascender
to descender:
#include <stdio.h>
#include <stdlib.h>
#include <Pt.h>

PtWidget t *label, *window;


PpPrintContext t *pc;

int quit cb (PtWidget t *widget, void *data,


PtCallbackInfo t *cbinfo )
{
exit (EXIT SUCCESS);
return (Pt CONTINUE);
}

int print cb (PtWidget t *widget, void *data,


PtCallbackInfo t *cbinfo )
{
int action;
PhDim t size;
PhRect t const *rect;
PhDim t const *dim;

action = PtPrintSelection(window, NULL,


"Demo Print Selector",
pc, Pt PRINTSEL DFLT LOOK);
if (action != Pt PRINTSEL CANCEL)
{
// Get the nonprintable area and page size.Both are in
// 1/1000ths of an inch.
PpPrintGetPC(pc, Pp PC NONPRINT MARGINS, &rect);
PpPrintGetPC(pc, Pp PC PAPER SIZE, &dim);
size.w = ((dim->w -
(rect->ul.x + rect->lr.x)) * 72) / 1000;
size.h = ((dim->h -
(rect->ul.y + rect->lr.y)) * 72) / 1000;

// Set the source size.


PpPrintSetPC( pc, INITIAL PC, 0, Pp PC SOURCE SIZE,
&size);

September 20, 2005 Chapter 19 ¯ Printing 453


Starting printing  2005, QNX Software Systems

// Start printing the label.


PpPrintOpen(pc);
PpPrintStart(pc);

// Damage the widget.


PtDamageWidget(label);
PtFlush();

// Close the pc.


PpPrintStop(pc);
PpPrintClose(pc);
}
return (Pt CONTINUE);
}

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


{
PtArg t args[10];
PtWidget t *print, *quit;
PhDim t win dim = { 400, 200 };
PhPoint t lbl pos = {0, 0};
PhArea t print area = { {130, 170}, {60, 20} };
PhArea t quit area = { {210, 170}, {60, 20} };
PtCallback t callbacks[2] = { {print cb, NULL},
{quit cb, NULL} };

// Create the main window.


PtSetArg (&args[0], Pt ARG DIM, &win dim, 0);
PtSetArg (&args[1], Pt ARG WINDOW TITLE,
"Print Example", 0);
if ((window = PtAppInit( NULL, &argc,
argv, 1, args)) == NULL)
exit (EXIT FAILURE);

// Create a print context.


pc = PpPrintCreatePC();

// Create a label to be printed.


PtSetArg (&args[0], Pt ARG POS, &lbl pos, 0);
PtSetArg (&args[1], Pt ARG TEXT STRING,
"I am 1 inch high", 0);
PtSetArg (&args[2], Pt ARG TEXT FONT, "swiss72", 0);
PtSetArg (&args[3], Pt ARG MARGIN HEIGHT, 0, 0);
PtSetArg (&args[4], Pt ARG MARGIN WIDTH, 0, 0);
PtSetArg (&args[5], Pt ARG BORDER WIDTH, 0, 0);
label = PtCreateWidget (PtLabel, window, 6, args);

// Create the print button.


PtSetArg(&args[0], Pt ARG AREA, &print area, 0);
PtSetArg(&args[1], Pt ARG TEXT STRING, "Print", 0);

454 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Drawing the desired widgets

PtSetArg(&args[2], Pt CB ACTIVATE, &callbacks[0], 0);


print = PtCreateWidget (PtButton, window, 3, args);

// Create the quit button.


PtSetArg(&args[0], Pt ARG AREA, &quit area, 0);
PtSetArg(&args[1], Pt ARG TEXT STRING, "Quit", 0);
PtSetArg(&args[2], Pt CB ACTIVATE, &callbacks[1], 0);
quit = PtCreateWidget (PtButton, window, 3, args);

PtRealizeWidget(window);
PtMainLoop();
return (EXIT SUCCESS);
}

You should also set the source offset, the upper left corner of what’s
to be printed. For example, if you have a button drawn at (20, 20)
from the top left of a pane and you want it to be drawn at (0, 0) on the
page, set the source offset to (20, 20). Any other widgets are drawn
relative to their position from this widget’s origin. A widget at (40,
40) will be drawn at (20, 20) on the page. The code is as follows:

PhPoint t offset = {20, 20};


...
PpPrintSetPC( pc, INITIAL PC, 0, Pp PC SOURCE OFFSET,
&offset );

Once the source size and offset have been set, you can start printing:

PpPrintOpen(pc);
PpPrintStart(pc);

PpPrintOpen() sets up the print context for printing and


PpPrintStart() makes the print context active, causing all Photon draw
commands to be redirected to the destination specified in the print
context.

Drawing the desired widgets


After you’ve made the print context active, you can start drawing
widgets. This can be done by any combination of the following:

¯ damaging widgets and forcing a redraw

September 20, 2005 Chapter 19 ¯ Printing 455


Drawing the desired widgets  2005, QNX Software Systems

¯ drawing new widgets

¯ calling Pg* functions

¯ calling PpPrintWidget() — you’ll have to use this if you want to


print an unrealized widget

You can force a page break at any point by calling PpPrintNewPage().


Note that once you call PpPrintOpen(), any changes to the print
context take effect after the next call to PpPrintNewPage().

☞ If you want to print all the contents of a widget that scrolls, you’ll
need to do some special preparations. See “Printing scrolling
widgets” below.

Printing by damaging widgets


For example, to print a widget B:
PtDamageWidget(B);
PtFlush();

Widget B redraws itself, and the draw commands are redirected to the
destination in the print context.

Printing by calling PpPrintWidget()


Instead of damaging a widget to print it, you can call PpPrintWidget(),
in which case you can specify some printing parameters:
int PpPrintWidget( PpPrintContext t *pc,
PtWidget t *widget,
PhPoint t *trans,
PhRect t *clip rect,
ulong t opt );

In addition to the print context and the widget, you can specify:

trans The source offset.

clip rect The clipping area. (Not implemented; set it to NULL.)

456 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Drawing the desired widgets

opt Any special resizing to be done:


¯ Pt PP RESIZE PC — set the source size of the print
context to be the size of the widget. The widget is
scaled to fit the page.
¯ Pt PP RESIZE WIDGET — set the dimension of the
widget to match the drawable area of the destination
page. The widget is resized to fit the page, as
opposed to being scaled to fit the page.
¯ Pt PP NO RESIZE — don’t modify the source size of
the print context or the widget’s dimensions. It’s
important to set the source size of the print context
before calling PpPrintWidget() with this option.

For example, to print a widget B (even if it hasn’t been realized):

PpPrintWidget(pc, B, trans, NULL, opt);


PtFlush();

☞ Be sure to call PtFlush() after calling PpPrintWidget().

Printing a new page


If you want to start a new page, call

PpPrintNewPage(pc);

Any changes to the print context (such as the orientation) will go into
effect for the new page.

Printing scrolling widgets


If you want to print all the contents of a widget that scrolls, you need
some special processing:

September 20, 2005 Chapter 19 ¯ Printing 457


Drawing the desired widgets  2005, QNX Software Systems

PtList
The only way to make a PtList print (or draw) all the items is by
resizing it to be the total height of all the items. The easiest way is
probably by using the resize policy:

☞ This will work only if the total height is smaller than 65K pixels.

1 Open and start the print context.

2 Get the current resize flags (Pt ARG RESIZE FLAGS) for the
PtList widget.

3 Change the resize flags to Pt RESIZE XY ALWAYS, to make the


list resize to fit all of its text.

4 Damage the widget or parent widget.

5 Call PtFlush().

6 Reset the resize flags for the PtList widget.

7 Stop and close the print context.

PtMultiText
Due to a bug in the resize flags of the multitext widget, the method
used for PtList doesn’t currently work on PtMultiText.
To print a PtMultiText widget’s entire text:

1 Open and start the print context.

2 Get the current values of the widget’s


Pt ARG MULTITEXT NUM LINES and
Pt ARG MULTITEXT NUM LINES VISIBLE resources.

3 Save the value of Pt ARG MULTITEXT NUM LINES VISIBLE


in a local variable (remember that PtGetResources() gives you a
pointer into the widget’s internal memory — don’t rely on it to
save the number of visible lines).

458 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Drawing the desired widgets

4 Set Pt ARG MULTITEXT ROWS to the value of


Pt ARG MULTITEXT NUM LINES.

5 To print just the multitext widget, damage it. To print the


widget and its sibling and parent widgets, damage the parent.

6 Call PtFlush().

7 Reset the value of Pt ARG MULTITEXT ROWS to be the saved


number of visible lines.

8 Stop and close the print context.

Here’s a callback that prints a PtMultiText widget:


int
print multi cb( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
int action;
PhDim t size = { 850, 1100 };
long *num lines;
short *num lines visible;
long vis lines;
PtArg t args[2];

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

// These calls to PpPrintSetPC() could be done right


// after creating the print context. Having it here lets
// you reuse the print context.

// Set the source resolution to be proportional to


// the size of a page.
PpPrintSetPC(pc, INITIAL PC, 0,
Pp PC SOURCE SIZE, &size);

action = PtPrintSelection(ABW base, NULL,


"Demo Print Selector", pc,
Pt PRINTSEL DFLT LOOK);

if (action != Pt PRINTSEL CANCEL)


{
// Start printing the pane. Note that we’re using
// the same print context for all print jobs.
PpPrintOpen(pc);

September 20, 2005 Chapter 19 ¯ Printing 459


Drawing the desired widgets  2005, QNX Software Systems

PpPrintStart(pc);

// Get the number of lines and the number of visible lines.

PtSetArg (&args[0], Pt ARG MULTITEXT NUM LINES,


&num lines, 0);
PtSetArg (&args[1], Pt ARG MULTITEXT NUM LINES VISIBLE,
&num lines visible, 0);
PtGetResources (ABW multi, 2, args);

// Save the number of visible lines ina local variable;


// remember that num lines visible points into the widget’s
// internal memory.

vis lines = *num lines visible;

// Set the number of rows to be the number of lines.

PtSetArg (&args[0], Pt ARG MULTITEXT ROWS, *num lines, 0);


PtSetResources (ABW multi, 1, args);

// Damage the widget

PtDamageWidget(ABW multi);
PtFlush();

// Close the print context


PpPrintStop(pc);
PpPrintClose(pc);

// Reset the number of rows to be the saved number of visible lines

PtSetArg (&args[0], Pt ARG MULTITEXT ROWS, vis lines, 0);


PtSetResources (ABW multi, 1, args);
}

return( Pt CONTINUE );
}

PtScrollArea
For a PtScrollArea, you need to print its virtual canvas, which is
where all widgets created within or moved to a scroll area are placed:

1 Get a pointer to the virtual canvas by calling:


PtValidParent( ABW Scroll area, PtWidget );

460 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Suspending and resuming printing

2 Get the area (Pt ARG AREA) of the virtual canvas, and use its
size member as the source size in the print context.

3 Set the print context’s source offset to:


PtWidgetOffset( PtValidParent( ABW Scroll area,
PtWidget ));

4 Print the scroll area’s virtual canvas by calling:


PpPrintWidget( pc, PtValidParent( ABW Scroll area,
PtWidget ),
NULL, NULL, opt);


You can’t print a scrollarea’s virtual canvas by damaging it; you must
use PpPrintWidget().

Suspending and resuming printing


To suspend a print job and direct all draw events back to the graphics
driver at any point after calling PpPrintStart(), call:
PpPrintStop( pc );

To resume a print job, reactivating the print context, causing draw


events to be directed towards the destination specified in the print
context, call:
PpPrintStart( pc );

Closing printing
When you’re finished printing your widgets, the print context must be
deactivated and closed. This is done by calling:
PpPrintStop(pc);
PpPrintClose(pc);

September 20, 2005 Chapter 19 ¯ Printing 461


Multiple print sessions  2005, QNX Software Systems

All draw events will be directed to the graphics driver.

☞ You can reuse the print context for new print jobs, eliminating the
need to create and initialize it again.

Multiple print sessions


You can have multiple print sessions and switch between them very
easily. For example, to print some widgets on one printer and other
widgets on a different printer:
// Create and set up pc1 and
// pc2 for separate printers

PpPrintStart(pc1);
// Print widget 1...
PpPrintStop(pc1);

PpPrintStart(pc2);
// Print widget 2...
PpPrintStop(pc2);

Freeing the print context


When printing is complete and you no longer need the print context,
you can free it, which in turn frees any resources used by it.
If you want to remember any information from the print context for
future use, save it by calling PpPrintGetPC() before freeing the print
context. For example:
short const *orientation;
...
PpPrintGetPC( pc, Pp PC ORIENTATION, &orientation );

To free a print context, call:


PpPrintReleasePC( pc );

462 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Example

Example
This example creates an application with a main window, and a pane
with a few widgets on it. When you press the Print button, a Print
Selection Dialog appears. When you select this dialog’s Print or
Preview button, the pane is damaged and the changes are flushed.
#include <stdio.h>
#include <stdlib.h>
#include <Pt.h>

PtWidget t *pane, *window;


PpPrintContext t *pc;

int quit cb ( PtWidget t *widget, void *data,


PtCallbackInfo t *cbinfo)
{
PpPrintReleasePC (pc);
exit (EXIT SUCCESS);
return (Pt CONTINUE);
}

int print cb ( PtWidget t *widget, void *data,


PtCallbackInfo t *cbinfo)
{
int action;

// These calls to PpPrintSetPC() could be done right


// after creating the print context. Having it here lets
// you reuse the print context.
PhDim t size = { 850, 1100 };
PhDim t size2 = { 200, 150 };

// Set the source resolution to be proportional to


// the size of a page.
PpPrintSetPC(pc, INITIAL PC, 0,
Pp PC SOURCE SIZE, &size);

// Uncomment this to set the source size to be the size


// of the widget. The widget will be scaled when printed.
//PpPrintSetPC(pc, INITIAL PC, 0,
// Pp PC SOURCE SIZE, &size2);

action = PtPrintSelection(window, NULL,


"Demo Print Selector", pc,
Pt PRINTSEL DFLT LOOK);
if (action != Pt PRINTSEL CANCEL)
{
// Start printing the pane. Note that we’re using

September 20, 2005 Chapter 19 ¯ Printing 463


Example  2005, QNX Software Systems

// the same print context for all print jobs.


PpPrintOpen(pc);
PpPrintStart(pc);

// damage the widget


PtDamageWidget(pane);
PtFlush();

// close the print context


PpPrintStop(pc);
PpPrintClose(pc);
}

return (Pt CONTINUE);


}

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


{
PtArg t args[4];
PtWidget t *print, *quit;
PhDim t win dim = { 200, 200 };
PhArea t pane area = { {0, 0}, {200, 150} };
PhArea t print area = { {30, 170}, {60, 20} };
PhArea t quit area = { {110, 170}, {60, 20} };
PhArea t cir area = { {35, 20}, {130, 110} };
PhArea t cir2 area = { {67, 40}, {20, 20} };
PhArea t cir3 area = { {110, 40}, {20, 20} };
PhArea t cir4 area = { {85, 80}, {30, 30} };
PtCallback t callbacks[2] = { {print cb, NULL},
{quit cb, NULL} };

// create the main window


PtSetArg (&args[0], Pt ARG DIM, &win dim, 0);
PtSetArg (&args[1], Pt ARG WINDOW TITLE,
"Print Example", 0);
if ((window = PtAppInit(NULL, &argc,
argv, 2, args)) == NULL)
exit (EXIT FAILURE);

// create a print context


pc = PpPrintCreatePC();

// create the pane to be printed


PtSetArg (&args[0], Pt ARG AREA, &pane area, 0);
pane = PtCreateWidget (PtPane, window, 1, args);

// put some stuff in the pane to be printed


PtSetArg (&args[0], Pt ARG AREA, &cir area, 0);
PtCreateWidget (PtEllipse, pane, 1, args);

464 Chapter 19 ¯ Printing September 20, 2005


 2005, QNX Software Systems Example

PtSetArg (&args[0], Pt ARG AREA, &cir2 area, 0);


PtSetArg (&args[1], Pt ARG FILL COLOR, Pg BLACK, 0);
PtCreateWidget (PtEllipse, pane, 2, args);

PtSetArg (&args[0], Pt ARG AREA, &cir3 area, 0);


PtSetArg (&args[1], Pt ARG FILL COLOR, Pg BLACK, 0);
PtCreateWidget (PtEllipse, pane, 2, args);

PtSetArg (&args[0], Pt ARG AREA, &cir4 area, 0);


PtCreateWidget (PtEllipse, pane, 1, args);

// create the print button


PtSetArg(&args[0], Pt ARG AREA, &print area, 0);
PtSetArg(&args[1], Pt ARG TEXT STRING, "Print", 0);
PtSetArg(&args[2], Pt CB ACTIVATE, &callbacks[0], 0);
print = PtCreateWidget (PtButton, window, 3, args);

// create the quit button


PtSetArg(&args[0], Pt ARG AREA, &quit area, 0);
PtSetArg(&args[1], Pt ARG TEXT STRING, "Quit", 0);
PtSetArg(&args[2], Pt CB ACTIVATE, &callbacks[1], 0);
quit = PtCreateWidget (PtButton, window, 3, args);

PtRealizeWidget(window);
PtMainLoop();
return (EXIT SUCCESS);
}

September 20, 2005 Chapter 19 ¯ Printing 465


Chapter 20
Regions

In this chapter. . .
Photon coordinate space 469
Region coordinates 470
Regions and event clipping 474
Placement and hierarchy 475
Using regions 481
System information 483

September 20, 2005 Chapter 20 ¯ Regions 467


 2005, QNX Software Systems Photon coordinate space

In Photon, all applications consist of one or more rectangles called


regions, which reside in an abstract, three-dimensional event space.

Photon coordinate space


The Photon coordinate space looks like this:
(-32K, -32K) (+32K, -32K)

Upper-left Upper-right
quadrant quadrant

(0, 0)
VGA
display

(640, 480)
Lower-left Lower-right
quadrant quadrant

(-32K, +32K) (+32K, +32K)

Photon coordinate space.

☞ Unlike the typical Cartesian layout, the lower-right quadrant is the


(+,+) quadrant.

The root region has the same dimensions as the entire coordinate
space. As a rule, graphics drivers map the display screen to the
location shown in the above diagram and place the Photon origin at
the upper-left corner of the display screen. (Graphics drivers equate a
single Photon coordinate to a single pixel value on your display
screen).

September 20, 2005 Chapter 20 ¯ Regions 469


Region coordinates  2005, QNX Software Systems

Region coordinates
Region origins
When an application specifies coordinates within a given region, these
are relative to the region’s origin. The application specifies this origin
when it opens the region.

Initial dimensions and location


The initial dimensions of a region (i.e. rect argument in
PhRegionOpen()) are relative to its origin. These dimensions control
the range of the coordinates that the application can use within the
region.
Let’s look at some examples to get an idea of the relationship between
a region’s origin and its initial rectangle coordinates. These examples
illustrate how opened regions are placed in relation to the root region,
which has its origin in the center of the Photon coordinate space.

470 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems Region coordinates

Origin at (0,0) and initial rectangle at (0,0)


As a rule, applications use the following approach for regions. (These
kinds of regions are described in the section “Photon window
manager” of the Photon Architecture appendix.)

Coordinates: Origin = (0,0)


Upper left of initial rectangle = (0,0)
Lower right of initial rectangle = (100,100)

Root region

Child's origin

(0, 0)

(100, 100)

Parent's origin

September 20, 2005 Chapter 20 ¯ Regions 471


Region coordinates  2005, QNX Software Systems

Origin at (0,0) and initial rectangle not at (0,0)


The following example shows an approach typically used for regions
that fill the entire coordinate space. For example, for the device region
and the workspace region, the upper left is (-32000,-32000) and the
lower right is (32000,32000).

Coordinates: Origin = (0,0)


Upper left of initial rectangle = (-50,-50)
Lower right of initial rectangle = (50,50)

Root region

Child's origin

(-50, -50)

(50, 50)

Parent's origin

472 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems Region coordinates

Origin not at (0,0) and initial rectangle not at (0,0)


The following example shows how a child’s origin can differ from its
parent’s origin.

Coordinates: Origin = (-50,-50)


Upper left of initial rectangle = (0,0)
Lower right of initial rectangle = (100,100)

Root region

Child's origin

(0, 0)

(50, 50) for parent


(100, 100) for child

Parent's origin

About child regions


Coordinates are always relative to a region. So when a region is
moved, all its children automatically move with it. Likewise, when a
region is destroyed, its children are destroyed.

☞ To become larger than any other of the application’s regions, a region


must make itself a child of the root region, using PhRegionOpen() or
PhRegionChange(). This action severs the region’s relationship with
its former parent.

September 20, 2005 Chapter 20 ¯ Regions 473


Regions and event clipping  2005, QNX Software Systems

Regions and event clipping


A region can emit or collect events only where it overlaps with its
parent. For example, in the following diagram:

¯ Child 1 can emit or collect events anywhere in its region

¯ Child 2 can emit or collect events only in the smaller gray area that
overlaps with its parent region
Parent region 1 Root region

Child region 1

Parent region 2

Child region 2

Regions and event clipping.

Because of this characteristic of regions, any portion of a region that


doesn’t overlap its parent is effectively invisible.

474 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems Placement and hierarchy

Placement and hierarchy


Region hierarchy
In Photon, every region has a parent region. This parent-child
relationship results in a region hierarchy with the root region at the
top. The following diagram shows the hierarchy of a typical Photon
system:
Root region

Device region Window Manager


(Workspace region)

Graphics Pointer Keyboard Window Manager Window Window Window Manager


region region region (Focus region) Frame Frame (Backdrop region)
region region

Application Application Widget


or Window or Window region
region region

Hierarchy of regions for a typical Photon system.

Parent region
The Photon Manager always places child regions in front (i.e. on the
user side) of their parents:

Root region

Parent region

Child region

September 20, 2005 Chapter 20 ¯ Regions 475


Placement and hierarchy  2005, QNX Software Systems

☞ When opening a region, an application specifies the region’s parent. If


an application opens a region without specifying its parent, the
region’s parent is set to a default — basic regions become children of
the root region and windows become children of the window
manager’s backdrop region.

Brother regions
Besides having a parent, a region may have “brothers,” i.e. other
regions who have the same parent. A region knows about only two of
its brothers — the one immediately in front and the one immediately
behind.
The following diagram shows a parent with three children, and the
relationship that child region 2 has with its brothers:

Root region

Parent region

Brother behind Child regions

Child region 2

Brother in front

When the application opens a region (e.g. child region 2 in the above
diagram), it can specify neither, one, or both immediate brothers.
Depending on how the application specifies these brothers, the new
region may be placed according to default rules (see below) or at a
specific location.

476 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems Placement and hierarchy

☞ If an application opens a region, specifying both brothers, and this


action results in an ambiguous placement request, the resulting
placement is undefined.

Default placement
If an application opens a region without specifying brothers, the
Photon Manager places that region using default placement rules. In
most cases, these rules cause a newly opened region to be placed in
front of its frontmost brother, which then becomes “brother behind”
of the new region. (To use different placement rules, you can specify
the Ph FORCE FRONT flag.)
For example, in the following diagram, child region 1 is the frontmost
region:

Root region

Parent region

Child region 1

When the application opens child region 2 with default placement


(next diagram), region 2 is placed in front of region 1. Region 1
becomes region 2’s brother “behind.” Region 2 becomes region 1’s
brother “in front.”

September 20, 2005 Chapter 20 ¯ Regions 477


Placement and hierarchy  2005, QNX Software Systems

Root region

Parent region

Child region 1

Child region 2

Ph FORCE FRONT flag

An application uses the Ph FORCE FRONT flag when it wants a region


to remain in front of any subsequent brothers that rely on the Photon
Manager’s default placement.
As mentioned earlier, when a region is opened with default placement,
it’s placed ahead of its frontmost brother. But if any brother has the
Ph FORCE FRONT flag set, then the new region is placed behind the
farthest brother that has the Ph FORCE FRONT flag set.
For example, let’s see what would happen in the following example if
child region 1 had the Ph FORCE FRONT flag set:

Root region

Parent region

Child region 1
(forced to front)

When child region 2 is opened with default placement (next diagram),


it’s placed behind region 1, and region 1 becomes its “brother in
front.” Because region 2 was placed using default rules, it doesn’t
inherit the Ph FORCE FRONT setting of region 1:

478 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems Placement and hierarchy

Root region

Parent region

Child region 2

Child region 1
(forced to front)

Then, if child region 3 is opened with default placement, it’s placed as


follows:

Root region

Parent region

Child region 2

Child region 3

Child region 1
(forced to front)

☞ The application can set the Ph FORCE FRONT flag when it opens a
region (or later) by changing the region’s flags. The state of this flag
doesn’t affect how the region itself is placed, but rather how
subsequent brothers are placed if those brothers are opened using
default placement rules. That is, the Ph FORCE FRONT state of
existing brothers doesn’t affect the placement of a new region if it’s
opened with specified brother relations. See the next section, Specific
placement.

September 20, 2005 Chapter 20 ¯ Regions 479


Placement and hierarchy  2005, QNX Software Systems

Remember that the Ph FORCE FRONT flag affects placement only


among brother regions — a child region always goes in front of its
parent.

Specific placement
In contrast to default placement, if any brother is specified when a
region is opened, then that specification controls the placement of the
new region. We refer to this as specific placement.
If a “behind” brother is specified, then the newly opened region
automatically is placed in front of that brother.
If an “in front” brother is specified, then the newly opened region is
automatically placed behind that brother.

☞ The Ph FORCE FRONT setting of the specified brother is inherited by


the new region. If an application opens a region, specifying both
brothers, and this results in an ambiguous placement request, then the
resulting placement is undefined.

480 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems Using regions

Using regions
Opening a region
To open a region, create a PtRegion widget. The PtRegion widget
isn’t available in PhAB; to instantiate it, you’ll have to call
PtCreateWidget() in your application.
For more information on the PtRegion widget, see the Widget
Reference.

Placing regions
While a region is always in front of its parent, the region’s placement
relative to its brothers is flexible. See “Placement and hierarchy” for
more information about “default” and “specific” placement.
The PhRegion t structure contains the following members. These
indicate the relationship of a region with its siblings:

¯ bro in front — indicates the sibling immediately in front

¯ bro behind — indicates the sibling immediately behind

To retrieve this information, you can use PhRegionQuery().

Changing region placement


An application can specify a region’s placement when it opens the
region, or it can change the placement later on. To change a region’s
placement, the application must change the relationship between the
region and the region’s family.
The application does this by doing any or all of the following:

¯ setting the parent, bro front, and bro behind members of the
PhRegion t structure

¯ setting the corresponding fields bits to indicate which members are


valid (only those fields marked as valid will be acted on)

¯ calling the PhRegionChange() function

September 20, 2005 Chapter 20 ¯ Regions 481


Using regions  2005, QNX Software Systems

☞ Since an application can be sure of the position of only the regions it


owns, it shouldn’t change the position of any other regions.
Otherwise, by the time the application makes a request to change the
position of a region it doesn’t own, the information retrieved by
PhRegionQuery() may not reflect that region’s current position. That
is, a request to change a region’s placement may not have the results
the application intended.

Changing the parent


You can change a region’s parent in two ways. The first and simplest
way is to specify the parent in the parent member of the PhRegion t
structure. This makes that region the parent of the region specified in
the rid member of PhRegion t. However, if you set parent to 0, then
the region’s parent is set to a default. For a basic region, the root
region becomes the parent. For a window frame region, the window
manager’s backdrop region becomes the parent.
The other way to change a region’s parent is to specify a child of
another parent as the region’s brother. This makes the region a child
of that parent.

Specifying brothers

If you set: Then:


bro behind The region indicated in the rid member of
PhRegion t moves in front of the bro behind
region
bro in front The region indicated in the rid member of
PhRegion t moves behind the bro in front region

As discussed in “Changing the parent,” a region inherits the parent of


any specified brothers that are children of another parent.

482 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems System information

System information
You can get the following information about your system:

¯ the version of your Photon server

¯ the bandwidth of communication between your window and the


Photon server

¯ information about regions that intersect your window:


- graphics regions
- keyboard regions
- pointer regions
- input group regions

☞ You don’t get information about each region. Instead, you get the
minimum value of each type of information.
For example, if several regions overlapping your window have
different bandwidths, the bandwidth given is the minimum of them.

There are two functions that you can use to get system information:

PhQuerySystemInfo()
Get the information for a given region.
PtQuerySystemInfo()
Get the information for a widget (usually a window).

PhQuerySystemInfo() sends a message to the server each time that


you call it.
PtQuerySystemInfo() calls PhQuerySystemInfo(), but buffers the
information. When a region that intersects your widget changes (for
example, it’s moved), the buffer is marked as invalid. The next time
you call PtQuerySystemInfo(), it calls PhQuerySystemInfo() again. By
using the buffer whenever possible, PtQuerySystemInfo() keeps the
number of messages to a minimum.

September 20, 2005 Chapter 20 ¯ Regions 483


System information  2005, QNX Software Systems

Both PtQuerySystemInfo() and PhQuerySystemInfo() fill in a structure


of type PhSysInfo t that your application has allocated. This
structure contains at least the following:

PhGeneralSysInfo t gen
general information. Always examine this.

PhGrafxInfo t gfx
information on graphics regions

PhKbdInfo t kbd
information on keyboard regions

PhPtrInfo t ptr
information on graphics regions

PhIgInfo t ig
information on input-group regions

☞ Always examine the general information gen first, to see which of the
other structures contain data.

The gen structure contains at least the following:

ulong t valid fields


Indicates which of the other fields are valid, as described below.
ushort t version
the version of the Photon server
ulong t bandwidth
the estimated bandwidth between your process and the Photon
server
ulong t capabilities
not in use

484 Chapter 20 ¯ Regions September 20, 2005


 2005, QNX Software Systems System information

ushort t num gfx


the number of graphics regions
ushort t num kbd
the number of keyboard regions
ushort t num ptr
the number of pointer regions
ushort t num ig
the number of input-group regions

The valid fields field is a set of flags that indicates which of the other
fields are valid. The flags include:

¯ Ph GEN INFO BANDWIDTH

¯ Ph GEN INFO CAPABILITIES

¯ Ph GEN INFO NUM GFX

¯ Ph GEN INFO NUM KBD

¯ Ph GEN INFO NUM PTR

¯ Ph GEN INFO NUM IG

For example, before referring to gfx in the PhSysInfo t structure,


you should check that it’s valid:
if (sysinfo.gen.valid fields & Ph GEN INFO NUM GFX)
{
/* It’s valid. */
...
}

The other fields in the PhSysInfo t structure are similar. Each has a
valid fields field that you should check before using the data. For
details on these structures, see the <photon/PhT.h> header file.
One field that’s of particular interest is the graphics bandwidth, in
gfx.bandwidth. This value can be used to modify the behavior of an

September 20, 2005 Chapter 20 ¯ Regions 485


System information  2005, QNX Software Systems

interface based on the connection speed. For example, a simple state


change could be substituted for an elaborate animation if the
bandwidth is Ph BAUD SLOW or less. It’s also a good idea to see if
shared memory can be used for drawing; the Ph GCAP SHMEM flag is
set in gfx.capabilities if all the graphics drivers support the ...mx()
functions and they’re all running on your node.

486 Chapter 20 ¯ Regions September 20, 2005


Chapter 21
Events

In this chapter. . .
Pointer events 489
Emitting events 491
Event coordinates 496
Collecting events 496
Event compression 496
Dragging 496

September 20, 2005 Chapter 21 ¯ Events 487


 2005, QNX Software Systems Pointer events

The interactions between applications, users and the Photon server are
represented by data structures called events.
Event information is stored in structures of type PhEvent t; see the
Photon Library Reference.

Pointer events
Most of the time, you can use a widget’s callbacks to handle what the
user does while pointing to it. If you’re working with raw events,
you’ll need to know what events Photon emits.

Pressing a button
When you press the pointer button, Photon emits a Ph EV BUT PRESS
event to the widget that currently has focus.

Releasing a button
When you release the button, Photon emits two Ph EV BUT RELEASE
events:

¯ One with subtype Ph EV RELEASE REAL

¯ One with subtype Ph EV RELEASE PHANTOM.

The REAL release hits whatever the mouse points to when you
release the button. The PHANTOM release always goes to the same
region (and position) that received the press.
In other words, if your widget saw the press, it will also see the
PHANTOM release. And depending on where the mouse was
pointing to, you may or may not get the REAL release.

Multiple clicks
Whenever the user presses or releases the mouse button, the event
includes the click count. How do you determine that the user clicked,
instead of double click?
If you keep clicking quickly enough without moving the mouse, the
counter keeps incrementing. If you move the mouse or stop clicking

September 20, 2005 Chapter 21 ¯ Events 489


Pointer events  2005, QNX Software Systems

for a while, the counter resets and Photon emits a


Ph EV BUT RELEASE event with a subtype of
Ph EV RELEASE ENDCLICK.
In other words, the first click generates a Ph EV BUT PRESS event
and a pair of Ph EV BUT RELEASE events (one REAL and one
PHANTOM) with click count set to 1. Then, depending on whether
the user clicks again soon enough or not, you get either:

¯ A Ph EV BUT PRESS event and a pair of Ph EV BUT RELEASE


events with click count set to 2
Or:

¯ A Ph EV BUT RELEASE event with a subtype of


Ph EV RELEASE ENDCLICK.

After the second click, you either get a third one or an ENDCLICK,
and so on. But eventually you get an ENDCLICK — and the next
time the person clicks, the click count is 1 again.

Modifier keys
If you need to determine what keys were pressed in a pointer event,
call PhGetData() to get the event data that’s included for
Ph EV BUT PRESS and Ph EV BUT RELEASE events. The data for
these events is a structure of type PhPointerEvent t; check its
key mods member to determine the modifier keys that were pressed.
For more information about the PhPointerEvent t structure, see
the description of Ph EV BUT PRESS in documentation for
PhEvent t in the Photon Library Reference.
For example, this Pt CB ACTIVATE callback lists the modifier keys
that were pressed when the pointer button was released:

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>

490 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Emitting events

#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "abimport.h"
#include "proto.h"

int
check keys( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

PhPointerEvent t *event data;

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

if (cbinfo->event->type != Ph EV BUT RELEASE) {


printf ("Not a Ph EV BUT RELEASE event\n");
} else {
printf ("It’s a Ph EV BUT RELEASE event\n");

event data = (PhPointerEvent t *)


PhGetData (cbinfo->event);

if (event data->key mods & Pk KM Shift )


printf (" Shift\n");

if (event data->key mods & Pk KM Ctrl )


printf (" Ctrl\n");

if (event data->key mods & Pk KM Alt )


printf (" Alt\n");

}
return( Pt CONTINUE );
}

Emitting events
The most general way for your application to emit an event is to call
PhEventEmit():

int PhEventEmit( PhEvent t *event,

September 20, 2005 Chapter 21 ¯ Events 491


Emitting events  2005, QNX Software Systems

PhRect t *rects,
void *data );

The arguments are:

event A pointer to a PhEvent t structure. The application


emitting the event needs to set the following members:
¯ type — the type of event.
¯ subtype — the event subtype (if necessary).
¯ flags — event modifiers (e.g. direction).
¯ emitter — a PhEventRegion t structure; you need to
set at least the ID of the region that’s emitting the event.
¯ translation — typically set to (0,0) when emitting an
event.
¯ num rects — the number of rectangles in the function’s
rects argument. If you set num rects to 0, you must also
pass rects as NULL.
The Photon Manager sets the following members of the
event structure after it has enqueued a copy of the event to
an application:
¯ timestamp — the time when this event was emitted (in
milliseconds).
¯ collector — a PhEventRegion t structure that
includes the ID of the collecting region.
rects An array of PhRect t structures (see the Photon Library
Reference) indicating the event’s initial rectangle set. If this
argument is NULL, the set consists of a single rectangle
corresponding to the emitting region.
data Valid data for the type of event being emitted. Each type of
event has its own type of data, as described for the
PhEvent t structure in the Photon Library Reference.
If the event-specific data isn’t in contiguous memory, you
may find PhEventEmitmx() more useful than
PhEventEmit():

492 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Emitting events

int PhEventEmitmx( PhEvent t *event,


PhRect t *rects,
int mxparts,
struct mxfer entry *mx );

The return codes for PhEventEmit() and PhEventEmitmx() are:

0 Successful completion.

-1 An error occurred, or no further events are pending. Check the


value of errno:
¯ If errno is ENOMSG, Photon had no messages enqueued to
your application at the time you emitted the event.
¯ If errno isn’t ENOMSG, an error occurred.

These return codes are useful for applications that spend most of their
time emitting events and want to retrieve an event only if there’s one
pending for them.

Targeting specific regions


Sometimes an application needs to target an event directly at a
specific region, without making the event travel through the event
space before arriving at that region. You can use an inclusive event or
a direct event to ensure that the targeted region sees the event.

Inclusive event
For an inclusive event, do the following:

¯ Set the emitter’s region ID (i.e. event->emitter->rid) to the ID of


the target region — this causes the event to be emitted
automatically from that region.

¯ Set Ph EVENT INCLUSIVE on in the flag member of the event —


this causes the Photon Manager to emit the event to the emitting
region before emitting it into the event space.

September 20, 2005 Chapter 21 ¯ Events 493


Emitting events  2005, QNX Software Systems

If you don’t want an inclusive targeted event to continue through the


event space, you must make the emitting region opaque to that type of
event.

Direct event
For a direct event, do the following:

¯ Set the emitter’s region ID (i.e. event->emitter->rid) to the ID of


your application’s region.

¯ Set the collector’s region ID (i.e. event->collector->rid) to the ID


of the target region.

¯ Set Ph EVENT DIRECT on in the flag member of the event — this


causes the Photon Manager to emit the event directly from emitter
to collector.

Targeting specific widgets


If you want to send an event to a specific widget, you could call
PhEventEmit() as described above, but you’ll need to look after a lot
of details, including making sure:

¯ The event is delivered to the right window.

¯ The widget still has focus — there might be other events enqueued
before yours.

It’s easier to call PtSendEventToWidget(). This function gives the


event to the specified widget directly and without delay. It’s much
more deterministic and efficient than PhEventEmit().
The prototype is:

int PtSendEventToWidget( PtWidget t *widget,


PhEvent t *event );

494 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Emitting events

Emitting key events


Sometimes you might need to simulate a key press in your
application. Depending on what exactly you want to achieve, you can
choose from several ways of generating key events:

¯ Emit a Ph EV KEY event from the device region:


event->emitter->rid = Ph DEV RID;

The rectangle set should consist of a single pixel — if you’re not


using the window manager, or if PWM is set to use cursor focus,
the position of that pixel determines which window the event will
hit.

¯ If you know which region you want to send the event to, emit a
Ph EV KEY event directly to that region:
event->collector->rid = rid;
event->flags |= Ph EVENT DIRECT;

¯ Emit a Ph EV RAW event with subtype Ph EV RAW KEY. The


event structure is PhRawKeyEvent t, which is declared in
<photon/PhT.h>). It’s similar to PhKeyEvent t; see the
Photon Library Reference.
If you’re creating a keyboard driver, the region you’re emitting
your events from should have the Ph KBD REGION flag set, and
should belong to an input group. To create a region that belongs to
an input group, set input group in PhRegion t to a nonzero value
(the same that you will put in the events), and set the
Ph REGION INPUT GROUP flag in the fields argument to
PhRegionOpen().
Emit the event directly to the device region:
region (event->collector->rid = Ph DEV RID;
event->flags |= Ph EVENT DIRECT;

Photon will re-emit the event as a regular Ph EV KEY event from


the current position of the pointer.

September 20, 2005 Chapter 21 ¯ Events 495


Event coordinates  2005, QNX Software Systems

Event coordinates
When an event is emitted, the coordinates of its rectangle set are
relative to the emitting region’s origin. But when the event is
collected, its coordinates become relative to the collecting region’s
origin. The Photon Manager ensures this happens by translating
coordinates accordingly.

Collecting events
To collect events, applications call PhEventRead() or PhEventNext().
The PhGetRects() function extracts the rectangle set, and
PhGetData() extracts the event’s data portion.

☞ A region can collect events only if portions of its region overlap with
the emitting region.

Event compression
The Photon Manager compresses drag, boundary, and pointer events.
That is, if an event of that type is pending when another event arrives,
the new event will be merged with the unprocessed events. As a
result, an application sees only the latest values for these events and is
saved from collecting too many unnecessary events.

Dragging
You’ll need to work with events if the user can drag objects in your
application.
There are two types of dragging:

outline dragging
The user sees an outline while dragging. When the dragging is
complete, the application repositions the widget.

496 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Dragging

opaque dragging
The application moves the widget as the dragging progresses.

Dragging is done in two steps:

1 Initiating the dragging, usually when the user clicks on


something.

2 Handling drag (Ph EV DRAG) events.

These steps are discussed in the sections that follow.

Initiating dragging
Where you initiate the dragging depends on how the user is meant to
drag widgets. For example, if the user holds down the left mouse
button on a widget to drag it, initiate dragging in the widget’s Arm
(Pt CB ARM) callback. Make sure that Pt SELECTABLE is set in the
widget’s Pt ARG FLAGS resource.
Dragging is started by calling the PhInitDrag() function:

int PhInitDrag( PhRid t rid,


unsigned flags,
PhRect t *rect,
PhRect t *boundary,
unsigned int input group,
PhDim t *min,
PhDim t *max,
PhDim t *step );

The arguments are used as follows:

rid The region that rect and boundary are relative to.
You can get this by calling PtWidgetRid().

flags Indicate whether outline or opaque dragging is to be


used, and which edge(s) of the dragging rectangle
track the pointer, as described below.

rect Rectangular area to drag.

September 20, 2005 Chapter 21 ¯ Events 497


Dragging  2005, QNX Software Systems

boundary Rectangular area that limits the dragging

input group Get this from the callback’s cbinfo parameter:

cbinfo->event->input group

min, max Minimum and maximum sizes of the drag rectangle.

step Dragging granularity.

If Ph DRAG TRACK is included in flags, then opaque dragging is


used; if Ph DRAG TRACK isn’t included, outline dragging is used.
The following flags indicate which edge(s) of the dragging rectangle
track the pointer:

¯ Ph TRACK LEFT

¯ Ph TRACK RIGHT

¯ Ph TRACK TOP

¯ Ph TRACK BOTTOM

¯ Ph TRACK DRAG — all the above

Outline dragging
The following example shows an Arm (Pt CB ARM) callback that
initiates outline dragging:

/* Start dragging a widget */


/* AppBuilder Photon Code Lib */
/* Version 1.11 */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */

498 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Dragging

#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
start dragging( PtWidget t *widget,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PhDim t *dimension;
PhRect t rect;
PhRect t boundary;
PtArg t args[1];

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

/* Set the dragging rectangle to the position and size of


the widget being dragged. */

PtWidgetExtent (widget, &rect);

/* Set the boundary for dragging to the boundary of the


window. */

PtSetArg (&args[0], Pt ARG DIM, &dimension, 0);


PtGetResources (ABW base, 1, args);
boundary.ul.x = 0;
boundary.ul.y = 0;
boundary.lr.x = dimension->w - 1;
boundary.lr.y = dimension->h - 1;

/* Initiate outline dragging (Ph DRAG TRACK isn’t


specified). */

PhInitDrag (PtWidgetRid (ABW base),


Ph TRACK DRAG,
&rect, &boundary,
cbinfo->event->input group,
NULL, NULL, NULL);

/* Save a pointer to the widget being dragged. */

dragged widget = widget;

September 20, 2005 Chapter 21 ¯ Events 499


Dragging  2005, QNX Software Systems

return( Pt CONTINUE );
}

The above callback is added to the Arm (Pt CB ARM) callback of the
widget to be dragged. It can be used for dragging any widget, so a
pointer to the widget is saved in the global variable dragged widget.

Opaque dragging
If you want to use opaque dragging, add the Ph DRAG TRACK flag to
the call to PhInitDrag():

PhInitDrag( PtWidgetRid (ABW base),


Ph TRACK DRAG | Ph DRAG TRACK,
&rect, &boundary,
cbinfo->event->input group,
NULL, NULL, NULL );

Handling drag events


To handle drag (Ph EV DRAG) events, you need to define a Raw
(Pt CB RAW) callback.

☞ The raw callback must be defined for the widget whose region was
passed to PhInitDrag(), not for the widget being dragged. For the
example given, the Raw callback is defined for the base window.

As described in “Raw-event callbacks” in the Editing Resources and


Callbacks in PhAB chapter, you use an event mask to indicate for
which events your callback is to be called. For dragging, the event is
Ph EV DRAG. The most commonly used subtypes for this event are:

Ph EV DRAG START
the user has started to drag
Ph EV DRAG MOVE
the dragging is in progress (opaque dragging only)

500 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Dragging

Ph EV DRAG COMPLETE
the user has released the mouse button

Outline dragging
If you’re doing outline dragging, the event subtype you’re interested
in is Ph EV DRAG COMPLETE. When this event occurs, your
callback should:

1 Get the data associated with the event. This includes the
location of the dragging rectangle, in absolute coordinates.

2 Calculate the new position of the widget, relative to the


dragging region. This is the position of the upper left corner of
the dragging rectangle, translated by the amount given in the
event’s translation field.

3 Set the widget’s Pt ARG POS resource to the new position.

☞ Remember, the callback’s widget parameter is a pointer to the


container (the base window in the example), not to the widget being
dragged. Make sure you pass the correct widget to PtSetResources()
when setting the Pt ARG POS resource.

For example, here’s the Raw callback for the outline dragging
initiated above:
/* Raw callback to handle drag events */
/* AppBuilder Photon Code Lib */
/* Version 1.11 */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */

September 20, 2005 Chapter 21 ¯ Events 501


Dragging  2005, QNX Software Systems

#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
end dragging( PtWidget t *widget,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PhDragEvent t *dragData;
PtArg t args[1];
PhPoint t new pos;

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

/* Ignore all events until dragging is done. */

if (cbinfo->event->subtype != Ph EV DRAG COMPLETE)


{
return (Pt CONTINUE);
}

/* Get the data associated with the event. */

dragData = PhGetData (cbinfo->event);

/* The rectangle in this data is the absolute


coordinates of the dragging rectangle. We want to
calculate the new position of the widget, relative to
the dragging region. */

new pos.x = dragData->rect.ul.x


+ cbinfo->event->translation.x;
new pos.y = dragData->rect.ul.y
+ cbinfo->event->translation.y;
printf ("New position: (%d, %d)\n", new pos.x, new pos.y);

/* Move the widget. */

PtSetArg (&args[0], Pt ARG POS, &new pos, 0);


PtSetResources (dragged widget, 1, args);

return( Pt CONTINUE );

502 Chapter 21 ¯ Events September 20, 2005


 2005, QNX Software Systems Dragging

Opaque dragging
The callback for opaque dragging is similar to that for outline
dragging — the only difference is the subtype of event handled:

if (cbinfo->event->subtype != Ph EV DRAG MOVE)


{
return (Pt CONTINUE);
}

September 20, 2005 Chapter 21 ¯ Events 503


Chapter 22
Window Management

In this chapter. . .
Window-management flags 507
Notification callback 511
Getting and setting the window state 513
Managing multiple windows 515
Window-manager functions 515
Running a standalone application 516

September 20, 2005 Chapter 22 ¯ Window Management 505


 2005, QNX Software Systems Window-management flags

Sometimes you’ll need to interact with the Photon Window Manager


to make your windows and dialogs behave the way you’d like.

☞ Remember that PhAB’s window and dialog modules are implemented


as PtWindow widgets. PtWindow has many resources that are used to
interact with the Window Manager.

For information about the Window Manager’s regions, see the


appendix on Photon architecture. For a list of related functions, see
“Window Manager” in the Summary of Functions chapter of the
Photon Library Reference.

Window-management flags
The PtWindow widget defines various types of flags:

Pt ARG WINDOW RENDER FLAGS


Which window decorations appear in the window frame.

Pt ARG WINDOW MANAGED FLAGS


How the Window Manager operates on the window.

Pt ARG WINDOW NOTIFY FLAGS


Which Window Manager events your application would like to
be notified of.
Pt ARG WINDOW STATE
The current state of the window.

☞ If you change the state of the window after it’s realized, you’ll need to
let the Window Manager know. See “Getting and setting the window
state” later in this chapter.

September 20, 2005 Chapter 22 ¯ Window Management 507


Window-management flags  2005, QNX Software Systems

Window render flags


The Pt ARG WINDOW RENDER FLAGS resource specifies what
appears in the window’s frame:

To display: Set this bit: Default:


Border Ph WM RENDER BORDER Yes
Resize handles Ph WM RENDER RESIZE Yes
Title bar Ph WM RENDER TITLE Yes
Menu button Ph WM RENDER MENU Yes
Close button Ph WM RENDER CLOSE
Help button (question Ph WM RENDER HELP
mark)
Minimize button Ph WM RENDER MIN Yes
Maximize button Ph WM RENDER MAX Yes

☞ Using these flags to display a decoration doesn’t cause the Window


Manager to do anything with it. You may need to set the window
managed flags and/or notify flags.

Window managed flags


The Pt ARG WINDOW MANAGED FLAGS resource specifies what
operations you want the window manager to handle:

To let the window manager: Set this bit: Default:


Close the window Ph WM CLOSE Yes
Give focus Ph WM FOCUS Yes

continued. . .

508 Chapter 22 ¯ Window Management September 20, 2005


 2005, QNX Software Systems Window-management flags

To let the window manager: Set this bit: Default:


Build and control the window Ph WM MENU Yes
menu
Move the window to the front Ph WM TOFRONT Yes
Move the window to the back Ph WM TOBACK Yes
Move the window to a new Ph WM CONSWITCH
console as the user switches
consoles
Resize the window Ph WM RESIZE Yes
Move the window Ph WM MOVE Yes
Hide (i.e. minimize) the Ph WM HIDE Yes
window
Maximize the window Ph WM MAX Yes
Display the window as a Ph WM BACKDROP
backdrop
Restore the window Ph WM RESTORE Yes
Provide context-sensitive help Ph WM HELP
Make the window force-front Ph WM FFRONT

By default, a selection of these flags are set, as defined by


Ph WM APP DEF MANAGED in <PhWm.h>. You’d turn the
management flags off if:

¯ You don’t want the operation to happen.

¯ You want the application to handle the operation. In this case,


you’ll need to set the appropriate notify flag as well.

Window notify flags


The Pt ARG WINDOW NOTIFY FLAGS resource specifies which
window-manager operations your application should be notified of.

September 20, 2005 Chapter 22 ¯ Window Management 509


Window-management flags  2005, QNX Software Systems

This resource uses the same bits as


Pt ARG WINDOW MANAGED FLAGS:

To be notified when: Set this bit: Default:


The window is to be closed Ph WM CLOSE Yes
(see below)
The window is to gain/lose Ph WM FOCUS
focus
The window menu is requested Ph WM MENU
or dismissed
The window is to be moved to Ph WM TOFRONT
the front
The window is to be moved to Ph WM TOBACK
the back
The window is to switch Ph WM CONSWITCH
consoles
The window is to be resized Ph WM RESIZE Yes
The window is to be moved Ph WM MOVE
The window is to be hidden or Ph WM HIDE
unhidden
The window is to be Ph WM MAX
maximized
The window is to be made into Ph WM BACKDROP
a backdrop
The window is to be restored Ph WM RESTORE
The help button is pressed Ph WM HELP Yes
The window is to be made Ph WM FFRONT
force-front or not force-front

510 Chapter 22 ¯ Window Management September 20, 2005


 2005, QNX Software Systems Notification callback

The default setting is Ph WM RESIZE|Ph WM CLOSE|


Ph WM HELP.
When the requested operations occur, the window’s Pt CB WINDOW
callback is invoked. See “Notification callback” below.
If you set the Ph WM CLOSE notify flag, your application’s
Pt CB WINDOW callback is invoked when someone wants the
window to close. Your application doesn’t have to close the window
— it could decide to leave it open.
In contrast, the Pt CB WINDOW CLOSING callback is called when a
window is being unrealized, but before its region is removed. At this
point, the application can’t stop the window from being closed.

☞ If you’ve set the Ph WM CLOSE managed flag, the window manager


is told to handle the window’s closing. In this case, the
Pt CB WINDOW CLOSING callback is invoked, but the
Pt CB WINDOW callback isn’t.

Notification callback
When a window manager operation occurs that’s listed in the
window’s notify flags (Pt ARG WINDOW NOTIFY FLAGS), the
window’s Pt CB WINDOW callback is invoked.
Each callback function listed in this resource is passed a
PtCallbackInfo t structure that contains at least the following
members:

reason Pt CB WINDOW

reason subtype
0 (not used).
event A pointer to the event that caused the callback to be
invoked.
cbdata A pointer to a PhWindowEvent t (described in the
Photon Library Reference).

September 20, 2005 Chapter 22 ¯ Window Management 511


Notification callback  2005, QNX Software Systems

These callback functions should return Pt CONTINUE.

Example: verifying window closure


Suppose you want to verify that the user really wants to exit the
application when the window is closed. Here’s what you need to do:

¯ Unset Ph WM CLOSE in the


Pt ARG WINDOW MANAGED FLAGS. This tells the window
manager not to close the window.

¯ Set Ph WM CLOSE in the Pt ARG WINDOW NOTIFY FLAGS.


The window manager will notify you when the user tries to close
the window.

¯ Add a Pt CB WINDOW like the following:


int
window callback( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )

{
PhWindowEvent t *we = cbinfo->cbdata;

/* eliminate ’unreferenced’ warnings */


widget = widget, apinfo = apinfo, cbinfo = cbinfo;

if ( we->event f == Ph WM CLOSE ) {
// Ask the user if we should really exit.
switch( PtAskQuestion( ABW base, NULL,
"Do you really want to exit?",
"helv14", "&Yes", "&No", NULL, 1 ) ) {

case 1: /* yes */
exit (EXIT SUCCESS);
break;

case 2: /* no */
return (Pt CONTINUE);
}
} else {
// Check for other events
}

return( Pt CONTINUE );

512 Chapter 22 ¯ Window Management September 20, 2005


 2005, QNX Software Systems Getting and setting the window state

There’s a significant difference between the Ph WM CLOSE event and


the Window Closing (Pt CB WINDOW CLOSING) callback.
A Pt CB WINDOW callback with a Ph WM CLOSE event is just a
notification from PWM that the user has clicked on the Close button
or chosen Close from the PWM menu. If the Ph WM CLOSE bit is
unset in the Pt ARG WINDOW MANAGED FLAGS, the library takes
no further action.
Window Closing is invoked when the window is about to unrealize for
any reason. This includes transporting to another Photon and explicit
calls to PtDestroyWidget() or PtUnrealizeWidget(). If you want to
make sure in a Window Closing callback that the window is actually
being destroyed, check the Pt DESTROYED flag in Pt ARG FLAGS.
You can also use the Pt CB DESTROYED callback to know when a
window is marked for destruction.
Also note that calling exit() explicitly bypasses all those callbacks.

Getting and setting the window state


The Pt ARG WINDOW STATE resource controls what state the
window will be in when it’s realized:

To do this: Set this bit:


Maximize the window Ph WM STATE ISMAX
Make the window a backdrop Ph WM STATE ISBACKDROP
Minimize the window Ph WM STATE ISHIDDEN
Place the base window in front Ph WM STATE ISFRONT
of the windows of all other
applications

continued. . .

September 20, 2005 Chapter 22 ¯ Window Management 513


Getting and setting the window state  2005, QNX Software Systems

To do this: Set this bit:


Give keyboard focus to the Ph WM STATE ISFOCUS
window if cursor focus is
disabled
Pass Alt key combinations to the Ph WM STATE ISALTKEY
application
Block the window Ph WM STATE ISBLOCKED
(read-only)

The default value is Ph WM STATE ISFOCUS.


You can get the state of the window at any time by using
PtGetResources() to get the Pt ARG WINDOW STATE resource.
You can use this resource to set the window state before a window is
realized. For example, you could set it when creating the PtWindow
widget or in the window’s Pt CB WINDOW OPENING callback. The
setting will be in effect when the window is realized. To set the
window state after it’s open, you’ll need to let the window manager
know by calling:

PtForwardWindowEvent()
Change the state for your application’s windows.

PtForwardWindowTaskEvent()
Change the state for another application’s windows.

For example, to minimize a window that belongs to your application


and is already open:

PhWindowEvent t event;

memset( &event, 0, sizeof (event) );


event.event f = Ph WM HIDE;
event.event state = Ph WM EVSTATE HIDE;
event.rid = PtWidgetRid( window );
PtForwardWindowEvent( &event );

514 Chapter 22 ¯ Window Management September 20, 2005


 2005, QNX Software Systems Managing multiple windows

To minimize a window that belongs to another application and is


already open:

PhWindowEvent t event;

memset( &event, 0, sizeof (event) );


event.event f = Ph WM HIDE;
event.event state = Ph WM EVSTATE HIDE;
PtForwardWindowTaskEvent( processid, &event );

☞ When you call these functions, you’re asking the window manager to
do the specified action. If the action isn’t set in the managed flags
(Pt ARG WINDOW MANAGED FLAGS) for the given window, the
window manager doesn’t do it.

Managing multiple windows


If your application has more than one window, you’ll need to take the
relationships between them into account.
By definition, a child window is always in front of its parent. The
child windows can move above and below siblings. For windows to
be able to go behind other windows, they must be siblings. So for a
window to be able to move behind the base window, that window
would have to have no parent.

Window-manager functions
The following low-level functions are associated with the window
manager, but shouldn’t be used in an application that uses widgets:

PhWindowChange()
Modify the attributes of a window’s region

PhWindowClose()
Close a window

September 20, 2005 Chapter 22 ¯ Window Management 515


Running a standalone application  2005, QNX Software Systems

PhWindowOpen()
Create a window region

These functions can be called in an application that uses widgets:

PhWindowQueryVisible()
Query a visible extent
PtConsoleSwitch()
Switch to another virtual console
PtForwardWindowEvent()
Forward a window event
PtForwardWindowTaskEvent()
Forward a window event to a task

PtFrameSize() Estimate the size of the window frame

PtWindowConsoleSwitch()
Switch to the console a given window’s displayed
on

Running a standalone application


If your application is intended to run by itself, you might want to:

¯ Make your application fill the screen. Set Ph WM STATE ISMAX


in the base window’s Pt ARG WINDOW STATE resource.

¯ Turn off all the flags in the base window’s


Pt ARG WINDOW RENDER FLAGS so that the window won’t
get a title bar, borders, menu buttons, and so on — there’s no use
having them if there aren’t any other applications running.

For information on starting your application automatically, see


“Booting directly into Photon” in the Configuring Photon chapter of
the Photon Installation & Configuration guide.

516 Chapter 22 ¯ Window Management September 20, 2005


Chapter 23
Programming Photon without PhAB

In this chapter. . .
Basic steps 519
Compiling and linking a non-PhAB application 520
Sample application 521
Connecting application code to widgets 525
Complete sample application 526

September 20, 2005 Chapter 23 ¯ Programming Photon without PhAB 517


 2005, QNX Software Systems Basic steps

We strongly recommend that you use PhAB to develop Photon


applications — this chapter is for those who insist on not using PhAB.

Basic steps
All applications using the Photon widget library follow the same basic
sequence:

1 Include <Pt.h>, the standard header file for the widget library.

2 Initialize the Photon widget toolkit and create the main window
using a call to PtAppInit().

3 Create the widgets that make up the UI. The function


PtCreateWidget() is used to create the widget and make it a
child of a widget that has already been created, such as the
main window.

4 Register any callback functions in the application with the


appropriate widgets using PtAddCallback() or
PtAddCallbacks().

5 Realize the widgets by calling PtRealizeWidget(). This function


needs to be called only once by the application.
The realize step actually creates any Photon regions that are
required and maps them to the screen. Until this step is
performed, no regions exist, and nothing is displayed on the
screen.

6 Begin processing photon events by calling PtMainLoop().


At this point, the Photon widget toolkit takes control over the
application and manages the widgets. If any widgets are to call
functions in your application, they must have been registered as
callbacks before this.

September 20, 2005 Chapter 23 ¯ Programming Photon without PhAB 519


Compiling and linking a non-PhAB application  2005, QNX Software Systems

Compiling and linking a non-PhAB


application
To compile and run an application that uses the Photon widget library,
you must link against the library. There are both static and shared
versions of this library. The names depend on whether you’re running
under QNX 4 or QNX Neutrino:

Library QNX 4 QNX Neutrino


Static photon3r.lib libphoton.a
Shared photon s.lib libphoton.so

We recommended that you always link against the shared library.


This lets you keep your applications smaller and allows them to
inherit new features that are added to the widget library when new
releases of the shared library are installed.
The Photon library includes most of the function and widget
definitions. If your application uses Px (extended) functions or
realtime widgets, you’ll also need to link with the following:

Library QNX 4 QNX Neutrino


Extended phexlib3r.lib libex.a
Realtime phrtlib3r.lib libphrt.a

Linking under QNX 4


To link against the shared library, specify the following link option for
the cc command:

-lphoton s

To link against the static library, specify the following link option:

520 Chapter 23 ¯ Programming Photon without PhAB September 20, 2005


 2005, QNX Software Systems Sample application

-lphoton

For example, if we have an application called hello.c, the command


to compile and link is:

cc -o hello hello.c -lphoton s

Linking under QNX Neutrino


Under Neutrino, the names of the shared and static libraries are the
same. By default, qcc links against the shared library; to link against
the static library, specify the -Bstatic option for qcc.

☞ You’ll also need to link against the math library, libm.so or libm.a.

For example, if we have an application called hello.c, the command


to compile and link against the shared libraries is:

qcc -o hello hello.c -lphoton -lm

To link against the static libraries, the command is:

qcc -o hello hello.c -Bstatic -lphoton -lm

Sample application
The following example illustrates a very simple application using the
widget library. The program creates a window that contains a single
pushbutton.
/*
* File: hello.c
*/
#include <Pt.h>

September 20, 2005 Chapter 23 ¯ Programming Photon without PhAB 521


Sample application  2005, QNX Software Systems

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


{
PtWidget t *window;
PtArg t args[1];

if ((window = PtAppInit(NULL, &argc, argv, 0, NULL))


== NULL)
exit(1);

PtSetArg(&args[0], Pt ARG TEXT STRING,


"Press to exit", 0);
PtCreateWidget(PtButton, window, 1, args);
PtRealizeWidget(window);

PtMainLoop();
return (EXIT SUCCESS);
}

What’s going on
Although this is a simple application, a lot of work is being done by
each of these calls.

PtAppInit()
This PtAppInit() call:

¯ reads any standard toolkit arguments from the command line

¯ attaches a channel to the Photon server using PhAttach()

¯ creates a window widget that is designed to interact with the


window manager and serve as the parent for other widgets created
in the application.

The first argument to this function passes the address of


PtAppContext t, which is a pointer to a structure that manages all
the data associated with this application. For Photon 1.1x, this must
be specified as NULL, so that the default values are used.
The second and third arguments are the common argc and argv. The
toolkit parses these for standard toolkit options.

522 Chapter 23 ¯ Programming Photon without PhAB September 20, 2005


 2005, QNX Software Systems Sample application

The final two arguments are an argument list, preceded by the number
of elements in the list. They’re used to provide initial values for
resources of the top-level window widget when it’s created. A pointer
to this widget is returned by PtAppInit(). This top-level widget will
become the parent of subsequent widgets created in the application.
See the Widget Reference for more information on this widget and its
available resources.

PtSetArg()
The PtSetArg() macro is used to set up an argument list that will be
used to initialize the button’s resources when it’s created. For more
information, see the Manipulating Resources in Application Code
chapter.

PtCreateWidget()
The call to PtCreateWidget() creates a push-button widget as a child
of the window widget, using the argument list to initialize the button’s
resources. All the widgets in the application — except the top-level
shell window — have a container widget as a parent. Container
widgets may have other containers within them. Creating the widgets
in the application produces a structure called the widget family.

PtRealizeWidget()
The function PtRealizeWidget() realizes the widget and all its
descendants in the widget family. Realizing a widget causes it to be
displayed. In our sample application, PtRealizeWidget() is called on
the top-level shell window (which is the ancestor of all the widgets in
the application), so all the widgets in the application are displayed
when this routine is called.
When the widget is realized, it uses the values of its resources to
determine how big it must be to display its contents. Before realizing
a widget, you should set any of the resources that may affect its size.
You may change some of the resources after the widget has been
realized, but it’s up to the widget to determine if it can or will resize to
accommodate the change in the resource’s value. You can set flags
that the widget will consult to determine whether or not to adjust its

September 20, 2005 Chapter 23 ¯ Programming Photon without PhAB 523


Sample application  2005, QNX Software Systems

size in response to such changes, but note that if the widget exceeds
the dimensions allocated to it by its parent, it will be clipped to the
parent’s size. There’s no mechanism for the widget to negotiate with
its parent to obtain more space. See the Geometry Management
chapter for more information.
If a Photon region is required to display the widget correctly, it’s
created each time the widget is realized. A region is required under
any of the following conditions:

¯ the widget sets a cursor

¯ the widget needs to get events that aren’t redirected to it by its


parent container (e.g. boundary, pointer-motion events)

¯ the Pt REGION flag is set for the widget

You can unrealize a widget by calling the PtUnrealizeWidget()


function. This affects the visibility of the widget and its descendants,
but not the rest of the widget family hierarchy. You can then redisplay
the widget later by calling PtRealizeWidget() again.
You can prevent a widget and its descendants from being realized
when the widget’s ancestor is realized. To do this, set
Pt DELAY REALIZE in the widget’s Pt ARG FLAGS resource. If you
set this flag, it’s the application’s responsibility to call
PtRealizeWidget() on the widget when the widget is to appear.

PtMainLoop()
Calling PtMainLoop() transfers control of the application to the
Photon widget library.
The widget library waits for Photon events and passes them on to the
widgets to handle them. Application code is executed only when
callback functions that the application has registered with a widget are
invoked as a result of some event.

524 Chapter 23 ¯ Programming Photon without PhAB September 20, 2005


 2005, QNX Software Systems Connecting application code to widgets

Connecting application code to widgets


If you compile, link, and run the sample application, you’ll see that a
window appears with a button in it. If you push the button, nothing
happens because no application code has been associated with it.
The Photon widget library is designed so that the UI code can be kept
distinctly separate from the application code. The UI is composed of
the code to create and manipulate the widget family hierarchy, and
must call the application code in response to particular events or user
actions. The connection between the application code and the UI that
allows it to use the application code is the single point where these
two parts have intimate knowledge of each other.
Connections are made between the UI and the application code using
callbacks and event handlers.
A callback is a special type of widget resource that allows the
application to take advantage of existing widget features. Using a
callback, the application can register a function to be called by the
widget library later in response to a particular occurrence within the
widget.
Event handlers are normally used to add capabilities to a widget. For
example, you could add behavior to a button press inside a widget that
has no callbacks associated with button-press events.

Callbacks
A callback resource is a special form of resource used to notify the
application that a specific action has occurred for a widget (e.g. the
user selects a button). Every callback resource for the widget
represents some particular user behavior that the widget’s author
anticipated would be of interest to the application.
As with all resources, a widget has its callbacks defined by its widget
class, and it inherits the callbacks defined by all the ancestors of its
class. This means that a widget may have several user actions that it
can notify the application about.

September 20, 2005 Chapter 23 ¯ Programming Photon without PhAB 525


Complete sample application  2005, QNX Software Systems

The value of a callback resource is a callback list. Each element of the


list is an application function to be called in response to the behavior
and client data associated with the callback. Client data is a pointer to
any arbitrary application data the application may need to provide to
the callback function for it to work correctly.
For information about callbacks, see “Manipulating callbacks in your
code” in the Creating Widgets in Application Code chapter.

Event handling
The writer of a widget class can’t possibly anticipate every need of
the application. The application may want to be notified of some
occurrence on a widget that doesn’t have an associated callback
resource. In such cases, the application may use event handling
functions.
For information about event handlers, see “Manipulating event
handlers in your code” in the Creating Widgets in Application Code
chapter.

Complete sample application


We can now use our newly acquired knowledge of resources and
callbacks to create a more functional version of the sample
application given earlier.
Using resources, we can give the pushbutton widget the same
dimensions as the window, and specify which font to display the label
in. We can also define the callback to be executed when the
pushbutton is pressed. We’ll make the callback function display a
simple message and exit.
Here’s the complete source code for our sample program with these
changes:
#include <stdio.h>
#include <stdlib.h>
#include <Pt.h>

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


{

526 Chapter 23 ¯ Programming Photon without PhAB September 20, 2005


 2005, QNX Software Systems Complete sample application

PtArg t args[3];
PtWidget t *window;
int push button cb( PtWidget t *, void *,
PtCallbackInfo t *);
PtCallback t callbacks[] = {{push button cb, NULL}};

if ((window = PtAppInit(NULL, &argc, argv, 0, NULL))


== NULL)
exit(EXIT FAILURE);

PtSetArg(&args[0], Pt ARG TEXT STRING,


"Press to exit", 0);
PtSetArg(&args[1], Pt ARG TEXT FONT, "helv14b ", 0);
PtSetArg(&args[2], Pt CB ACTIVATE, callbacks,
sizeof(callbacks)/sizeof(callbacks[0]));
PtCreateWidget(PtButton, window, 3, args);

PtRealizeWidget(window);
PtMainLoop();
return (EXIT SUCCESS);
}

int
push button cb(PtWidget t *w, void *data,
PtCallbackInfo t *cbinfo)
{
printf( "I was pushed\n " );
exit( EXIT SUCCESS );

/* This line won’t be reached, but it keeps


the compiler happy. */

return( Pt CONTINUE );
}

September 20, 2005 Chapter 23 ¯ Programming Photon without PhAB 527


Appendix A
Photon Architecture

In this appendix. . .
Event space 531
Events 532
Regions 533
Event types 538
How region owners are notified of events 538
Device region 539
Photon drivers 541
Photon window manager 544

September 20, 2005 Appendix: A ¯ Photon Architecture 529


 2005, QNX Software Systems Event space

Event space
The essential characteristic of Photon is the way in which graphical
applications are represented. All Photon applications consist of one or
more rectangles called regions. These regions reside in an abstract,
three-dimensional event space; the user is outside this space looking
in.
Event space

Root region
Application region

Child application region

Regions can emit and collect objects called events. These events can
travel in either direction through the event space (i.e. either toward or
away from the user). As events move through the event space, they
interact with other regions — this is how applications interact with
each other. The process maintaining this simple architecture is the
Photon Manager.
All the services required for a windowing system — window
managers, drivers, and applications — can easily be created using
regions and events. And because processes whose regions are

September 20, 2005 Appendix: A ¯ Photon Architecture 531


Events  2005, QNX Software Systems

managed by the Photon Manager needn’t reside on the same computer


as the Photon Manager, it’s also easy to implement
network-distributed applications.

Regions and events


Photon programs use two basic objects: regions and events. Regions
are stationary, while events move through the event space.
A region is a single, fixed rectangular area that a program places in
the event space. A region possesses attributes that define how it
interacts with events.
An event is a set of nonoverlapping rectangles that can be emitted and
collected by regions in either direction in the event space. All events
have an associated type. Some event types also possess corresponding
data.

Events
As an event flows through the event space, its rectangle set intersects
with regions placed in the event space by other applications. As this
occurs, the Photon Manager adjusts the event’s rectangle set according
to the attributes of the regions with which the event intersected.

Initial rectangle set


An emitted event’s initial rectangle set contains a single rectangle
whose dimensions are usually the size of the emitting region. As the
event moves through the event space, its interactions with other
regions may cause some portions of this rectangle to be removed. If
this happens, the rectangle will be divided into a set of smaller
rectangles that represent the remaining portions:

532 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Regions

Region
C Tile Tile Tile
Region 1 2 3
D
Tile
4
Region
A
Region
B Event received by
Region D

A region’s rectangle set.

Certain event types (e.g. button presses) have no need for their initial
rectangle set to have the dimensions of the emitting region. For such
events, the rectangle set consists of a single rectangle whose size is a
single point. A single-point rectangle set is called a point source.

Collected rectangle set


The rectangle set of a “collected” event contains the rectangles
resulting from the event’s interaction with prior regions in the event
space. If an event is completely occluded by other regions such that it
results in a set containing no rectangles, then that event ceases to exist.

☞ For a list of the event types, see the “Event types” section.

Regions
A process may create or use any number of regions and may place
them anywhere in the event space. Furthermore, by controlling the
dimensions, location, and attributes of a region (relative to the other
regions in the event space), a process can use, modify, add, or remove
services provided by other regions.
Photon uses a series of regions, ranging from the Root region at the
back of the Photon event space to the Graphics region at the front.

September 20, 2005 Appendix: A ¯ Photon Architecture 533


Regions  2005, QNX Software Systems

Draw events start at an application’s region and move forward to the


Graphics region. Input events start at the Pointer/Keyboard region and
travel towards the Root region.

Root

Workspace (PWM)

Backdrop (PWM) Window Frame (PWM)

Application
or Window

Focus (PWM)

Device

Input Group

Pointer/Keyboard

Graphics

Exploded view of Photon’s regions.

A region’s owner and the Photon Manager can reside on different


computers.
A region has two attributes that control how events are to be treated
when they intersect with a region:

¯ sensitivity

¯ opacity

You can set these independently for each different type of event.

534 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Regions

Sensitivity
If a region is sensitive to a particular type of event, then the region’s
owner collects a copy of any event of that type that intersects with the
region. If other regions are sensitive to this same event type and the
event intersects with them, they’ll also collect a copy of the event —
but with a potentially different rectangle set.
Although many regions can collect a copy of the same event, the
rectangle set for the event may be adjusted and will therefore be
unique for each region that collects the event. The rectangle set
reflects the event’s interaction with other regions in the event space
before arriving at the collecting region.
If a region isn’t sensitive to an event type, the region’s owner never
collects that type of event.
The sensitivity attribute doesn’t modify the rectangle set of an event,
nor does it affect the event’s ability to continue flowing through the
event space.

Opacity
Opaque regions block portions of an event’s rectangle set from
traveling further in the event space. The opacity attribute controls
whether or not an event’s rectangle set is adjusted as a result of
intersecting with a region.
If a region is opaque to an event type, any event of that type that
intersects with the region has its rectangle set adjusted in order to
“clip out” the intersecting area. This changes the rectangle set such
that it includes more, but smaller, rectangles. These new rectangles
describe the portions of the event that remain visible to regions
beyond this region in the event space.
If a region isn’t opaque to an event type, then events of that type never
have their rectangle set adjusted as a result of intersecting with that
region.

September 20, 2005 Appendix: A ¯ Photon Architecture 535


Regions  2005, QNX Software Systems

Attribute summary
The following table summarizes how a region’s attributes affect
events that intersect with that region:

If the region is: Then the event is: And the rectangle set is:
Not sensitive, Ignored Unaffected
not opaque
Not sensitive, Ignored Adjusted
opaque
Sensitive, not Collected Unaffected
opaque
Sensitive, Collected Adjusted
opaque

Event logging
By placing a region across the entire event space, a process can
intercept and modify any event passing through that region. If a
region is sensitive to all events, but not opaque, it can transparently
log all events.

Event modification
If a region is sensitive and opaque, it can choose to reemit a modified
version of the event. For example, a region could collect pointer
events, perform handwriting recognition on those events, and then
generate the equivalent keyboard events.

Parent/child relationships
All regions have parent/child relationships. A child region is always
placed in front of the parent region (i.e. closer to the user), and its
coordinates are relative to the parent’s region.

536 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Regions

Photon coordinate space


All regions reside within the Photon coordinate space, whose
dimensions are as follows:
(-32K, -32K) (+32K, -32K)

Upper-left Upper-right
quadrant quadrant

(0, 0)
VGA
display

(640, 480)
Lower-left Lower-right
quadrant quadrant

(-32K, +32K) (+32K, +32K)

Root region
A special region called the root region is always the region furthest
away from the user. All other regions descend in some way from the
root region. Once an event traveling away from the user reaches the
root region, it ceases to exist.
The root region’s dimensions are the width of the entire Photon
coordinate space. As a result of the parent/child relationship of all
regions, any region’s location is ultimately related to the root region’s
dimensions.

☞ A region can be located anywhere in the event space and still have the
root region as its parent.

September 20, 2005 Appendix: A ¯ Photon Architecture 537


Event types  2005, QNX Software Systems

Event types
Events are emitted for the following reasons:

¯ key presses, keyboard state information

¯ button presses and releases

¯ pointer motions (with or without button pressed)

¯ boundary crossings

¯ regions exposed or covered

¯ drag operations

¯ drawing functions

For more information on event types, see PhEvent t in the Photon


Library Reference.

How region owners are notified of events


Region owners can be notified of events by the Photon Manager in
three different ways:

¯ polling

¯ synchronous notification

¯ asynchronous notification

Polling
To poll, the application calls a function that asks the Photon Manager
to reply immediately with either an event or a status indicating no
event is available.

538 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Device region

☞ Normally you should avoid polling, but you may find it beneficial on
occasion. For example, an application rapidly animating a screen can
poll for events as part of its stream of draw events. An application can
also use polling to retrieve an event after asynchronous notification.

Synchronous notification
For synchronous notification, the application calls a function that asks
the Photon Manager to reply immediately if an event is pending, or to
wait until one becomes available before replying.
With synchronous notification, an application can’t block on other
sources while it’s waiting for the Photon Manager to reply. You
should find this behavior acceptable in most cases since it causes the
application to execute only when the desired events become available.
But if for some reason the possibility of blocking on the Photon
Manager isn’t acceptable, you may consider asynchronous
notification.

Asynchronous notification
For asynchronous notification, the application calls a function that
sets up a notification method (e.g. a signal or a proxy) that the Photon
Manager activates when an event of the desired type is available. The
application can then retrieve the event by polling.
With asynchronous notification, an application can block on multiple
sources, including processes that aren’t Photon applications.

Device region
The device region is owned by the Photon Manager, which divides the
event space into two sections:

¯ driver regions, which reside on the user’s side of the device region

¯ application regions, which reside on the other side of the device


region

September 20, 2005 Appendix: A ¯ Photon Architecture 539


Device region  2005, QNX Software Systems

The Photon Manager uses the device region to focus pointer and
keyboard events as well as to manage drag events.

Pointer focus
As with other windowing systems, Photon has the concept of a
pointer (i.e. screen cursor). This pointer is graphically represented on
the screen and tracks the movements of the pointing device (e.g. a
mouse or touchscreen). Drivers for pointing devices emit pointer
events toward the root region.
A pointer event emitted from a driver is unfocused, or raw, until it
arrives at the device region, where the Photon Manager intercepts it
and then assigns it a location in the Photon coordinate space.
Assigning this location — which is known as focusing the event —
controls which regions will collect the event. The Photon Manager
then reemits the event with the focused location.
Because Photon emits focused, or cooked, pointer motion events in
both directions from the device region, application programs as well
as driver programs can be informed of pointer actions. For example,
when the graphics driver collects focused pointer events, it updates
the location of the pointer’s graphical image on the screen.

Keyboard focus
The keyboard driver is similar to pointing device drivers, except it
emits keyboard events. As with pointer events, keyboard events are
unfocused until they arrive at the device region, where the Photon
Manager assigns them a location (i.e. focuses them) in the Photon
coordinate space.
By default, the device region sets the same focus location for both
keyboard events and pointer events. Therefore, regions directly
behind the screen pointer will collect focused keyboard events.
The window manager supplements the keyboard focus methods. For
more information, see the section on the Photon window manager.

540 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Photon drivers

Drag events
An application initiates dragging by emitting a drag event to the
device region. Once this event is collected at the device region, the
Photon Manager takes care of the interaction with the pointer (i.e.
drag rectangle) until the drag operation is complete. Once completed,
the device region emits a drag event to the application.

Photon drivers
In Photon, drivers aren’t inherently different from other applications.
They’re simply programs that use regions and events in a particular
way to provide their services. Depending on its function, a driver is
either an input driver or an output driver.
For example, the mouse and keyboard drivers are input drivers
because they emit, and are the source of, hardware actions. Graphics
and printer drivers, on the other hand, are output drivers because they
collect events that cause them to take action with hardware devices.

Input drivers
Mouse driver
The mouse driver places a region on the user’s side of the device
region. It gets information from the mouse hardware and builds
Photon raw pointer events that it then emits toward the root region.
When the device region collects a raw pointer event, the Photon
Manager focuses it and then emits cooked events in both directions in
the event space.

Keyboard driver
The keyboard driver also places a region on the user’s side of the
device region. The driver gets information from the keyboard
hardware and builds Photon keyboard events that it then emits toward
the root region.
When the device region collects keyboard events, the Photon Manager
focuses those events and then reemits them toward the root region.

September 20, 2005 Appendix: A ¯ Photon Architecture 541


Photon drivers  2005, QNX Software Systems

☞ The window manager supplements the default focus method provided


by the device region.

Since Photon makes no assumptions as to what type of keyboard is


being used, the keyboard driver could acquire its event data on any
hardware or even from another process.
Photon allows multiple input drivers and multiple output drivers to be
associated with each other as an input group. This group of devices
will be treated distinctly from other input groups by Photon.
You can determine the current input group as follows:

¯ If you have the event that triggered the clipboard operation, use its
input group (e.g. cbinfo->event->input group) if it’s nonzero.
¯ If that fails, get the value of the PHIG environment variable. If
this value is nonzero, use it.
¯ If neither of the above if nonzero, specify an input group of 1.

Output drivers
Graphics driver
A graphics driver places a region sensitive to draw events onto the
user’s side of the device region. As the driver collects draw events, it
renders the graphical information on the screen. Because the collected
event’s rectangle set contains only those areas that need to be updated,
the driver can optimize its update. (This is especially efficient if the
graphics hardware can handle clipping lists directly.)

☞ The Photon drawing API accumulates draw requests into batches that
are emitted as single draw events.

Multiple graphic drivers


The region a graphics driver uses can have dimensions that represent
an area smaller than the entire Photon coordinate space. As a result,
multiple graphics drivers can share the coordinate space by each

542 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Photon drivers

handling different portions of it and displaying their events on


different screens. And since region owners don’t have to be on the
same node as the Photon Manager, those graphics drivers can display
their portion of the coordinate space on screens located on other
computers in the network.

Drivers using separate regions


From an application’s perspective, the Photon coordinate space
always looks like a single, unified graphical space, yet it allows users
to drag windows from one physical screen to another.
For example, let’s say an operator in a factory control environment
has a small handheld computer. If this computer were connected to
network via a wireless link, the operator could walk up to a computer
with a large-screen control application and drag a window from that
screen onto the screen of the handheld unit. Taking the handheld
computer, the operator could then walk out onto the plant floor and
continue to interact with the control application to monitor and adjust
equipment.

Drivers using overlapping regions


In another type of example, instead of having driver regions with
exclusive portions of the coordinate space, you could have drivers
using overlapping regions. This approach would let you replicate the
same draw events on multiple screens, which would be ideal for
support or training environments.

Printer driver
To print an area of the Photon coordinate space, the printer driver
inserts a region that’s opaque to draw events in front of the area of the
coordinate space that you want to print. This prevents draw events
from reaching the graphics driver.
The printer driver then emits an expose event toward the region being
printed, waits to collect draw events from that region, and renders
them on the printer. Once the draw events are completed, the region is
removed without having caused a visible redraw on the screen.

September 20, 2005 Appendix: A ¯ Photon Architecture 543


Photon window manager  2005, QNX Software Systems

This scheme lets you print any region, even if the region is blocked by
others in the event space. Also, the printer driver could emit its own
draw events toward the user to indicate a printing operation is in
progress.
Since the printer driver collects draw events, it can translate them into
the format necessary for different types of print devices. For example,
if you’re using a PostScript printer, draw events could be translated
directly into commands that take full advantage of the printer’s
resolution.

Encapsulation drivers
Since graphics drivers for Photon are really just applications, they can
display the graphical output of Photon inside another windowing
system (for example, the X Window System). A Photon driver could
also take the keyboard and mouse events it collects from the X system
and regenerate them within Photon, allowing the Photon window in
the X system to be fully functional, both for graphical display and for
keyboard/mouse input.

Photon window manager


The window manager is an optional Photon application that manages
the appearance and operation of menus, buttons, scrollbars, and so on.
It provides the windowing system with a certain “look and feel” (e.g.
Motif).
The window manager also manages the workspace, supplements the
methods for focusing keyboard events, and lets you display a
backdrop. To provide all these services, the window manager places
several regions in the event space:

¯ window frame regions

¯ a focus region

¯ a workspace region

¯ a backdrop region

544 Appendix: A ¯ Photon Architecture September 20, 2005


 2005, QNX Software Systems Photon window manager

Window frame regions


Most applications rely on the windowing system to provide the user
with the means to manipulate their size, position, and state (i.e.
open/iconified). In order for the user to perform these actions, the
window manager puts a frame around the application’s region and
then places controls in that frame (e.g. resize corners, title bars,
buttons). We refer to these controls as window services.
To indicate it can provide window services, the window manager
registers with the Photon Manager. When an application opens a
window, the window manager sets up two regions on its behalf: a
window frame region and an application region (or window region).
The window frame region is slightly larger than the application region
and is placed just behind it.
The window manager uses the window frame region for its controls,
while the application uses its own region. But the application isn’t
aware of the controls. If the user uses the controls to move the
application, the application notices only that its location has changed.
The same goes for resizing, iconifying, and so on.

Focus region
As mentioned earlier, the device region focuses keyboard events to
regions directly behind the screen pointer. But by placing a region of
its own (i.e. the focus region) just behind the device region, the
window manager intercepts these keyboard events as they’re emitted
from the device region and implements an alternate focus method.
The window manager can redirect keyboard events to regions not
directly beneath the screen pointer. For example, it can focus events
toward the last window the user “clicked” on (i.e. the active window).
The window manager can direct keyboard events to that active region
even if the region gets covered by another region.

Workspace region
From the user’s perspective, the workspace is the empty space
surrounding the windows on the screen. The window manager places

September 20, 2005 Appendix: A ¯ Photon Architecture 545


Photon window manager  2005, QNX Software Systems

a workspace region just in front of the root region to capture pointer


events before they get to the root region and thus disappear. When the
user presses a pointer button and no region collects the event, the
window manager brings up a workspace menu that lets the user select
a program to run.

Backdrop region
Users often like to have an ornamental backdrop image displayed
behind the windows on the screen. To display such a bitmap, the
window manager places a backdrop region in the event space.

546 Appendix: A ¯ Photon Architecture September 20, 2005


Appendix B
Widgets at a Glance

September 20, 2005 Appendix: B ¯ Widgets at a Glance 547


 2005, QNX Software Systems

The following table lists the Photon widget classes and the icons used
in PhAB’s widget bar. For more information on specific widget
classes, see the Widget Reference.

PhAB Icon Class Description

PtArc Arc

PtBasic Widget superclass that


provides basic resources

PtBezier Bézier curve

PtBitmap Multiplaned bitmapped


images

PtBkgd Background of tiled


images, gradients, or
bitmaps

PtButton Pushbutton

PtCalendar Calendar
Pt Calenda

Pt Clock
PtClock Analog, digital, or LED
clock

PtComboBox Text-entry field with a list


of choices
N/A PtCompound Superclass for compound
widgets — not normally
instantiated

continued. . .

September 20, 2005 Appendix: B ¯ Widgets at a Glance 549


 2005, QNX Software Systems

PhAB Icon Class Description


N/A PtContainer Superclass for container
widgets — not normally
instantiated

t DBCont ain
PtDBContainer Double Buffer container,
useful for drawing
flicker-free images and
animations

PtDivider Widget that divides a given


space among its child
widgets and allows resizing

PtEllipse Ellipse

PtFileSel File selector

PtFontSel Font selector


N/A PtGauge Superclass for gauge-like
widgets — not normally
instantiated
N/A PtGenList Superclass for list widgets
— not normally
instantiated
N/A PtGenTree Superclass for tree widgets
— not normally
instantiated
N/A PtGraphic Superclass for graphical
widgets — not normally
instantiated

PtGrid Grid

continued. . .

550 Appendix: B ¯ Widgets at a Glance September 20, 2005


 2005, QNX Software Systems

PhAB Icon Class Description


N/A PtGroup Group — use PhAB’s
Group Together button to
create this

PtHtml Area for displaying HTML


N/A PtIcon Icons for use by PDM —
use an Icon module instead.

PtLabel Label or text string that


can’t be edited

PtLine Straight line (single


segment)

PtList List of text items


N/A PtMenu Menu — use a Menu
module instead

PtMenuBar Menubar that’s placed at


the top of a window

PtMenuButton Button that pops up a


menu, or an item in a menu
N/A PtMessage Dialog that displays a
message

PtMultitext Multiple-line text field


N/A PtNumeric Numeric field superclass —
not normally instantiated

continued. . .

September 20, 2005 Appendix: B ¯ Widgets at a Glance 551


 2005, QNX Software Systems

PhAB Icon Class Description

PtNumericFloat Floating-point numeric


t NumericFl
field

PtNumericInteger Integer field

PtOnOffButton Button that’s either on or


off

PtPane Container that provides


anchoring and layout for its
children

PtPixel Set of points

PtPolygon Set of connected line


segments

PtPrintSel Compound widget for


choosing printing options

PtRaw Area in which you can use


low-level Pg drawing
functions

PtRect Rectangle
N/A PtRegion Photon region — must be
created with
PtCreateWidget()

PtScrollArea Scrolling area

continued. . .

552 Appendix: B ¯ Widgets at a Glance September 20, 2005


 2005, QNX Software Systems

PhAB Icon Class Description

PtScrollBar Scrollbar

PtSeparator Separator for menu entries


— use PhAB’s Menu editor
instead

PtSlider Numerical input


mechanism with a range

Pt Tab
PtTab Tab button

PtTerminal Terminal emulator

PtText Single-line text field

PtTimer Timer

PtToggleButton Toggle button

PtTree Hierarchy tree

PtTty Terminal device

PtUpdown Set of buttons for


increasing and decreasing a
value
N/A PtWidget Widget superclass — not
normally instantiated
N/A PtWindow Window — use a Window
module instead

continued. . .

September 20, 2005 Appendix: B ¯ Widgets at a Glance 553


 2005, QNX Software Systems

PhAB Icon Class Description

RtMeter Realtime meter widget

RtProgress Realtime widget that


displays an operation’s
progress

RtTrend Display of connected


points that shift in a
specified direction at the
rate in which data is fed

554 Appendix: B ¯ Widgets at a Glance September 20, 2005


Appendix C
Unicode Multilingual Support

In this appendix. . .
Wide and multibyte characters 557
Unicode 559
UTF-8 encoding 559
Other encodings 561
Keyboard drivers 562

September 20, 2005 Appendix: C ¯ Unicode Multilingual Support 555


 2005, QNX Software Systems Wide and multibyte characters

Photon is designed to handle international characters. Following the


Unicode Standard (ISO/IEC 10646), Photon provides developers with
the ability to create applications that can easily support the world’s
major languages and scripts.
Unicode is modeled on the ASCII character set, but uses a 16-bit
encoding to support full multilingual text. There’s no need for escape
sequences or control codes when specifying any character in any
language. Note that Unicode encoding conveniently treats all
characters — whether alphabetic, ideographs, or symbols — in
exactly the same way.
In designing the keyboard driver and the character handling
mechanisms, we referred to the X11 keyboard extensions and ISO
standards 9995 and 10646-1.

Wide and multibyte characters


ANSI C includes the following concepts:

wide character
A character represented as a value of type wchar t, which
typically is larger than a char.
multibyte character
A sequence of one or more bytes that represents a character,
stored in a char array. The number of bytes depends on the
character.
wide-character string
An array of wchar t.

multibyte string
A sequence of multibyte characters stored in a char array.

The following ANSI C functions (described in the Watcom C Library


Reference) are used for converting between wide-character encoding
and multibyte encoding:

September 20, 2005 Appendix: C ¯ Unicode Multilingual Support 557


Wide and multibyte characters  2005, QNX Software Systems

mblen() Compute the length of a multibyte string in


characters
mbtowc() Convert a multibyte character to a wide character
mbstowcs() Convert a multibyte string to a wide-character string
wctomb() Convert a wide character to its multibyte
representation
wcstombs() Convert a wide-character string to a multibyte string

In addition, the Photon library provides the following non-ANSI


functions (described in the Photon Library Reference) for working
with multibyte characters:

mbstrblen() Find the number of multibyte characters in part of a


string
mbstrchr() Search for a multibyte character in a string
mbstrlen() Find the length of a multibyte-character string
mbstrnchr() Search for a multibyte character in part of a string
mbstrncmp() Compare part of a multibyte-character string
mbstrnlen() Find the number of bytes used by a
multibyte-character string
mbstrrchr() Search backwards for a multibyte character in a
string

In our C libraries, “wide characters” are assumed to be Unicode, and


“multibyte” is a synonym for UTF-8. The wchar t type is defined as
unsigned short, and wctomb() and mbtowc() implement the
UTF-8 encoding.
Photon libraries use multibyte-character strings: any function that
handles strings should be able to handle a valid UTF-8 string, and
functions that return a string can return a multibyte-character string.
This also applies to widget resources. The graphics drivers and font
server assume that all strings use UTF-8.

558 Appendix: C ¯ Unicode Multilingual Support September 20, 2005


 2005, QNX Software Systems UTF-8 encoding

Unicode
Unicode is a 16-bit encoding scheme defined in the ISO/IEC 10646
standard:

¯ It packs most international characters into wide-character


representations (two bytes per character).

¯ Codes below 128 define the same characters as the ASCII


standard.

¯ Codes between 128 and 255 define the same characters as in the
ISO 8859-1 character set.

¯ There’s a private-use area from 0xE000 to 0xF7FF; Photon maps


it as follows:

Glyphs Range
Nondisplayable keys 0xF000 – 0xF0FF
Cursor font 0xE900 – 0xE9FF

For Unicode character values, see


/usr/include/photon/PkKeyDef.h. For more information about
Unicode, see the Unicode Consortium’s website at
www.unicode.org.

UTF-8 encoding
Formerly known as UTF-2, the UTF-8 (for “8-bit form”)
transformation format is designed to address the use of Unicode
character data in 8-bit UNIX environments. Each 16-bit Unicode
value is encoded as a one-, two-, or three-byte UTF-8 sequence.
Here are some of the main features of UTF-8:

¯ The UTF-8 representation of codes below 128 is the same as in the


ASCII standard, so any ASCII string is also a valid UTF-8 string
and represents the same characters.

September 20, 2005 Appendix: C ¯ Unicode Multilingual Support 559


UTF-8 encoding  2005, QNX Software Systems

¯ ASCII values don’t otherwise occur in a UTF-8 transformation,


giving complete compatibility with historical filesystems that parse
for ASCII bytes.

¯ UTF-8 encodes the ISO 8859-1 character set as double-byte


sequences.

¯ UTF-8 simplifies conversions to and from Unicode text.

¯ The first byte indicates the number of bytes to follow in a


multibyte sequence, allowing for efficient forward parsing.

¯ Finding the start of a character from an arbitrary location in a byte


stream is efficient, because you need to search at most four bytes
backwards to find an easily recognizable initial byte. For example:
isInitialByte = ((byte & 0xC0) != 0x80);

¯ UTF-8 is reasonably compact in terms of the number of bytes used


for encoding.

The actual encoding is this:

¯ For multibyte encodings, the first byte sets 1 in a number of


high-order bits equal to the number of bytes used in the encoding;
the bit after that is set to 0. For example, a 2-byte sequence always
starts with 110 in the first byte.

¯ For all subsequent bytes in a multibyte encoding, the first two bits
are 10. The value of a trailing byte in a multibyte encoding is
always greater than or equal to 0x80.
The following table shows the binary form of each byte of the
encoding and the minimum and maximum values for the
characters represented by 1-, 2-, and 3-byte encodings:

560 Appendix: C ¯ Unicode Multilingual Support September 20, 2005


 2005, QNX Software Systems Other encodings

Length First byte Following bytes Min. value Max. value


Single byte 0XXXXXXX N/A 0x0000 0x007F
Two bytes 110XXXXX 10XXXXXX 0x0080 0x07FF
Three bytes 1110XXXX 10XXXXXX 0x0800 0xFFFF

¯ The actual content of the multibyte encoding (i.e. the


wide-character encoding) is the catenation of the XX bits in the
encoding. A 2-byte encoding of 11011111 10000000 encodes
the wide character 11111000000.

¯ Where there’s more than one way to encode a value (such as 0),
the shortest is the only legal value. The null character is always a
single byte.

Other encodings
If your application needs to work with other character encodings,
you’ll need to convert to and from UTF-8. Character sets are defined
in the file /usr/photon/translations/charsets, and include:

¯ Big5 (Chinese)

¯ Cyrillic (KOI8-R)

¯ Japanese (EUC)

¯ Japanese (Shift-JIS)

¯ Korean (EUC)

¯ Western (ISO 8859-1)

The following translation functions are provided, and are described in


the Photon Library Reference:

PxTranslateFromUTF()
Translate characters from UTF-8

September 20, 2005 Appendix: C ¯ Unicode Multilingual Support 561


Keyboard drivers  2005, QNX Software Systems

PxTranslateList()
Create a list of all supported character translations
PxTranslateSet()
Install a new character-set translation
PxTranslateStateFromUTF()
Translate characters from UTF-8, using an internal state buffer

PxTranslateStateToUTF()
Translate characters to UTF-8, using an internal state buffer

PxTranslateToUTF()
Translate characters to UTF-8
PxTranslateUnknown()
Control how unknown encodings are handled

☞ These functions are supplied only in static form in the Photon library
phexlib3r.lib. The prototypes are in <photon/PxProto.h>.

Keyboard drivers
The keyboard driver is table-driven; it handles any keyboard with 127
or fewer physical keys.
A keypress is stored in a structure of type PhKeyEvent t (described
in the Photon Library Reference).

Example: text widgets


The text widgets use the key sym field for displayable characters.
These widgets also check it to detect cursor movement. For example,
if the content of the field is Pk Left, the cursor is moved left. The
key sym is Pk Left for both the left cursor key and the numeric keypad
left cursor key (assuming NumLock is off).

562 Appendix: C ¯ Unicode Multilingual Support September 20, 2005


 2005, QNX Software Systems Keyboard drivers

Dead keys and compose sequences


QNX supports “dead” keys and “compose” key sequences to generate
key syms that aren’t on the keyboard. The key sym field is valid only
on a key press — not on a key release — to ensure that you get only
one symbol, not two.
For example, if the keyboard has a dead accent key (for example, ‘)
and the user presses it followed by e, the key sym is an “e” with a
grave accent (è). If the e key isn’t released, and then another group of
keys (or more compose or dead key sequences) are pressed, the
key syms would have to be stacked for the final releases.
If an invalid key is pressed during a compose sequence, the keyboard
drivers generate key syms for all the intermediate keys, but not an
actual press or release.
For a list of compose sequences, see the International Character
Support chapter of the Photon User’s Guide.

September 20, 2005 Appendix: C ¯ Unicode Multilingual Support 563


Glossary

September 20, 2005 Glossary 565


 2005, QNX Software Systems

accelerator
See hotkey.

activate
A widget is usually activated when you release a mouse button while
pointing at an armed widget.

active window
The window that currently has focus.

anchor offset
The absolute or proportional distance between the edges of a
container-class child widget and the parent widget it’s anchored to.

anchor
A constraint mechanism used to manage what happens to a
container-class child widget when its parent is expanded or
contracted. For example, a pane that’s anchored to the sides of a
window expands or contracts as the window’s size is changed.

application region
A region that belongs to a Photon application (as opposed to a Photon
system process, such as the window manager, graphics drivers, etc.).
An application region is usually placed behind the device region.
Also called a window region.

argument list
An array of type PtArg t used when setting and getting widget
resources.

arm
A widget is usually armed when you press a mouse button while
pointing at it.

September 20, 2005 Glossary 567


 2005, QNX Software Systems

backdrop
An image that’s displayed as a background on your screen.

backdrop region
A region placed behind all windows to display a background image.

balloon
A small box that pops up to define or explain part of the user interface.
A balloon is displayed when the pointer pauses over a widget.

bitmap
A color picture consisting of one or more bitplanes.

bitplane
An array of bits representing pixels of a single color in a bitmap.

blit
An operation that moves an area of the screen.

callback
A callback function or a callback resource.

callback function
Code connecting an application’s user interface to its code. For
example, a callback is invoked when you press a button.

callback resource
A resource that specifies a list of functions and their client data to be
called when a certain action occurs.

canvas
The part of a widget that’s used for drawing. For PtWidget, this is
the area inside the widget’s borders. For PtBasic and its
descendants, the canvas is the area inside the widget’s border and

568 Glossary September 20, 2005


 2005, QNX Software Systems

margins. Other widgets, such as PtLabel, may define additional


margins.

class
See widget class.

class hierarchy
The relationships between all of the widget classes.

client data
Any arbitrary data the application may need to provide to a callback
function.

clipping list
An array of rectangles used to restrict output to a particular area.

clipping rectangle
A rectangle used to restrict output to a particular area.

CMY value
A color expressed as levels of cyan, magenta, and yellow.

CMYK value
A color expressed as levels of cyan, magenta, yellow, and black.

code-type link callback


In a PhAB application, an application function that’s called when a
widget’s callback list is invoked.

color depth
The number of bits per pixel for a screen or pixmap.

September 20, 2005 Glossary 569


 2005, QNX Software Systems

Common User Access


See CUA.

compose sequence
A sequence of key presses that can be used to type a character that
might not appear on the keyboard.

console
One of nine virtual screens on the desktop. Also called a workspace.

consume
When a widget has processed an event and prevents another widget
from interacting with the event, the first widget is said to have
consumed the event.

container
A widget that can have other widgets as children. For example,
PtWindow, PtGroup, and PtPane.

cooked event
A key or pointer event that has been assigned a location in the Photon
event space. Also called a focused event.

CUA
Common User Access — a standard that defines how you can change
keyboard focus.

cursor
An indicator of a position on a screen, such as a pointer or an
insertion point in a text field.

damaged
Whenever a widget needs to be redisplayed due to a change in the
window (e.g. the widget is changed, moved, or realized), it’s said to
be damaged.

570 Glossary September 20, 2005


 2005, QNX Software Systems

DayMinder
A Photon application that you can use to organize your daily schedule
and activities.

dead key
A key that, when pressed, doesn’t produce a symbol, but initiates a
compose sequence.

default placement
The placement of a region when no siblings are specified. The
opposite of specific placement.

desktop
The virtual screen provided by the Photon Desktop Manager. The
desktop consists of nine consoles or workspaces.

desktop manager
See Photon Desktop Manager.

device region
The region located in the middle of the event space, with application
regions behind it and driver regions in front of it.

dialog module
A PhAB module similar to a window module, except that a dialog
module can have only one instance per process.

direct-color
A color scheme in which each pixel is represented by an RGB value.
Contrast palette-based.

disjoint parent
A disjoint widget that’s the ancestor of another widget.

September 20, 2005 Glossary 571


 2005, QNX Software Systems

disjoint widget
A widget that can exist without a parent. If a disjoint widget has a
parent, it can exist outside its parent’s canvas. For example,
PtWindow, PtMenu, and PtRegion are disjoint widgets, but
PtButton, PtBkgd, and PtRect aren’t.
A disjoint widget owns regions that aren’t children of its parent’s
regions. Any clipping set by the parent of a disjoint widget isn’t
applied to the disjoint widget. The regions of disjoint widgets are
sensitive and opaque to expose events.

dithering
A process whereby pixels of two colors are combined to create a
texture or a blended color.

ditto
A QNX utility that lets you attach a local console or terminal to a
remote console. See also phditto.

draw context
A structure that defines the flow of the draw stream. The default draw
context emits draw events to graphics drivers. Print contexts and
memory contexts are types of draw contexts.

draw stream
A series of draw events.

driver region
A region created by a driver, usually placed in front of the device
region.

encapsulation driver
A program that displays Photon graphical output inside another
windowing system such as the X Window System.

572 Glossary September 20, 2005


 2005, QNX Software Systems

event
A data structure that represents an interaction between you and an
application or between applications. Events travel through the event
space either toward you or away (i.e. toward the root region).

event compression
The merging of events such that the application sees only their latest
values. The application doesn’t have to process many unnecessary
events.

event handler
A callback function that lets an application respond directly to Photon
events, such as dragging events.

event mask
A set of event types that are or interest to an event handler. When
one of these events occurs, the event handler is invoked.

event space
An abstract, three-dimensional space that contains regions — from
the root region at the back to the graphics region at the front. You sit
outside the event space, looking in from the front. Events travel
through the event space either toward the root region or toward you.

exported subordinate child


A widget created by another widget (as opposed to an application)
whose resources you can access through the parent.

exposure
Occurs when a region is destroyed, resized, or moved. Expose events
are sent to applications to inform them when the contents of their
regions need to be redisplayed.

September 20, 2005 Glossary 573


 2005, QNX Software Systems

extent
A rectangle that describes the outermost edges of a widget.

File Manager
The Photon File Manager (PFM), an application used to maintain and
organize files and directories.

focus
A widget that has focus will receive any key events collected by its
window.

focus region
A region placed just behind the device region by the Photon
Window Manager that lets it intercept key events and direct them to
the active window.

focused event
A key or pointer event that has been assigned a location in the Photon
event space. Also called a cooked event.

folder
In the Photon File Manager, a metaphor for a directory.

GC
See graphics context.

geometry negotiation
The process of determining the layout for a widget and its
descendants, which depends on the widget’s layout policy, any size
set for the widget, and the dimensions and desired positions of each of
the widget’s children.

574 Glossary September 20, 2005


 2005, QNX Software Systems

global header file


A header file that’s included in all code generated by PhAB for an
application. The global header file is specified in PhAB’s Application
Startup Information dialog.

graphics driver
A program that places a region that’s sensitive to draw events on the
user’s side of the device region, collects draw events, and renders the
graphical information on the screen.

graphics context (GC)


A data structure that defines the characteristics of primitives,
including foreground color, background color, line width, clipping,
etc.

Helpviewer
A Photon application for viewing online documentation.

hotkey
A special key or keychord that invokes an action (such as a menu
item) without actually selecting a widget. Also called an accelerator.
Contrast keyboard shortcut.

hotspot
The part of the pointer that corresponds to the coordinates reported
for the pointer (e.g. the intersection of crosshairs, or the tip of the
arrow of the basic pointer).

HSB
Hue-Saturation-Brightness color model.

HSV
Hue-Saturation-Value color model.

September 20, 2005 Glossary 575


 2005, QNX Software Systems

icon module
A PhAB module that holds the icons used by the Photon Desktop
Manager for launch buttons and by the Photon Window Manager for
the taskbar.

image
A rectangular array of color values, where each color value represents
a single pixel. See also direct-color and palette-based.

initialization function
In a PhAB application, a function that’s called before any widgets are
created.

input driver
A program that emits, and is the source of, key and pointer events.

input group
A set of input and output devices. There’s typically one input group
per user.

input handler (or input-handling function)


A function that’s hooked into Photon’s main event-processing loop to
handle messages and pulses sent to the application by other processes.

instance
A member of a class; for example, “Lassie” is an instance of the class
“dog.” In Photon, an instance is usually a widget instance. When an
instance is created, the initial values of its resources are assigned.

instance name
In PhAB, a string that identifies a particular instance of a widget so
that the instance can be accessed in an application’s code.

576 Glossary September 20, 2005


 2005, QNX Software Systems

instantiation
The action of creating an instance of a widget class in an application.

internal link
A PhAB mechanism that lets a developer access a PhAB module
directly from an application’s code.

Image Viewer
A Photon application (pv) that displays images.

Jump Gate
A mechanism that “transports” an application from one QNX node to
another.

key modifier
A flag in a key event that indicates the state of the corresponding
modifier key when another key was pressed.

keyboard driver
A program that gets information from the keyboard hardware, builds
Photon key events, and emits them towards the root region.

keyboard shortcut
A key that selects a menu item. The shortcut works only if the menu
is displayed. Contrast hotkey.

language database
A file that contains the text strings used in a PhAB application; a
language database makes it easier to create multilingual applications
with PhAB’s language editor.

link callback
A mechanism that connects different parts of a PhAB application. For
example, a link callback can be invoked to display a dialog when a
button is pressed.

September 20, 2005 Glossary 577


 2005, QNX Software Systems

margin
The area between a widget’s border and canvas.

memory context
A draw context in which Photon draw events are directed to memory
for future displaying on the screen, as opposed to a printer (print
context) or to the screen directly (the default draw context).

menu module
A PhAB module used to create a menu.

Message Pad
A Photon application that lets you post notes on your computer’s
screen or send them to other users over the network.

method
A function that’s internal to a widget class and invoked under specific
conditions (e.g. to draw the widget). Methods are provided as
pointers to functions in widget class records.

modifier key
A key (such as Shift, Alt, or Ctrl) used to change the meaning of
another key.

module
An object in PhAB that holds an application’s widgets. PhAB
modules include windows, menus, icons, pictures, and dialogs.

module-type link callback


A link callback that displays a PhAB module.

mouse driver
A program that gets information from the pointer hardware, builds
Photon raw pointer events, and emits them towards the root region.

578 Glossary September 20, 2005


 2005, QNX Software Systems

opaque
The state of a region with regard to events. If a region is opaque to an
event type, any event of that type that intersects with the region has its
rectangle set adjusted to clip out the intersecting area.

palette
An array of colors. A hard palette is in hardware; a soft palette is in
software.

palette-based
A color scheme in which each pixel is represented by an index into a
palette. Contrast direct-color.

PDM
See Photon Desktop Manager.

PDR
See Press-drag-release.

PFM
See Photon File Manager.

PhAB
Photon Application Builder. Visual design tool that generates the
code required to implement a user interface.

phditto
A utility that accesses the Photon workspace on a remote node. See
also ditto.

Phindows
Photon in Windows. An application that accesses Photon from a
Microsoft Windows environment.

September 20, 2005 Glossary 579


 2005, QNX Software Systems

PhinX
Photon in X. An application that accesses Photon from an X Window
System environment.

Photon Desktop Manager (PDM)


An application that provides a “control panel” that lets you launch
applications, move around the desktop, and change the desktop’s
settings.

Photon File Manager (PFM)


An application used to maintain and organize files and directories.

Photon Manager or server


The program that maintains the Photon event space by managing
regions and events.

Photon Terminal
An application (pterm) that emulates a character-mode terminal in a
Photon window.

Photon Window Manager (PWM)


An application that manages the appearance of window frames and
other objects on the screen. For example, the window manager adds
the resize bars, title bar, and various buttons to an application’s
window. The window manager also provides a method of focusing
keyboard events.

phsac
A utility that displays system activity.

picture module
A PhAB module that contains an arrangement of widgets that can be
displayed in another widget or used as a widget database.

580 Glossary September 20, 2005


 2005, QNX Software Systems

pixmap
A bitmap or image.

plane mask
A mask used to restrict graphics operations to affect only a subset of
color bits.

point source
A single-point rectangle set used as the source of an event.

pointer
An object on the screen that tracks the position of a pointing device
(e.g. a mouse, tablet, track-ball, or joystick). Photon has several
pointers indicating various states: Basic, Busy, Help, Move, Resize,
I-beam, No-input.

Press-drag-release (PDR)
A method of selecting a menu item by pressing down a mouse button
while pointing to a menu button, dragging until the desired item is
highlighted, and releasing the mouse button.

print context
A draw context in which Photon draw events are directed to a file, as
opposed to the screen (the default draw context) or to memory
(memory context).

printer driver
A program that converts Photon draw stream format into a format
suitable for some printers, including PostScript, Hewlett-Packard
PCL, and Canon.

procreated widget
A widget created by another widget (as opposed to an application),
such as the PtList and PtText created by a PtComboBox. Also
known as a subordinate child.

September 20, 2005 Glossary 581


 2005, QNX Software Systems

pterm
A Photon Terminal; an application that emulates a character-mode
terminal in a Photon window.

pulse
A small message that doesn’t require a reply; used for asynchronous
communication with a Photon application.

pv
See Image Viewer.

PWM
See Photon Window Manager.

raw event
An input event that hasn’t been assigned a location in the Photon
event space. Also called an unfocused event.

raw-event callback
A function that lets an application respond directly to Photon events
such as dragging events. Also called an event handler.

realize
To display a widget and its descendants, possibly making them
interactive.

rectangle set
An array of nonoverlapping rectangles associated with an event.

region
A rectangular area within the Photon event space that’s used by an
application for collecting and emitting events.

582 Glossary September 20, 2005


 2005, QNX Software Systems

resize policy
A rule that governs how a widget resizes itself when its contents
change.

resource
An attribute of a widget, such as fill color, dimensions, or a callback
list.

root region
The region at the very back of the Photon event space.

sensitive
The state of a region with regard to events. If a region is sensitive to a
particular type of event, the region’s owner collects a copy of any
such event that intersects with the region.

setup function
A function that’s called after a PhAB module is created.

Snapshot
A Photon application for capturing images of the screen.

specific placement
The placement of a region when one or more siblings are specified.
The opposite of default placement.

subordinate child
A widget created by another widget (as opposed to an application),
such as the PtList and PtText created by a PtComboBox. Also
known as a procreated widget.

table-of-contents (TOC) file


In the Photon Helpviewer, a file that describes a hierarchy of help
topics.

September 20, 2005 Glossary 583


 2005, QNX Software Systems

Taskbar
An area in which the Photon Window Manager displays icons
representing the applications that are currently running.

tile
A data structure used to build linked lists of rectangles, such as a list
of the damaged parts of an interface.

topic path
Help information identified by a string of titles that are separated by
slashes.

topic root
A topic path that’s used as a starting point for locating help topics.

topic tree
A hierarchy of help information.

translation file
A file containing translated strings for a PhAB application. There’s
one translation file per language supported by the application.

unfocused event
See raw event.

Unicode
The ISO/IEC 10646 16-bit encoding scheme for representing the
characters used in most languages.

UTF-8
The encoding for Unicode characters, where each character is
represented by one, two, or three bytes.

584 Glossary September 20, 2005


 2005, QNX Software Systems

vsin
A utility that displays system information.

widget
A component (e.g. a pushbutton) in a graphical user interface.

widget class
A template for widgets that perform similar functions and provide the
same public interface. For example, PtButton is a widget class.

widget database
In PhAB, a module containing widgets that can be copied at any time
into a window, dialog, or other container.

widget family
A hierarchy of widget instances. For example, a window and the
widgets it contains.

widget instance
See instance.

window frame region


A region that PWM adds to a window. It lets you move, resize,
iconify, and close the window.

Window Manager
See Photon Window Manager.

window module
A PhAB module that’s instantiated as a PtWindow widget.

window region
A region that belongs to an application window.

September 20, 2005 Glossary 585


 2005, QNX Software Systems

work procedure
A function that’s invoked when there are no Photon events pending
for an application.

workspace
See console.

workspace menu
A configurable menu that’s displayed when you press or click the
right mouse button while pointing at the background of the screen.

586 Glossary September 20, 2005


Index

! A
.html extension 337 abapp.dfn 231
.ldb extension 324 abdefine.h 226, 243
.toc extension 340 abevents.h 226
.wgtd extension 109, 116 abHfiles 226
.wgti extension 109, 127 abimport.h 226, 228
.wgtm extension 109, 117 AB ITEM DIM 259
.wgtp extension 109, 126 AB ITEM NORMAL 259
.wgtw extension 109, 115 AB ITEM SET 259
.wgtx extension 109, 129 ABLANG environment
/usr/bin/photon 333 variable 330
/usr/help/product 340 ablinks.h 226
:: in function names 250 ABLPATH environment
@ in function names 250 variable 330, 332, 333
@ in instance names 141, 322 ABM ... manifests 247, 305
<PhT.h> 485 abmain.c 226
<PhWm.h> 509 abmain.cc 226
<PkKeyDef.h> 193, 272 ABN ... manifests 119, 243, 244,
<Pt.h> 519 259
<PtPulseDeliver.h> 373 abOfiles 226
<PtWidget.h> 207 AB OPTIONS 254
<PxImage.h> 421 About PhAB (Help menu) 92
abplatform 227
ABR CANCEL 257
ABR CODE 257

September 20, 2005 Index 587


Index  2005, QNX Software Systems

ABR DONE 258 ApCreateWidgetFamily() 311


ABR POST REALIZE 256 ApDeleteWidget() 312
ABR PRE REALIZE 256 ApFreeBitmapRes() 313
abSfiles 226 ApGetBitmapRes() 312
abvars.h 227, 243 ApGetImageRes() 312, 415, 417,
ABW ... manifests 243–245, 247, 418, 420
248 ApGetItemText() 260
abwidgets.h 227 apinfo 256, 257
accelerator See hotkey ApModifyItemState() 195, 258
Activate callback 125, 183, 261, ApModifyItemText() 259
293 ApModuleFunction() 306
Activate callbacks ApModuleLocation() 306
modifier keys 490 ApModuleParent() 306
active region 545 ApName() 244
aligning ApOpenDBase() 306, 310, 311,
horizontally 209, 319 420
in rows and columns 210 ApOpenDBaseFile() 310, 311
to a parent widget 149 app make target 235
to another widget 149 application
using groups 208 accessing help
vertically 209, 320 information 345
Alignment (Edit menu) 78, 149 bilingual 323
anchoring 213–218 blocking 539
flags 215 closing 99
offset 213, 217, 218 command-line options
animation 419–424 defaults for PhAB
cycling through snapshots 421 applications 101
eliminating flicker 422–424 processing 252, 522
graphics bandwidth 485 specifying in Build &
loading images from a file 420 Run 237
widget database 419 compiling 520
ApAddClass() 311 context 522
ApAppendTranslation() 323 creating 95
ApCloseDBase() 311 debugging 237, 238
ApCopyWidget() 312 directory 231, 232
ApCreateModule() 303, 306 drawing 395
ApCreateWidget() 311, 312 exiting, verifying 512

588 Index September 20, 2005


 2005, QNX Software Systems Index

files 230 running 237


initialization function 101, saving 97, 98, 224
249, 251 standalone 516
language startup windows 104–106
@ in instance names 141, version control 227
322 version, displaying 358
choosing a language 330 Application Information dialog 99
database 324 Application menu 77
design considerations 317 Build & Run 224
distributing an Convert to Multiplatform 233
application 332 Internal Links 304
font size 320 Languages
help resources 329 Generate Language
hotkeys 329 Database 324
justification 318 Run Language Editor 325
running 330 module types 112–115
text widgets 317 Startup Info/Modules 99,
translating text 328 103–105, 229
translation file 326, 327, 330 Application Startup Information
widget database 321 dialog 99
lengthy operations 349, 376 applications
modal dialog 377 files
QNX messages 376 non-PhAB, including 239,
timers 383 240
visual feedback 376 ApSaveDBaseFile() 311
work procedures 376–378, ApWidget() 256
382 arc (draw primitive) 409
linking 520 argument list 269
mainloop function 103, 226, Arm callback 125, 183, 497, 498
254, 255, 519, 524 Arrange Icons (Window
multilingual See application menu) 130, 134
language Arrange Modules (Window
non-PhAB 519 menu) 82, 134
opening 95 ASCII 559
overwriting 98 AwFileSelect 129
region 539, 545 AwMessage 129
renaming 97

September 20, 2005 Index 589


Index  2005, QNX Software Systems

B disabling 195
keycap 193
backdrop label 192
region 482, 544, 546 menu items 120, 192
balloons, descriptive 90 modifier keys 191
beveled box (draw primitive) 406 multilingual
bitmap (draw primitive) 412 applications 193, 329
border, widget 13, 14, 16 processing 194
Build & Run (Application link 184
menu) 224 Lost Focus 290
Build & Run dialog 24, 25, 90, 91, Menu 183
223, 224, 232–234, 237 menu item 261
module-type link 184, 187
parameters 257, 294
preattaching 310
C raw-event 184, 188, 190, 196,
C++ 297, 500
class member functions 250 reason 295
main program 226 removing 187, 295
prototypes 228 Repeat 183
callback See also work procedures return value 258
Activate 125, 183, 261, 293 traversing callback lists 297
adding 186, 292 callbacks
Arm 125, 183, 497, 498 Activate
Cancel 184, 190, 257 modifier keys 490
client data 293, 294, 296, 525 Callbacks mode 85
code-type link 184, 189, 190, canvas 13, 207
257 cbinfo 256, 258, 261
cc 520
defined 11, 183, 525
Disarm 183 characters
Done 184, 190, 258 conversion functions 557, 561
editing 185 encodings other than
examining in your code 296 Unicode 561
filename 249 international 180, 272,
hotkey 183, 188, 190–194 557–563
<PkKeyDef.h> 193
multibyte 557, 559, 560
callback 192 Unicode encodings 559

590 Index September 20, 2005


 2005, QNX Software Systems Index

wide 557, 559 linking 235, 236, 520


child mainloop function 103, 226,
region 474, 475 254, 255, 519, 524
chord (draw primitive) 409 making 235, 236
circle (draw primitive) 409 menu setup 258–260
client data 300 creating submenus 262
clipboard 156–158 setup function 189, 255
Clipboard (View menu) 158 version control 227
clipping area See canvas viewing 233
Close (File menu) 99 code-type link callback 184, 189
closing color 403
application 99 color editor 172
modules 111, 132 color palette
code global 414
accessing help hard 414
information 345 physical 414
callbacks 257 soft 414
filename 249 command-line options
compiling 235, 236, 520 defaults for PhAB
creating 234 applications 101
deleting 233 processing 252, 522
editing 223, 233, 236, 249 specifying in Build & Run 237
filename 249, 250 Common User Access
files 225, 230 (CUA) 150–152
non-PhAB, including 239, compose key sequences 563
240 container widget See also
generating 223, 225 PtGroup
initialization function 101, absolute positioning 207
249, 251 aligning children 149
filename 249 anchoring 213, 215
lengthy operations 349, 376 defined 201
modal dialog 377 duplicating 159
QNX messages 376 flags 215
timers 383 focus 150–152
visual feedback 376 geometry management 201
work procedures 376–378, manipulating in PhAB 139
382

September 20, 2005 Index 591


Index  2005, QNX Software Systems

moving children between resource names 84, 90


containers 154 resources displayed 110, 145,
overview 139 163, 208
PhAB modules 109 resources not displayed 85
picture modules 126, 303 selecting widgets 83, 144, 146,
positioning children 16, 147, 147, 153, 209
153, 202 Control Panel (View menu) 82
Pt CB RESIZE 218 conventions, typographical xxvii
resize callback 218 Convert to Multiplatform
resize flags 205, 206 (Application menu) 233
resize policy 203 coordinate space 469, 470, 472,
selecting children 139 537, 542, 543
widget databases 308 Copy (Edit menu) 78, 157
Control Panel create mode 80, 143
about 31 CUA (Common User
background color 91 Access) 150–152
Callbacks mode 85, 185, 196 Customize Widget Bar (Options
display modes 82 menu) 81
displaying 82 customizing
editing a color resource 172 colors 91
editing a font resource 175 dragging 91
editing a list resource 176 editor 90
editing a pixmap resource 164 file viewer 90
editing a text resource 179 PhAB 89
editing callback resources 185 print command 91
editing menu items 118 widget bar 81
editing raw callbacks 196 Cut (Edit menu) 78, 157
finding 82 CVS 228
instance name 83, 140
Module Links mode 88
Module Tree mode 87, 144,
146, 147, 153 D
next and previous buttons 83,
146, 147, 153 damping factor 91
overview 82 data types
positioning 82, 134 PhEvent t 489, 492
Resource mode 83, 163 PhEventRegion t 492

592 Index September 20, 2005


 2005, QNX Software Systems Index

PhPointerEvent t 490 handling events 501


database, language See language initiating 498
database specifying 498
database, widget See widget preferences 91
database draw context 424, 437
dead keys 563 draw event 539, 542–544
debugging an application 237, 238 draw primitives 21, 403–415
Delete (Edit menu) 157, 159 arc 409
deleting beveled box 406
modules 115 bitmap 412
widgets 159 chord 409
Desktop Manager See PDM circle 409
dev arm() 363 flags 404
development platform flickerless animation 423
multiple 231, 233, 239 image 413
single 232, 240 caching 416
device region 472, 539–542, 545 creating 415
dialog direct color 413, 415
modal 377, 383 displaying 417
example 384 format 414
module 116, 507 gradient color 414, 415
resizing 117 palette-based 413, 414
direct-color image See image releasing 418
(draw primitive) remote processes 416
Disarm callback 183 shared memory 417, 418
double-buffered container 423 transparency 416
dragging 496–503 line 411
event 196, 540, 541 overlapping polygon 407
events 496, 500, 501, 503 pie 409
initiating 497 pixel 411
opaque polygon 407
defined 497 rectangle 404
handling events 503 rounded rectangle 405
initiating 500 text 411
specifying 498 draw stream 437
outline driver
defined 496 encapsulation 544

September 20, 2005 Index 593


Index  2005, QNX Software Systems

graphics 21, 173, 469, editor buttons 163


540–544 flags 173
multiple 542 fonts 175
input 541 functions 182
keyboard 540–542, 557, 562 lists 176
mouse 540, 541 numbers 178
output 541 pixmaps 164
overlapping regions 543 text, multiline 180
printer 541, 543, 544 text, single line 179
separate regions 543 encapsulation driver 544
driver region 539 environment variables
duplicating ABLANG 330
containers 159 ABLPATH 330, 332, 333
widgets 159 PHIG 542
even-odd rule 407
event
callback 295, 297
E clipping 474
consuming 297, 300
edit command, specifying 90 data 300, 532
Edit menu 77 defined 4, 531, 532
Alignment 78, 149 drag 196, 540, 541
Copy 78, 157 draw 539, 542–544
Cut 78, 157 expose 543
Delete 157, 159 focusing 540
Group Together 78, 208 handler 184, 188, 190, 196,
Paste 78, 158 297, 525
Split Apart 78, 213 adding 298
To Back 78, 152 invoking 300
To Front 78, 152 removing 299
Transfer 78, 154 handling 254, 255, 519, 524,
editing 526
callbacks 185 intersection with regions 532
code 249 keyboard 536, 540, 541, 544,
menus 118 545
resources 163 lengthy operations 349
colors 172 logging 536

594 Index September 20, 2005


 2005, QNX Software Systems Index

mask 188, 190, 196, 297–299 modifier keys 490


modifying 536 PhEvent t 489, 492
nonopaque regions 535 PhEventRegion t 492
notification 538 pointer 496
asynchronous 539 buttons 489
polling 538 PhPointerEvent t 490
synchronous 539 rectangle set 496
opaque regions 534–536 region 496
point source 533 targeting regions 493
pointer 524, 536, 540, 541, exit() 513
545 expose event 543
cooked 540 extended library 520
focused 540
raw 540
unfocused 540
raw 184, 196, 197 F
rectangle set 532, 533, 535,
536 file extension
collected 533 .html 337
region 524 .ldb 324
resize 218 .toc 340
root region 537 .wgtd 109, 116
sensitive regions 298, 534–536 .wgti 109, 127
space 3, 469, 531, 533 .wgtm 109, 117
types 538 .wgtp 109, 126
events .wgtw 109, 115
boundary 496 .wgtx 109, 129
collecting 496 File menu 77
compression 496 Close 99
coordinates 496 Import Files 130, 131, 160
data 490 New 95
drag 496, 500, 501, 503 Open 95
emitting 491 Save 98
key 495 Save As 97, 98
to a specific widget 494 file selector module 129
handler 500 files
mask 500

September 20, 2005 Index 595


Index  2005, QNX Software Systems

non-PhAB, including in your grid 147


application 239, 240 Grid (Options menu) 148
finding Group Together (Edit menu) 78,
modules 134 208
widgets 147 groups
flag editor 173 creating 78, 208
focus 150, 151, 290, 540 realizing 210
functions 152 splitting 78, 213
region 544, 545
font editor 175
fontcfg 427
FontDetails 429 H
fontdir 427
fonts 427 header file, global 100, 225, 248
frame help
window 545 accessing from code 345
function editor 182 displaying
function prototypes 228 in a balloon 344
potential problems 229 in the Helpviewer 343
files 337
table-of-content (TOC)
files 340, 341
G topic path 342–345
topic root 343–346
Generate Language Database Universal Resource Locator
(Application menu, (URL) 341–343, 345
Languages submenu) 324 restriction on scope 342
generating code 223, 225 root 345, 346
geometry negotiation 201 Help menu 77, 91
getopt() 253 About PhAB 92
global header file 100, 225, 248 Helpviewer
gradient-color image See image HTML tags 337
(draw primitive) HTML1/ISO entities 339
graphic files, importing 159 high color 403
graphics driver 21, 173, 469, hotkey 183, 188, 190
540–544 <PkKeyDef.h> 193
multiple 542 callback 192

596 Index September 20, 2005


 2005, QNX Software Systems Index

disabling 195 graphic files 159


keycap 193 QNX Windows picture
label 192 files 131
menu items 120, 192 indHfiles 239
modifier keys 191, 194 indOfiles 239
multilingual applications 193, indSfiles 239
329 initialization function 101, 249,
processing 194 251
hotkey callback 194 filename 249
HTML 337 INITIAL PC 445
anchor 341 input groups
defined 542
determining 542
keyboard driver 495
I regions, information
about 484, 485
I/O 375 input handler 351
icon adding 352
instance name 114, 128 removing 354
manifests 247 instance name 83, 119, 140, 158,
module 127 159
resizing 128 generated by PhAB 141, 322
image (draw primitive) 413 icon module 128
caching 416 icon widgets 128
creating 415 in widget databases 310
direct color 413, 415 including in widgets 104
displaying 417 language database 141, 322
format 414 starting with @ 141, 322
gradient color 414, 415 INTERACTIVE PC 445
palette-based 413, 414 internal link 247, 303, 309
releasing 418 accessing picture modules 303
remote processes 416 creating 304
shared memory 417, 418 creating a module 303
transparency 416 manifests 305
Import Files (File menu) 130, 131, opening widget databases 303
160 setup function 305
importing

September 20, 2005 Index 597


Index  2005, QNX Software Systems

Internal Links (Application database 141, 317, 322,


menu) 304 324–327, 329, 330, 333
international characters 180, 272, design considerations 317
557–563 distributing an application 332
interprocess communication (IPC) editor 324
asynchronous 359 in PhAB 325
messages 350 standalone 326, 333
pulses 359 font size 320
signals 373 help resources 329
synchronous 350 hotkeys 329
ionotify() 363 international characters 328
justification 318
running a multilingual
application 330
K text widgets 317
translating text 328
key presses, simulating 495 translation file 326, 327, 330
keyboard widget database 321
driver 540–542, 557, 562 Languages (Application
drivers 495 menu) 324, 325
event 536, 540, 541, 544, 545 languages.def 326, 331, 333
events lengthy operations 349, 376
emitting 495 modal dialog 377
focus 150, 540 QNX messages 376
shortcut 119, 122 timers 383
keycap 193 visual feedback 376
keys, modifier 191, 490 work procedures 376, 377
adding 378
example 378
preemption 382
L removing 378, 382
language libex.a 520
@ in instance names 141, 322 libphoton.a 520
bilingual applications 323 libphoton.so 520
changing 237 libphrt.a 520
choosing a language 330 libraries 20, 235
common strings 323 extended 520

598 Index September 20, 2005


 2005, QNX Software Systems Index

multithreading 251 ABN ... 119, 243, 244, 259


of user functions 250 ABW ... 243–245, 247, 248
realtime 520 widget database 312
shared 235, 520 window, multiple instances
static 235, 520 of 245
version numbers 22 margins 15
line (draw primitive) 411 margins, widget 13
link instance 256 mblen() 558
list editor 176 mbstowcs() 558
Location dialog 132, 188 mbstrblen() 558
Lost Focus callback 290 mbstrchr() 558
mbstrlen() 558
mbstrnchr() 558
mbstrncmp() 558
M mbstrnlen() 558
mbstrrchr() 558
mainloop function 103, 226, 254, mbtowc() 558
255, 519, 524 MC See memory context
make command 236 memory context 423, 437
Makefile menu
adding libraries 240 command items 120
dependency on header disabling items 258
files 249 displaying 125
generated by PhAB 226 editing 118
multiplatform applications 232 enabling items 258
converting to 233 function item 124, 260
including non-PhAB creating submenus 262
files 240 generating items at
renaming the application 98 runtime 124, 260
restrictions on modifying 235 creating submenus 262
running make 235 hotkeys 119, 192, 193
single-platform items 118
applications 233 instance names 119
including non-PhAB moving 124
files 240 text, changing 259
manifests text, getting 260
ABM ... 247, 305 module 117

September 20, 2005 Index 599


Index  2005, QNX Software Systems

resizing 120 Message 129


separator items 122 minimizing 130
shortcuts 119, 260 opening 114
submenu item 122 Other 129
toggle item 123 Picture 126
toggling items 258 predefined 129
Menu callback 183 selecting 134
menubar 30, 77 setup function 188, 255, 305
message module 129 filename 249
messages 349 return value 256
receiving 351 specifying a location 132, 188
sending 350 Test mode 111, 153
modal dialog 377, 383 types 109
example 384 in Application menu 112
modifier keys 191, 490 usage 109
module viewing 114
accessing with an internal Window 115, 507
link 303 Window menu 134
as container 109 Work menu 111, 130
closing 111, 132 Module Links mode 88
colors 109 module selector 112–115
creating 113 Module Tree mode 87
creating within application module-type link callback 184, 187
code 303 mouse driver 540, 541
deleting 115 MsgSendv() 364
Dialog 116, 507 multibyte characters 557, 559, 560
file extensions 109 conversion functions 557
File selector 129 multiline text editor 180
finding 134 multilingual application See
Icon 127 language
iconifying 130 multiplatform development 231,
icons 233, 239
moving 130 multithreaded programs 251
rearranging 130 MYHDR 239, 240
importing 130 MYOBJ 239, 240
instance name 111, 113, 243 MYSRC 239, 240
Menu 117, 118

600 Index September 20, 2005


 2005, QNX Software Systems Index

N Paste (Edit menu) 78, 158


pathname delimiter in QNX
Neutrino pulses 359. See also Momentics documentation
pulses xxviii
New (File menu) 95 PC See print context
NFS and PhAB 97 PDM 114, 127, 247, 310
non-PhAB code, including in your PDR (press-drag-release)
application 239, 240 method 125
number editor 178 PfQueryFonts() 428
Pg.h 403
Pg ARC 410
Pg ARC CHORD 410
O Pg ARC PIE 410
Pg BACK FILL 411, 412
Open (File menu) 95
Pg CLOSED 407
opening
PgColor t 403
application 95
PgDrawArc() 409
modules 114
Pg DRAW FILL 404, 406
Options menu 77
Pg DRAW FILL STROKE 404
Customize Widget Bar 81
PgDrawImage() 417
Grid 148
PgDrawImagemx() 417
Preferences 85, 89
PgDrawIRect() 404
options, command-line See
PgDrawPhImagemx() 417
command-line options
PgDrawPolygon() 409
Other module 129
PgDrawPolygonmx() 409
how displayed 90
PgDrawRect() 404
resizing 129
PgDrawRepImage() 417
overlapping polygon (draw
PgDrawRepImagemx() 417
primitive) 407
PgDrawRoundRect() 405
overwriting an application 98
Pg DRAW STROKE 404, 406
PgDrawTImage() 417
PgDrawTImagemx() 417
P Pg IMAGE DIRECT 888 423, 424
Pg IMAGE PALETTE BYTE 423,
palette-based image See image 424
(draw primitive) Pg POLY RELATIVE 407
parent region 474, 475 PgSetFillColor() 414

September 20, 2005 Index 601


Index  2005, QNX Software Systems

PgSetTranslation() 398 resources displayed 110,


PgSetUnderline() 411 145, 163, 208
PgShmemCreate() 417, 418 resources not displayed 85
PhAB selecting widgets 83, 144,
balloon help 92 146, 147, 153, 209
disabling 90 customizing 89
clipboard 156–158 exiting 92
context-sensitive help 92 grid 147
Control Panel help 91
about 31 menubar 30, 77
background color 91 NFS, use with 97
Callbacks mode 85, 185, SMB, use with 97
196 speedbar 30, 78
display modes 82 hiding 90
displaying 82 version number 92
editing a color resource 172 widget bar 30, 79
editing a font resource 175 customizing 81
editing a list resource 176 work area 31, 130
editing a pixmap phablang language editor 326,
resource 164 333
editing a text resource 179 PhAttach() 522
editing callback Ph DEV RID 495
resources 185 phditto 416
editing menu items 118 Ph DRAG TRACK 498, 500
editing raw callbacks 196 Ph EV BUT PRESS 489, 490
finding 82 modifier keys 490
instance name 83, 140 Ph EV BUT RELEASE 489
Module Links mode 88 modifier keys 490
Module Tree mode 87, 144, Ph EV DRAG 196, 500
146, 147, 153 Ph EV DRAG COMPLETE 501
next and previous Ph EV DRAG MOVE 500, 503
buttons 83, 146, 147, 153 Ph EV DRAG START 500
overview 82 PhEvent t 489, 492
positioning 82, 134 Ph EVENT DIRECT 494
Resource mode 83, 163 PhEventEmit() 491
resource names 84, 90 PhEventEmitmx() 492
Ph EVENT INCLUSIVE 493

602 Index September 20, 2005


 2005, QNX Software Systems Index

PhEventNext() 496 PhInputGroup() 542


PhEventRead() 496 PhKbdInfo t 484
PhEventRegion t 492 Ph KBD REGION 495
Ph EV KEY 495 PhKeyEvent t 562
Ph EV RAW 495 Ph LIB VERSION 22
Ph EV RAW KEY 495 PhLibVersion() 22
Ph EV RELEASE ENDCLICK 489 PhMakeTransBitmap() 416
Ph EV RELEASE PHANTOM 489 photon s.lib 21, 520
Ph EV RELEASE REAL 489 Photon coordinate space 469, 470,
phexlib3r.lib 21, 520 472, 537, 542, 543
PHFONT ALL FONTS 429 Photon Desktop Manager 114, 127,
PHFONT ALL SYMBOLS 428 247, 310
PHFONT BITMAP 428 Photon Manager 197, 475, 477,
PHFONT FIXED 428 478, 492–494, 496, 531,
PHFONT INFO BOLD 430 534, 538–542, 545
PHFONT INFO FIXED 430 Photon pulses See pulses
PHFONT INFO ITALIC 430 Photon Window Manager 127, 133,
PHFONT INFO PLAIN 430 188, 476, 482, 522, 540,
PHFONT INFO PROP 430 542, 544–546
PHFONT PROP 428 taskbar 127, 237, 238, 248
PHFONT SCALABLE 428 workspace menu 545
Ph FORCE FRONT 477, 478, 480 photon3r.lib 520
PhGeneralSysInfo t 484 PhPoint t 405, 407
Ph GEN INFO BANDWIDTH 485 PhPointerEvent t 490
Ph GEN INFO CAPABILITIES 485 PhPtrInfo t 484
Ph GEN INFO NUM GFX 485 PhQuerySystemInfo() 483
Ph GEN INFO NUM IG 485 PhRawKeyEvent t 495
Ph GEN INFO NUM KBD 485 PhRect t 404
Ph GEN INFO NUM PTR 485 PhRegion t 481, 495
PhGetData() 300, 490, 496 PhRegionChange() 298, 473, 481
PhGetRects() 496 Ph REGION INPUT GROUP 495
PhGrafxInfo t 484 PhRegionOpen() 470, 473
PHIG environment variable 542 PhRegionQuery() 481, 482
PhIgInfo t 484 phrelay 416
PhImage t 414, 420 Ph RELEASE GHOST BITMAP 418
phindows 416 Ph RELEASE IMAGE 418
PhInitDrag() 497 PhReleaseImage() 418

September 20, 2005 Index 603


Index  2005, QNX Software Systems

Ph RELEASE PALETTE 418 Ph WM STATE ISBACKDROP 513


Ph RELEASE TRANSPARENCY MASK Ph WM STATE ISBLOCKED 513
418 Ph WM STATE ISFOCUS 513
phrtlib3r.lib 520 Ph WM STATE ISFRONT 513
PhSysInfo t 483 Ph WM STATE ISHIDDEN 513
Ph TRACK BOTTOM 498 Ph WM STATE ISMAX 513, 516
Ph TRACK DRAG 498 Ph WM TOBACK 508, 510
Ph TRACK LEFT 498 Ph WM TOFRONT 508, 510
Ph TRACK RIGHT 498 picture
Ph TRACK TOP 498 as widget database 126, 419
PhWindowChange() 515 displaying 126
PhWindowClose() 515 module 126, 308, 309, 323
PhWindowEvent t 511 accessing and
PhWindowOpen() 516 displaying 303
PhWindowQueryVisible() 516 resizing 127
Ph WM APP DEF MANAGED 509 pie (draw primitive) 409
Ph WM BACKDROP 508, 510 pipes 375
Ph WM CLOSE 508, 510–512 pixel (draw primitive) 411
Ph WM CONSWITCH 508, 510 pixmap editor 164
Ph WM FFRONT 508, 510 PkKeyDef.h 559
Ph WM FOCUS 508, 510 PmMemCreateMC() 423, 424
Ph WM HELP 343, 508, 510 PmMemFlush() 423, 424
Ph WM HIDE 508, 510 PmMemReleaseMC() 423, 424
Ph WM MAX 508, 510 PmMemSetChunkSize() 424
Ph WM MENU 508, 510 PmMemSetMaxBufSize() 424
Ph WM MOVE 508, 510 PmMemSetType() 424
Ph WM RENDER BORDER 508 PmMemStart() 424
Ph WM RENDER CLOSE 508 PmMemStop() 424
Ph WM RENDER HELP 343, 508 pointer
Ph WM RENDER MAX 508 buttons, multiple clicks 489
Ph WM RENDER MENU 508 event 524, 536, 540, 541, 545
Ph WM RENDER MIN 508 cooked 540
Ph WM RENDER RESIZE 508 focused 540
Ph WM RENDER TITLE 508 raw 540
Ph WM RESIZE 508, 510 unfocused 540
Ph WM RESTORE 508, 510 events
Ph WM STATE ISALTKEY 513 buttons 489

604 Index September 20, 2005


 2005, QNX Software Systems Index

focus 540 PpPrintClose() 461


polygon (draw primitive) 407 PpPrintCreatePC() 446
polygon, overlapping (draw PpPrintGetPC() 438, 452
primitive) 407 PpPrintNewPage() 456, 457
Pp PC COLLATING MODE 442 PpPrintOpen() 455
Pp PC COLOR MODE 444 PpPrintReleasePC() 462
Pp PC COMMENT 439 PpPrintSetPC() 438, 447, 451
Pp PC CONTROL 444 PpPrintStart() 455, 461
Pp PC COPIES 443 PpPrintStop() 461
Pp PC DATE 440 PpPrintWidget() 456
Pp PC DEVICE 438 predefined module See Other
Pp PC DITHERING 442 module
Pp PC DO PREVIEW 444 Preferences (Options menu) 85, 89
Pp PC DRIVER 439 press-drag-release (PDR)
Pp PC DUPLEX 443 method 125
Pp PC FILENAME 439 print command, specifying 91
Pp PC INKTYPE 443 print context 437, 438
Pp PC INTENSITY 442 creating 446
Pp PC JOB NAME 444 example 463
Pp PC LOCATION 438 freeing 462
Pp PC MARGINS 441 modifying 446
Pp PC NAME 438 printing 452
Pp PC NONPRINT MARGINS 439 printer driver 541, 543, 544
Pp PC ORIENTATION 443 PRINTER GLOBAL 445
Pp PC PAGE RANGE 440 PRINTER LOCAL 445
Pp PC PAPER SIZE 442 printing 437–463
Pp PC PAPER SOURCE 443 closing 461
Pp PC PAPER TYPE 443 collating mode 442
Pp PC PREVIEW APP 439 color mode 444
Pp PC PRINTER RESOLUTION 442 control 444
Pp PC PROP APP 439 date 440
Pp PC SCALE 441 dithering 442
Pp PC SOURCE COLORS 441 driver application 439
Pp PC SOURCE OFFSET 440 duplex 443
Pp PC SOURCE RESOLUTION 441 example 463
Pp PC SOURCE SIZE 441 ink type 443
Pp PC USER ID 440 intensity 442

September 20, 2005 Index 605


Index  2005, QNX Software Systems

job name 444 PtScrollArea 460


margins 441 scrolling widgets 457
multiple print sessions 462 proto.h 225, 227, 228
new page 456, 457 potential problems 229
nonprintable margins 439, 452 prototypes 228
number of copies 443 potential problems 229
orientation 443 proxies 359. See also pulses
overview 437 PtAddCallback() 261, 292–294,
page range 440 519
paper size 442 PtAddCallbacks() 292, 294, 519
paper source 443 PtAddEventHandler() 298
paper type 443 PtAddEventHandlers() 298
preview 439, 444 PtAddHotkeyHandler() 196
print context 437, 438 PtAppAddFd() 375
creating 446 PtAppAddFdPri() 375
freeing 462 PtAppAddInput() 352
modifying 446 PtAppAddSignalProc() 373
printer location 438 PtAppAddWorkProc() 378
printer name 438 PtAppCreatePulse() 361
printer properties 439 PtAppDeletePulse() 365
printer resolution 442 PtAppInit() 519, 522
resuming 461 PtAppPulseTrigger() 365
scale 441 PtAppRemoveInput() 354
source PtAppRemoveSignalProc() 375
colors 441 PtAppRemoveWorkProc() 378
offset 440, 455, 456 PtAppSetFdMode() 375
resolution 441 PtArg t 269
size 441, 452, 457 Pt ARG() 270
spooler 438 Pt ARG ACCEL KEY 192
starting 452 multilingual applications 329
suspending 461 Pt ARG ANCHOR FLAGS 215
to a file 439 Pt ARG ANCHOR OFFSETS 218
widgets 455 Pt ARG AREA 16, 85
by damaging 456 Pt ARG BORDER WIDTH 14, 271
PpPrintWidget() 456 Pt ARG BUTTON TYPE 263
PtList 458 Pt ARG CBOX FLAGS 274
PtMultiText 458

606 Index September 20, 2005


 2005, QNX Software Systems Index

Pt ARG CONTAINER FLAGS Pt ARGTEXT STRING 272, 280


151, 191, 194 Pt ARGTIMER INITIAL 421
Pt ARG DB IMAGE TYPE 423 Pt ARGTIMER REPEAT 421
Pt ARG DIM 14, 85, 154, 207 Pt ARGUSER DATA 273, 401
Pt ARG EFLAGS 344 Pt ARGWINDOW HELP ROOT
Pt ARG FLAGS 151, 191, 195, 343
279, 376, 383, 418, 497, Pt ARG WINDOW MANAGED FLAGS
513 343, 507–509, 512, 513,
Pt ARG GROUP FLAGS 211 515
Pt ARG GROUP ORIENTATION Pt ARG WINDOW NOTIFY FLAGS
209 507, 509, 511, 512
Pt ARG GROUP ROWS COLS Pt ARG WINDOW RENDER FLAGS
210 343, 507, 508, 516
Pt ARG GROUP SPACING 209, Pt ARG WINDOW STATE 507,
210 513, 514, 516
Pt ARG HELP TOPIC 344 PtAskQuestion() 377
Pt ARG ICON WINDOW 128 Pt AS REQUIRED 207
Pt ARG ITEMS 273 PtBasic 15, 183
Pt ARG LABEL DATA 415, 417 PtBasicWidgetCanvas() 397
Pt ARG LABEL TYPE 160 PtBezier 143
Pt ARG MARGIN HEIGHT 15 PtBkgdHandlerProcess() 376, 377
Pt ARG MARGIN WIDTH 15 Pt BLOCK CUA FOCUS 151
Pt ARG MENU FLAGS 263 Pt BLOCKED 376, 383, 384
Pt ARG MULTITEXT NUM LINES Pt BOTTOM ANCHORED BOTTOM 216
458 Pt BOTTOM ANCHORED RELATIVE 216
Pt ARG MULTITEXT NUM LINES VISIBLE Pt BOTTOM ANCHORED TOP 216
458 Pt BOTTOM IS ANCHORED 217
Pt ARG MULTITEXT ROWS 459 PtButton 293, 415
Pt ARG POS 16, 85, 207, 501 PtCallbackInfo t 295
Pt ARG PRINT CONTEXT 450 PtCallbackList t 296
Pt ARG RAW CONNECT F 396 Pt CB ACTIVATE 125, 183, 261,
Pt ARG RAW DRAW F 396 293
Pt ARG RAW EXTENT F 396 modifier keys 490
Pt ARG RAW INIT F 396 Pt CB ARM 125, 183, 497, 498
Pt ARG RESIZE FLAGS 202, Pt CB DESTROYED 13, 290, 513
203, 205 Pt CB DISARM 183
Pt ARG TERM PROTOCOL 276 Pt CB GOT FOCUS 151

September 20, 2005 Index 607


Index  2005, QNX Software Systems

Pt CB HOTKEY 120, 192 Pt FOCUS RENDER 151


multilingual applications 329 PtForwardWindowEvent() 514, 516
Pt CB LOST FOCUS 152, 290 PtForwardWindowTaskEvent() 514,
Pt CB MENU 183 516
Pt CB RAW 196, 297, 298, 500 PtFrameSize() 516
Pt CB REALIZED 12 Pt FREE MEMORY 418
Pt CB REPEAT 183 PtGetParent() 263, 291
Pt CB RESIZE 218 PtGetParentWidget() 291
Pt CB TIMER ACTIVATE 421 PtGetResources() 269, 278, 279,
Pt CB UNREALIZED 12 281–286, 297
Pt CB WINDOW 511, 512 Pt GETS FOCUS 151, 191, 195
Pt CB WINDOW CLOSING 511, Pt GHOST 195
513 PtGroup 208, 213
PtChannelCreate() 360 flags 211
PtChildType() 291 Pt GROUP EQUAL SIZE 211
PtClipAdd() 399 Pt GROUP EQUAL SIZE HORIZONTAL
PtClipRemove() 399 211
PtComboBox 271 Pt GROUP EQUAL SIZE VERTICAL
Pt COMBOBOX STATIC 274 211
PtConsoleSwitch() 516 Pt GROUP EXCLUSIVE 211
PtContainer 201 Pt GROUP HORIZONTAL 209
PtContainerCallback t 218 Pt GROUP NO KEYS 211
PtContainerGiveFocus() 290 Pt GROUP NO KEY WRAP HORIZONTAL
Pt CONTINUE 189, 256, 258, 354 211
PtCreateWidget() 260, 261, 269, Pt GROUP NO KEY WRAP VERTICAL
276, 289, 293, 519, 523 211
PtDBContainer 423 Pt GROUP NO SELECT ALLOWED 211
Pt DELAY REALIZE 524 Pt GROUP STRETCH FILL 212
Pt DESTROYED 513 Pt GROUP STRETCH HORIZONTAL 212
PtDestroyWidget() 13, 513 Pt GROUP STRETCH VERTICAL 212
Pt ENABLE CUA 151 Pt GROUP VERTICAL 209
Pt ENABLE CUA ARROWS 151 Pt HOTKEYS FIRST 191, 194
Pt END 256, 300, 375, 382 Pt HOTKEY TERMINATOR 194
PtFileSelection() 377 Pt IMAGE 160
PtFindFocusChild() 291 PtInit() 251
PtFindGuardian() 291 Pt INITIAL 207
PtFlush() 354, 376, 378, 383 Pt INTERNAL HELP 344

608 Index September 20, 2005


 2005, QNX Software Systems Index

PtLabel 160, 180, 415, 419 canvas 397


Pt LEFT ANCHORED LEFT 216 clipping 399
Pt LEFT ANCHORED RELATIVE 216 damage tiles 400
Pt LEFT ANCHORED RIGHT 216 drawing function 396
Pt LEFT IS ANCHORED 217 dynamic contents 401
Pt LINK DELETE 275 examples of drawing
PtLinkedList t 283 functions 401
Pt LINK INSERT 275 translating coordinates 398
PtList 176 PtRawCallback t 298
printing 458 PtRawCallbackList t 298
PtMainLoop() 519, 524 PtRealizeWidget() 12, 290, 519,
PtMenu 263 523, 524
PtMenuBar 125 Pt REGION 524
PtMenuButton 125, 260 PtRemoveCallback() 295
hotkeys 192 PtRemoveCallbacks() 295
Pt MENU CHILD 263 PtRemoveEventHandler() 299
Pt MENU DOWN 263 PtRemoveEventHandlers() 299
Pt MENU RIGHT 263 PtRemoveHotkeyHandler() 196
PtMultiText 180 PtReParentWidget() 289
printing 458 Pt RESIZE X ALWAYS 203
PtNextTopLevelWidget() 291, 385 Pt RESIZE X AS REQUIRED 204
PtPane 207 Pt RESIZE X BITS 206
PtPolygon 143 Pt RESIZE X INITIAL 205
Pt PP NO RESIZE 457 Pt RESIZE XY ALWAYS 204
Pt PP RESIZE PC 457 Pt RESIZE XY AS REQUIRED 204
Pt PP RESIZE WIDGET 457 Pt RESIZE XY BITS 206
PtPrintSel 446, 447, 450 Pt RESIZE XY INITIAL 205
PtPrintSelection() 446, 447 Pt RESIZE Y ALWAYS 204
PtProcessEvent() 377, 383 Pt RESIZE Y AS REQUIRED 204
PtPulseArmFd() 362 Pt RESIZE Y BITS 206
PtPulseArmPid() 362 Pt RESIZE Y INITIAL 205
PtPulseDeliver() 370 Pt RIGHT ANCHORED LEFT 216
multithreading 251 Pt RIGHT ANCHORED RELATIVE 216
PtPulseDisarm() 365 Pt RIGHT ANCHORED RIGHT 216
PtPulseMsg t 360 Pt RIGHT IS ANCHORED 217
PtQuerySystemInfo() 483 PtScrollArea
PtRaw 21, 182, 395, 423 printing 460

September 20, 2005 Index 609


Index  2005, QNX Software Systems

Pt SELECTABLE 191, 195, 497 render flags 343, 508, 516


Pt SELECT NOREDRAW 191 state 513, 516
PtSendEventToWidget() 494 PtWindowConsoleSwitch() 516
PtSetArg() 206, 218, 260, 269, pulses 359
271–276, 278, 279, arming 362
281–285, 293, 294, 297, creating 361
523 delivering from a non-Photon
PtSetParentWidget() 263, 289, 311 application 373
PtSetResources() 11, 206, 260, delivering from a Photon
269, 271–276, 293 application 369, 370
PtSpawnWait() 377 delivering to yourself 365
PtSuperClassDraw() 396 destroying 365
PtText 179 disarming 365
PtTimer 383, 421 receiving 360
Pt TOP ANCHORED BOTTOM 216 example 365
Pt TOP ANCHORED RELATIVE 216 registering an input
Pt TOP ANCHORED TOP 216 handler 364
Pt TOP IS ANCHORED 217 sending to the deliverer 363
PtUnrealizeWidget() 12, 513, 524 PWM 127, 133, 188, 476, 482,
PtValidParent() 291, 460 507–516, 522, 540, 542,
PtWidget 297 544–546
PtWidgetBrotherBehind() 291 taskbar 127, 237, 238, 248
PtWidgetBrotherInFront() 291 workspace menu 545
PtWidgetChildBack() 292 PxCRC() 416
PtWidgetChildFront() 292 PxHelpQuit() 346
PtWidgetFamily() 292 PxHelpSearch() 345
PtWidgetInsert() 290 PxHelpTopic() 345
PtWidgetParent() 292 PxHelpTopicRoot() 345
PtWidgetRid() 497 PxHelpTopicTree() 345
PtWidgetSkip() 292 PxHelpUrl() 345
PtWidgetToBack() 290 PxHelpUrlRoot() 345
PtWidgetToFront() 290 PX IMAGE MODULES 421
PtWidgetTree() 292 PxLoadImage() 415, 417, 418, 420
PtWidgetTreeTraverse() 292 PxTranslateFromUTF() 561
PtWindow 207, 507 PxTranslateList() 562
managed flags 343, 508, 515 PxTranslateSet() 562
notify flags 508, 509, 511 PxTranslateStateFromUTF() 562

610 Index September 20, 2005


 2005, QNX Software Systems Index

PxTranslateStateToUTF() 562 application 539, 545


PxTranslateToUTF() 562 backdrop 482, 544, 546
PxTranslateUnknown() 562 brother 476
behind 477, 480
in front 477, 480
specifying 482
Q child 474, 475, 536
coordinates 470
qcc 521 creating 519, 524
QNX messages 349 defined 469, 532
receiving 351 destroying 473
sending 350 device 472, 539–542, 545
QNX Windows picture files, driver 539
importing 131 event clipping 474
event notification 538
asynchronous 539
polling 538
R synchronous 539
radio buttons 211 events 298
raw-event callback 196, 500 focus 544, 545
Readmsg() 357 hierarchy 475
realizing 12, 18, 20, 24, 106, 201, initial dimensions 470
203, 205–207, 210, 215, initial locations 470
256, 305, 519, 523, 524 keyboard events 540
delaying 524 location 537
realtime library 520 moving 473
realtime signals 359 notification of events 538
Receive() 351, 377 asynchronous 539
rectangle (draw primitive) 404 polling 538
rectangle, beveled (draw synchronous 539
primitive) 406 opacity 534–536
rectangle, rounded (draw opening 481
primitive) 405 origins 470–473
Red-Green-Blue (RGB) parent 474, 475, 536
representation 403 changing 482
region 3, 531, 533 placement 476, 481
active 545 changing 481

September 20, 2005 Index 611


Index  2005, QNX Software Systems

default 477 functions 182


specific 480 lists 176
raw events 197 numbers 178
root 469, 470, 473, 475, 476, pixmaps 164
482, 537, 540, 541, 545 text, multiline 180
defined 537 text, single line 179
sensitivity 534–536 getting 277–286
system information 483–486 argument list 269
window 545 manifests 90
window frame 482, 544, 545 modifying values 280
workspace 472, 544, 545 names 90
regions not displayed in PhAB 85
events 496 setting 271–277, 523
opacity 494 argument list 269
origin 496 types 270, 279
targeting events 493 RGB representation 403
renaming an application 97 root region 469, 470, 473, 475,
Repeat callback 183 476, 482, 537, 540, 541,
Reply() 350 545
resize event 218 defined 537
resize handle, changing color 91 rounded rectangle (draw
resize policy 202, 203 primitive) 405
resizing Run Language Editor (Application
dialog module 117 menu, Languages
icon module 128 submenu) 325
menu module 120
Other module 129
picture module 127
widgets 154, 155 S
window module 116
Resource mode 83 Save (File menu) 98
resources Save As (File menu) 97, 98
editing 163 saving an application 97, 98
colors 172 select mode 80, 143
editor buttons 163 selecting
flags 173 bounding-box method 145
fonts 175

612 Index September 20, 2005


 2005, QNX Software Systems Index

Control-Panel Startup Info/Modules (Application


method 144–146 menu) 99, 103–105, 229
extended selection method 146 startup windows 104–106
from Module Tree 144 static libraries 235, 520
modules 134 stem name 427
multiple widgets 145 submenu 122
point-and-click method 144 system information 483–486
Shift – click method 145, 146,
208
widgets 143–147
within a group 146 T
Send() 350, 364
Sendfd() 363 table-of-content (TOC) files 340,
setup function See module, setup 341
function taskbar 127, 237, 238, 248
shared libraries 235, 520 Test mode 111, 153
shared memory 417, 418 text
shortcut, keyboard 119, 122 draw primitive 411
shr make target 235 international characters 180,
sigaddset() 374 272, 557–563
sigemptyset() 374 multiline editor 180
sigevent 360 single-line editor 179
signals 373 threads 251
Photon’s signal handler 373 timers 383, 421
processing function 373 To Back (Edit menu) 78, 152
adding 373 To Front (Edit menu) 78, 152
prototype 374 Transfer (Edit menu) 78, 154
removing 375 true color 403
realtime (Neutrino) 359 typographical conventions xxvii
sin ver, replying to 358
single-platform development 232,
240
SMB and PhAB 97
U
speedbar 30, 78 Unicode 557–559
hiding 90 character values 559
Split Apart (Edit menu) 78, 213 Universal Resource Locator
src directory 232, 233 (URL) 341–343, 345

September 20, 2005 Index 613


Index  2005, QNX Software Systems

restriction on scope 342 to a parent widget 149


root 345, 346 to another widget 149
unrealizing 12, 20, 524 using groups 208
Usemsg 226 vertically 209, 320
UTF-8 558–561 anchoring 213–218
flags 215
bar 79
customizing 81
V border 13
canvas 13, 207
version control 227 class 9
view command, specifying 90 container See also PtGroup
View menu 77 absolute positioning 207
Clipboard 158 aligning children 149
Control Panel 82 anchoring 213, 215
viewing modules 114 defined 201
duplicating 159
flags 215
focus 150–152
W geometry management 201
wcstombs() 558 manipulating in PhAB 139
wctomb() 558 moving children between
wd 237, 238 containers 154
wgt directory 112, 232, 233 overview 139
wgtd extension 109, 116 PhAB modules 109
wgti extension 109, 127 picture modules 126, 303
wgtm extension 109, 117 positioning children 16, 147,
wgtp extension 109, 126 153, 202
wgtw extension 109, 115 Pt CB RESIZE 218
wgtx extension 109, 129 resize callback 218
wide characters 557, 559 resize flags 205, 206
conversion functions 557 resize policy 203
widget selecting children 139
absolute positioning 207 widget databases 308
aligning copying 156
horizontally 209, 319 creating 12, 142
in rows and columns 210 from code 289

614 Index September 20, 2005


 2005, QNX Software Systems Index

cutting 156 focus 150–152


damaging 8 focus callbacks 151
database 7, 23, 126, 251, 303, geometry 13, 523
308, 321 hierarchy 9
animation 419 images 417
creating 309 releasing 418
dynamic 310 instance 11
functions 311 instance name 83, 131, 140,
instance names 310 158, 159, 243
preattaching callbacks 310 generated by PhAB 141, 322
defined 8 language database 141, 322
deleting 159 starting with @ 141, 322
destroying 13, 20, 290 instantiating 12, 18, 20, 523
dragging 153 from code 289
duplicating 159 life cycle 12
editing resources 163 margins 13
colors 172 moving 153, 155
editor buttons 163 moving between
flags 173 containers 154
fonts 175 nudging 155
functions 182 ordering 152
lists 176 origin 15
numbers 178 parent
pixmaps 164 default 289
text, multiline 180 reparenting 289
text, single line 179 pasting 157
event position 16
handler 297 position or size constraints 218
extent 16 positioning with a grid 147
family printing 455
container-class widgets 139 by damaging 456
defined 10 PpPrintWidget() 456
functions dealing with 291 PtList 458
geometry negotiation 201 PtMultiText 458
PtCreateWidget() 289, 519, PtScrollArea 460
523 scrolling widgets 457
finding 147

September 20, 2005 Index 615


Index  2005, QNX Software Systems

realizing 12, 18, 20, 201, 203, window frame


205–207, 210, 290, 519, region 482, 544, 545
523, 524 Window Manager See PWM
delaying 524 Window menu 77
resize policy 202, 203 Arrange Icons 130, 134
resizing 154, 155 Arrange Modules 82, 134
resource 11 module names 134
manifests 90 work area 31, 130
names 90 work procedures 376, 377
selecting 143–147 adding 378
specifying coordinates 154 example 378
splitting groups 213 preemption 382
unrealizing 12, 20, 524 removing 378, 382
user data 273 workspace
widget bar 30 menu 545
widgets region 472, 544, 545
events wvideo 238
sending to 494
focus 290
ordering 290
window
blocking 383
closing, verifying 512
frame 545
manager 133, 188, 476, 482,
507–516, 522, 540, 542,
544–546
standalone application 516
taskbar 127, 237, 238, 248
workspace menu 545
manifest 245
module 115, 507
region 545
resizing 116
services 545
startup 104–106
unblocking 384

616 Index September 20, 2005

You might also like