photon_prog_guide
photon_prog_guide
Programmer’s Guide
Publishing history
November 1995 First edition
December 1996 Second edition
April 1998 Third edition
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
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
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
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
Exiting PhAB 92
Pasting 157
Viewing the clipboard 158
Editing the clipboard 158
Duplicating widgets and containers 159
Deleting widgets 159
Importing graphic files 159
Hotkeys 329
Help resources 329
Running your application 330
Distributing your application 332
18 Fonts 425
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
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
Glossary 565
Index 587
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 use an arrow (→) in directions for accessing menu items, like this:
!
CAUTION: Cautions tell you about commands or procedures that
may have unwanted or undesirable side effects.
- window management
¯ a glossary
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
Event space
Root region
Application region
When you run the application, you interact with it, and it interacts
with other applications and Photon, in many ways:
¯ 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).
A region that’s interested in the event can catch it and process it,
for example, activating a push button.
Each region can determine which events it’s interested in by setting its
sensitivity and opacity:
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.
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.
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
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.
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
Create
Realize
Unrealize
Destroy
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.
Margin
Border
☞ 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.
Origin of parent
x
Margin
y width
POS (x, y)
Border
Margin height
DIM
(height)
Margin height
DIM (width)
Border
Container widget
POS (x, y)
Origin of container
POS (x, y)
Child widget
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()
Non-PhAB application
A Photon application written without PhAB is similar to a text-mode
application, except that you also:
Main program
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()
PhAB application
When you develop a PhAB application, the main program is provided
for you. Instead of worrying about the main program, you:
¯ set up signal handlers, which process the signals as they arrive and
call signal-processing functions that you write
Initialization
function
Message
handler
Photon events functions
Graphics
driver Callbacks
exit()
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:
¯ Pm — memory functions
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:
¯ PhLibVersion() at runtime.
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.
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.
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
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.
Hello World
6 You’re almost ready to generate code! But first, you must save
the application and give it a name.
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.
100%
Messages
Generation Complete.
Done
4 Once the application has been compiled and linked, PhAB will
enable the dialog’s Done button. Click on Done to close the
dialog.
Hello World
¯ text fonts
¯ text strings
¯ flags
¯ colors
¯ pixmaps
4 Drag any of the button’s resize handles until the button matches
the following picture:
Button
Number Editor
Border Width
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.
3 To apply the new value and close the editor, press Enter or click
on Done.
1 Click on the “Font” resource. You’ll see the font editor, which
displays the button’s current font:
Font Editor
Font
Helvetica
AaBbCcXxYyZ z
This editor lets you change the text font of any widget that has
text.
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.
Flag/Option Editor
Horz Alignment
Pt_LEFT
Pt_RIGHT
Pt_CENTER
3 Click on Done.
Setting flags
Let’s now use the flag/option editor to set one of the widget’s flags:
Flag/Option Editor
Flags
Pt_SET
Pt_AUTOHIGHLIGHT
Pt_TOGGLE
Pt_SELECTABLE
Pt_SELECT_NOREDRAW
Pt_GHOST
Pt_HIGHLIGHTED
Pt_ETCH_HIGHLIGHT
A flags resource isn’t exclusive, so this time you can use the
editor to select multiple options, if desired.
Button
Color Editor
Transparent
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.
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.
☞ 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.
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.
¯ 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.
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.
Text String
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.
Mary
had
a
little
lamb.
☞
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
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.
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.
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:
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.
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:
File Help
base_file
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.
Quit
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.
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.
Single Line
Double Line
Etched - In
Etched - Out
Blank
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.
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.
Class : PtMenuButton
base_file
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.
6 Repeat the above steps to link the Help menu button to the Help
menu module.
4 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. 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.
2 From the Application menu, choose Build & Run and generate
the application code.
return( Pt CONTINUE );
}
5 After you’ve edited the code, saved your changes, and closed
the editor, click on Make to compile the code.
¯ 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.
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.
Name: aboutdlg
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.
5 Select the PtButton widget and change its button text resource
to Done. Then change its instance name to about done and
press Enter.
Done
4 Close the editor. The callback list now indicates that you’ve
added an Activate callback called Done:
Class : PtButton
about_done
2 Open the Build & Run dialog and generate the code.
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];
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.
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.
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.
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:
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.
Button
int
newwin setup( PtWidget t *link instance,
ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
PtArg t args[1];
char buffer[40];
return( Pt CONTINUE );
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:
int
color change( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
int i, prev;
PtArg t args[1];
return( Pt CONTINUE );
}
return( Pt CONTINUE );
int
newwin close( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
PhWindowEvent t *we = cbinfo->cbdata;
int i;
return( Pt CONTINUE );
In this chapter. . .
Menubar 77
Speedbar 78
Widget bar 79
Control Panel 82
Customizing your PhAB environment 89
Help 91
Exiting PhAB 92
Menubar
Across the top of PhAB’s workspace you’ll see the following
menubar:
PhAB’s menubar.
Speedbar
The speedbar gives you quick access to the Edit menu’s commands:
Cut Paste To Front Group Together Alignment Position
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.
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.
¯ select mode — lets you select existing widgets and modules in the
work area
¯ 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.
Done
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.
☞ 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
Instance name Lets you enter a unique instance name for the
widget.
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:
Class : PtWindow
base
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
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:
Class : PtButton
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
The left side of the list indicates the callback type. The right side
displays:
Class : PtWindow
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
Class : PtMenuButton
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
General
G e n e r a l Pr e f e r e n c e s
Colors
Speedbar: On Off
Dragging
Edit Command:
View Command:
Print Command:
Done
2 Click on the button that represents the kind of settings you wish
to change: General, Colors, or Dragging.
General preferences
You can set the following general preferences:
View Command
Lets you specify the file viewer to use with the Build &
Run dialog.
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:
Exiting PhAB
To exit PhAB, do one of the following:
¯ Press Ctrl – X.
In this chapter. . .
Creating an application 95
Opening an application 95
Saving an application 97
Closing an application 99
Specifying application startup information 99
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:
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:
Application Selector
Application Directory
//222/home/stever/phab
Application Name
background
Saving an application
You can save your application in several ways, as described in the
sections below.
1 Choose Save As from the File menu. You’ll see the application
selector dialog.
☞ 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.
Closing an application
To close an application, choose Close from the File menu.
¯ Press F2.
Init ializat ion Funct ion: No Pos Arg No Dim Arg No St at e Arg
Remov e
Done Cancel
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
☞ 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:
Command-line options
By default, all PhAB-generated applications have the following
command-line options:
-s server name
The name of the Photon server:
-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.
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
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:
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.
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.
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:
¯ it acts as the default parent window for all other windows and
dialogs
Remov e
3 Click on Apply.
3 Click on Apply.
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.
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
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:
¯ 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.
continued. . .
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.
¯ 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
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.
Module Selector
Module Ty pe:
Window s Dialogs Menus Pictures Icons Others
Name
base
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.
2 In the Name field, type the instance name of the new module,
then press Enter or click on Open.
4 Click on Done.
☞ ¯ If you choose the “Others” module type, PhAB asks you to select
the type of module you want.
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:
Opening a module
To display a module in your work area:
Deleting a module
To delete a module:
☞ 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
Dialog modules
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:
Menu modules
Callback: None
Actions
Apply
Reset
Remov e
Done Cancel
Menu editor.
¯ provide a hotkey that directly invokes the command that the item
represents, even when the menu isn’t visible
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
1 Click on <NEW>.
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.
Field Description
Item Text The text that will be displayed
1 Click on <NEW>.
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.
1 Click on <NEW>.
Separator Sty le
Single Line
Double Line
Etched - In
Etched - Out
Blank
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
Field Description
Function The function that will be called
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.
☞
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.
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.
Picture modules
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.
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.
Icon modules
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:
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.
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.
Other modules
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).
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:
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.
1 Choose Import Files from the File menu, then choose PhAB
Module from the Import Files submenu. You’ll see a file
selector.
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.
Closing a module
If you wish to stop working on a module and remove it from the work
area:
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.
+ Offset: X 0 Y 0
Done Cancel
Location dialog.
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.
4 Click on Done.
Selecting a module
To select a module that’s in the PhAB work area:
¯ 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.
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.
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
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:
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
You can optionally include the instance name in the widget’s memory.
See “Including instance names” in the Working with Applications
chapter.
¯ Leave the instance name equivalent to the class name (that is, leave
the default alone).
Or
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:
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.
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
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.
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:
A single widget
To select a single widget, you can:
Point-and-click method
To select a single widget using point and click:
Control-Panel methods
The Next and Previous buttons in the Control Panel let you select any
widget in the current module.
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:
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.
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.
☞ 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.
To remove the last widget from the current list of selected widgets:
2 Find the group in the tree and click on the widget’s name.
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.
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:
Grid Settings
Grid Origin
Horizontal: Pixels
Vertical: Pixels
Grid Frequency
Horizontal: Pixels
Vertical: Pixels
Snap to Grid
Done Cancel
4 Click on Done.
☞ Grid settings remain for the current session only. They aren’t saved.
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:
To a parent container
To align widgets to their parent container:
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
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
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.
Focus callbacks
All descendants of the PtBasic widget have the following callback
resources:
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):
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.
Dragging widgets
Dragging a widget is the easiest way to move a widget in most
situations since it’s quick and fairly accurate:
☞ ¯ Widgets will snap to the grid if the grid is enabled. See the
“Positioning with a grid” section in this chapter.
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.
3 Move the pointer into the other container and click the mouse
button.
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:
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:
☞ Whenever you cut or copy, PhAB removes any widgets already in the
clipboard.
Pasting
A paste operation copies widgets from the clipboard into a module.
To paste the contents of the clipboard:
¯ The instance names of the new widgets are reset to be the widget
class name.
Deleting widgets
To permanently remove one or more selected widgets without
copying them to the clipboard:
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.
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.
5 If you wish to edit the imported file, use the pixmap editor,
described in the Editing Resources and Callbacks in PhAB
chapter.
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
☞ 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.
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 163
Pixmap editor 2005, QNX Software Systems
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
The editor has several drawing modes and tools. The default is
freehand mode — you simply drag the pointer across the drawing
grid.
☞ 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:
continued. . .
166 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Pixmap editor
Drawing freehand
The freehand tool lets you draw freeform lines and erase single pixels
for quick fix-ups.
To draw in freehand mode:
➤ To erase the pixel under the pointer, click the right mouse
button.
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
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:
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:
168 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Pixmap editor
¯ PhAB introduces blank space into the pixmap to fill the space left
by the area you’ve nudged.
Copy Paste
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:
¯ 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):
☞ By using the flip tools with the copy tool, you can create mirror
images.
☞ 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
2 Point to the new location, then click. This click specifies the
top-left corner of the area’s new position.
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:
Color Editor
Transparent
R 254
G 128
B 1
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.
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
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.
174 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Font editor
Font editor
Whenever you select any font resource in the Control Panel you’ll see
the font editor:
Font Editor
Font
Helvetica
AaBbCcXxYyZ z
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.
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:
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
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.
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 177
Number editor 2005, QNX Software Systems
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
Number Editor.
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
Text Editor.
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 179
Multiline text editor 2005, QNX Software Systems
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.
180 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Multiline text editor
Button Text
Help
continued. . .
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 181
Function editor 2005, QNX Software Systems
☞ 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.
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
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:
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
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.
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.
2 Choose the callback type from the widget’s callback list. (For
example, to add an Pt CB ACTIVATE callback, click on
Activate.)
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 185
Editing callbacks 2005, QNX Software Systems
Sav e
Restore
Done Cancel
Callback Editor.
186 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Module callbacks
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.
Name: aboutdlg
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
188 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Code callbacks
☞ 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.
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
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
¯ You can use a modifier on its own as a hotkey, but it’s probably not
a good idea.
¯ 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.
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 191
Hotkey callbacks 2005, QNX Software Systems
¯ 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.
192 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Hotkey callbacks
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.
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.
¯ ...
¯ 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
September 20, 2005 Chapter 7 ¯ Editing Resources and Callbacks in PhAB 195
Raw-event callbacks 2005, QNX Software Systems
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.
196 Chapter 7 ¯ Editing Resources and Callbacks in PhAB September 20, 2005
2005, QNX Software Systems Raw-event callbacks
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
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:
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.
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.
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.
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.
These flags may also be modified by the values of another set of flags,
namely:
¯ Pt RESIZE X INITIAL
¯ Pt RESIZE Y INITIAL
¯ Pt RESIZE XY INITIAL
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.
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
¯ 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:
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.
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.
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.
One Another
Two
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.
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.
One Another
Two
One Another
Two
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.
PhAB will split apart the widgets and remove the PtGroup
container.
☞ 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.
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:
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
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);
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
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.
¯ edit code
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.
.. File Spec
default *
ntoold
Makefile
Refresh
abHfiles
abOfiles Create
abSfiles Edit
abdefine.h View
abevents.h
Delete
abimport.h
Print
ablinks.h
Build Preferences...
Done
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
☞ 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.
1 Click on the Generate button in the Build & Run dialog. Wait
for the progress meter to reach 100%.
The file list now shows all the generated code files.
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:
abHfiles
abOfiles
abSfiles External PhAB references in the Makefile
226 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
2005, QNX Software Systems Generating application code
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):
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
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.
#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
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
230 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
2005, QNX Software Systems How application files are organized
appl
src wgt
platforms
Multiplatform applications
Here’s what each directory contains if you generate your application
for the first time after installing Watcom 10.6 or later:
September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 231
How application files are organized 2005, QNX Software Systems
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.
!
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:
232 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
2005, QNX Software Systems Editing source
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:
September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 233
Editing source 2005, QNX Software Systems
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.
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,
234 Chapter 9 ¯ Generating, Compiling, & Running Code September 20, 2005
2005, QNX Software Systems Compiling & linking
¯ 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.
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 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.
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.
☞ 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
☞ When your application runs, its working directory is the one that’s
displayed in the Build & Run dialog.
¯ 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.
Debugging
PhAB lets you run your application with a debugger such as wd,
which can be handy if your application crashes or behaves incorrectly.
September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 237
Debugging 2005, QNX Software Systems
To switch between the debugger and the application, use the Window
Manager’s taskbar.
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
Multiplatform applications
PhAB generates empty lists in the following files in the src directory,
and you can edit them:
September 20, 2005 Chapter 9 ¯ Generating, Compiling, & Running Code 239
Including non-PhAB files in your application 2005, QNX Software Systems
¯ header files and source files are usually in the parent directory,
src, so their names start with ../
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.
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:
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
☞ 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.
☞ 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.
¯ 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.
int
mycallback( PtWidget t *widget, ... )
return( Pt CONTINUE );
}
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];
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.
search_win
name_txt
search_btn
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;
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;
return( Pt CONTINUE );
}
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.
#include <Pt.h>
#define GLOBAL
#define INIT(x) = x
#else
#endif
/* global variables */
GLOBAL int variable1 INIT(1);
If DEFINE GLOBALS isn’t defined, then the last line in the above
example looks like:
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 name
Create a C stub file called function name.c
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.
You can use C and C++ in the same PhAB application. See “What
PhAB generates” in the Generating, Compiling, & Running Code
chapter.
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>
/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"
int
init( int argc, char *argv[] )
{
char *device;
return( Pt CONTINUE );
-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.
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.
¯ 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.
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.
!
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.
return( Pt CONTINUE );
}
where:
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 )
return( Pt CONTINUE );
}
where:
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:
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.
AB ITEM DIM
to disable the item
AB ITEM NORMAL
to enable and unset the item
AB ITEM SET
to set a toggle item
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:
PtArg t args[2];
PtWidget t *new item;
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:
int
add shapes (PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo)
{
PtArg t args[2];
PtWidget t *new item;
Creating submenus
You can create submenus in the menu created for a menu function
item as follows:
/* 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 */
#include "abimport.h"
#include "proto.h"
int
ShapeMenuCB( PtWidget t *widget, void *client data,
PtCallbackInfo t *cbinfo )
{
int shape chosen = (int) client data;
int
add shapes( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
PtArg t args[3];
PtWidget t *menu, *new item;
menu = PtGetParentWidget();
PtSetParentWidget (menu);
return( Pt CONTINUE );
In this chapter. . .
Argument lists 269
Setting resources 271
Getting resources 277
¯ 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.
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:
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.
Setting resources
Remember that there are two steps involved in setting resource values:
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:
When you call PtSetResources(), the widget copies the scalar value
into its own internal data structure.
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:
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.
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:
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:
The widget copies the contents of the array into its own internal data
structure when you call PtSetResources().
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.
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:
When you call PtSetResources(), the widget copies the pointer into
the resource.
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.
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:
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().
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);
Getting resources
There are two steps involved in retrieving resource values:
¯ 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.
PtArg t arg;
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:
!
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];
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);
PtArg t arg;
const int *bool;
long mask;
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;
if ( bool ) {
// Arrows are on
}
Calling PtGetResources()
Use PtGetResources() to obtain the values of each of the resources
identified in an argument list:
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.
In this chapter. . .
Creating widgets 289
Ordering widgets 290
Manipulating callbacks in your code 292
Manipulating event handlers in your code 297
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 );
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:
¯ 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
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
PtWidgetBrotherBehind()
Get the brother behind a widget
PtWidgetBrotherInFront()
Get the brother in front of a widget
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
PtWidgetTreeTraverse()
Walk the widget family hierarchy from front to
back
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
{
PtWidget t *button;
int push button cb( PtWidget t *, void *,
PtCallbackInfo t *);
PtCallback t callbacks[] = { {push button cb, NULL} };
...
{
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
{
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);
}
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.
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;
Removing callbacks
You can remove one or more callbacks from a callback list associated
with a widget resource using the PtRemoveCallbacks() and
PtRemoveCallback() functions.
!
CAUTION: Don’t try to remove a callback that was added through
PhAB; unexpected behavior may result.
or this:
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).
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;
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().
!
CAUTION: Don’t remove event handlers that were added through
PhAB; unexpected behavior may result.
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:
¯ 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.
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.
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:
September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 303
Creating internal links 2005, QNX Software Systems
Actions
Apply
Reset
Remov e
Done Cancel
4 Fill in the fields in the Module Link Info section — see below.
304 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
2005, QNX Software Systems Using internal links in your code
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.
306 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
2005, QNX Software Systems Using internal links in your code
return( Pt CONTINUE );
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
308 Chapter 13 ¯ Accessing PhAB Modules from Code September 20, 2005
2005, QNX Software Systems Using widget databases
123456789012
Trash
ol
tag M en u
resource
or
name
Creating a database
To create a widget database:
September 20, 2005 Chapter 13 ¯ Accessing PhAB Modules from Code 309
Using widget databases 2005, QNX Software Systems
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.
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
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.
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.
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
3 The translated text strings are saved in a translation file, and are
shipped with your application.
¯ 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.
Done Cancel
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:
Name
Name
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.
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.
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:
Class : PtLabel
@label1
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
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.
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
/home/stever/phab/lang/lang.ldb
Translations
German
¯ /qnx4/phtk/appbuilder/phablang
¯ /qnx4/phtk/appbuilder/languages.def
Add Cancel
The Language Selection dialog closes, and you should now see the
newly created translation file in the list of available translations.
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
☞
¯ 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:
Repeat the above steps for all the text strings you need to translate.
When you’re finished, click on the Save & Close button.
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.
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.
Language: Value:
Belgian French fr BE
Canadian English en CA
Canadian French fr CA
continued. . .
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
☞ The application looks for the best match. For example, if the language
extension specified is fr CA, the search is as follows:
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.
The language database and the translation files that the customer
creates should be in:
In this chapter. . .
Creating help text 337
Referring to help topics 341
Connecting help to widgets 343
Accessing help from your code 345
¯ 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):
continued. . .
continued. . .
continued. . .
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/
1|Photon microGUI|./photon/bookset.html
where:
| delimits fields
Photon microGUI
is a topic title
./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/
/usr/help/product/photon/run inst/pdm.html
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.
1 Put the text you want displayed in the balloon into the widget’s
Help Topic (Pt ARG HELP TOPIC) resource.
When the user clicks on the ? icon, and selects the widget, the help
information appears in a balloon.
¯ 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:
int
help cb( PtWidget t *widget, ApInfo t *apinfo, PtCallbackInfo t *cbinfo )
{
PhWindowEvent t winev;
return( Pt CONTINUE );
}
PxHelpUrlRoot()
Set a URL root.
PxHelpTopicRoot()
Set a topic root.
PxHelpTopicTree()
Display help for the topic tree.
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
¯ messages
¯ proxies (QNX)
¯ pulses (Neutrino)
¯ signals
¯ interrupts
¯ process signals
/* 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;
return( Pt CONTINUE );
PtInputId t *PtAppAddInput(
PtAppContext t app context,
pid t pid,
PtInputCallbackProc t input func,
void *data );
data A pointer to any extra data you want to pass to the input
handler.
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:
¯ 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.
status = errno;
Reply(pid, &status, sizeof(status));
return 0; /* bail out */
}
log = &header;
}
return Pt CONTINUE;
}
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);
PtRealizeWidget(window);
PtMainLoop();
}
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.
#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().
*/
/*
* And now to handle the version request message from sin ver ...
*/
int
input function(void *data, pid t rcvid, void *msg, size t size)
{
message t *vmsg = (message t *) msg;
reply t reply;
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.
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.
3 Send the pulse message to the process that will deliver it.
☞ Before exiting, the recipient process should tell the delivering process
to stop sending pulses.
Creating a pulse
To create a Photon pulse, call PtAppCreatePulse():
priority The priority of the pulse. If this is -1, the priority of the
calling program is used.
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 ID of the process that will deliver the pulse if the process is on
the same node as the pulse recipient
or
Or
// Create your own message format:
msg.pulsemsg = pulsemsg;
Sendfd (fd, &msg, &rmsg,
sizeof (msg), sizeof (rmsg));
Or
char buf[15];
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 );
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 );
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:
// Message types:
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"
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);
int
init app( int argc, char *argv[] )
MyMsg smsg;
/* 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 */
#include "globals.h"
#include "abimport.h"
#include "proto.h"
int
quit callback( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
{
MyMsg smsg;
Save the rcvid from the message that contains the pulse message —
you’ll need it to deliver the pulse.
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"
#include "proto.h"
int
init app( int argc, char *argv[] )
return( Pt CONTINUE );
}
int
send pulse( PtWidget t *widget, ApInfo t *apinfo,
PtCallbackInfo t *cbinfo )
return( Pt CONTINUE );
}
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
!
CAUTION: By handling signals in this way, you’re not getting strict
realtime performance, since your signal-processing function isn’t
called right away.
!
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.
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
¯ 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.
#include <Pt.h>
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;
nargs = 0;
PtSetArg(&arg[nargs], Pt ARG TEXT STRING, "Stop", 0);
nargs++;
dialog->ok button = PtCreateWidget(PtButton, group,
1, arg);
}
return dialog;
}
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);
}
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);
}
w = w; call = call;
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);
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);
}
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.
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.
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:
call = call;
if (!closure->done) {
PtAppRemoveWorkProc(NULL, closure->work id);
}
PtDestroyWidget(closure->dialog->widget);
free(closure->dialog);
Here’s a little routine that we’ll use to block or unblock the windows
in the application:
{
PtWidget t *widget;
PtArg t args;
w = w; call = call;
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;
count = PtModalStart();
while( !closure->destroyed) {
PtProcessEvent();
}
PtModalEnd( count );
free (closure);
}
}
return (Pt CONTINUE);
}
#include <Pt.h>
PtWidget t *label;
PtWidget t *ok button;
} 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;
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);
nargs = 0;
PtSetArg(&arg[nargs], Pt ARG TEXT STRING, "Stop", 0);
nargs++;
dialog->ok button = PtCreateWidget(PtButton, group,
1, arg);
}
return dialog;
}
call = call;
if (!closure->done) {
PtAppRemoveWorkProc(NULL, closure->work id);
}
PtDestroyWidget(closure->dialog->widget);
free(closure->dialog);
int
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);
}
w = w; call = call;
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;
count = PtModalStart();
while( !closure->destroyed) {
PtProcessEvent();
}
PtModalEnd( count );
free (closure);
}
}
return (Pt CONTINUE);
}
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);
}
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
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:
☞ 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:
To create a PtRaw widget in PhAB, click on its icon in the widget bar:
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.
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.
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 };
PgSetFillColor(Pg YELLOW);
PgDrawEllipse ( &c1, &r, Pg DRAW FILL );
☞ 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. */
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:
¯ 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.
PtClipRemove ();
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) {
damage = damage->next;
}
.
.
.
damage = damage->next; // Go on the the next tile.
}
}
PtClipRemove ();
}
PgSetFillColor(Pg YELLOW);
PgDrawEllipse ( &c1, &r, Pg DRAW FILL );
PgSetFillColor(Pg RED);
PgDrawEllipse ( &c2, &r, Pg DRAW FILL );
PtClipRemove ();
}
Color
Colors are specified in Photon with the PgColor t type, a 32-bit
Red-Green-Blue (RGB) representation:
¯ arcs
¯ ellipses
¯ polygons
¯ rectangles
¯ rounded rectangles
¯ Create a PtRaw widget and call the primitives in its draw function.
See the section on the PtRaw widget earlier in this chapter.
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 );
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:
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
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:
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:
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:
¯ When you cross an odd number of lines, you’re inside the polygon,
so the area is filled.
¯ 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:
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 );
}
PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgSetFillColor( Pg BLUE );
PgDrawText( s, strlen( s ), &p, Pg BACK FILL );
}
PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgSetUnderline( Pg RED, Pg TRANSPARENT, 0 );
PgDrawText( s, strlen( s ), &p, 0 );
PgSetUnderline( Pg TRANSPARENT, Pg TRANSPARENT, 0 );
}
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 )
{
PhPoint t p = { 8, 8 };
PgSetTextColor( Pg WHITE );
PgDrawBitmap( TestBitmap, 0, &p, &TestBitmapSize,
TestBitmapBPL, 0 );
}
PgSetFont( "helv18" );
PgSetTextColor( Pg WHITE );
PgSetFillColor( Pg BLUE );
PgDrawBitmap( TestBitmap, Pg BACK FILL, &p,
&TestBitmapSize, TestBitmapBPL, 0 );
}
Images
Photon supports these main types of images:
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;
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:
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.
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:
Displaying images
There are various ways to display an image:
If you do this, the image data isn’t copied to the graphics driver.
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.
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.
/* 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];
☞ 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.
☞ 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:
#include <PxImage.h>
/* 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 */
#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];
cur image++;
if (cur image >= num images)
{
cur image=0;
}
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:
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.
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
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
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:
In this chapter. . .
Font names 427
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:
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.
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:
list[] An array that the Photon Font Manager fills in for you.
You need to declare a FontDetails structure, which is
described below.
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.
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.
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:
int
fcnAppInit( int argc, char *argv[] )
{
/* Local variables */
FontDetails tsFontList [nFONTLIST SIZE];
short sCurrFont = 0;
char caBuff[20];
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 */
}
/* 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);
}
if (GcaCharter14Bold[0] == ’\x0’)
{
printf ("Charter font stem name was blank.\n");
return (Pt CONTINUE);
}
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 ***
***************************/
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 )
PtAskQuestion
(ABW base, "Font Demonstration",
"This sentence is in 14-pt. Charter bold",
GcaCharter14Bold, "OK", NULL, NULL, 1);
return( Pt CONTINUE );
}
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
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 LOCATION
The location of the printer (e.g. By board room
#2).
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.
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:
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).
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.
¯ half toning
Pp PC ORIENTATION
Portrait or landscape
¯ 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.
ulong t changed[4]
Indicates which portions of the context have been
modified. There are 32 modifiable attributes of a print
ulong t emitted
Indicates which of the changed print context attributes
have already been written to the destination or temporary
file. For example:
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.
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.
PpPrintContext t *pc;
pc = PpPrintCreatePC();
!
CAUTION: Never access the fields in a print context directly; use
PpPrintGetPC() and PpPrintSetPC().
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
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 |
¯ 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
}
A PtPrintSel widget.
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.
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:
...
// Set the name of the printer if you’re using method 2.
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
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>
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:
Once the source size and offset have been set, you can start printing:
PpPrintOpen(pc);
PpPrintStart(pc);
☞ 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.
Widget B redraws itself, and the draw commands are redirected to the
destination in the print context.
In addition to the print context and the widget, you can specify:
PpPrintNewPage(pc);
Any changes to the print context (such as the orientation) will go into
effect for the new page.
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.
2 Get the current resize flags (Pt ARG RESIZE FLAGS) for the
PtList widget.
5 Call PtFlush().
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:
6 Call PtFlush().
{
int action;
PhDim t size = { 850, 1100 };
long *num lines;
short *num lines visible;
long vis lines;
PtArg t args[2];
PpPrintStart(pc);
PtDamageWidget(ABW multi);
PtFlush();
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:
2 Get the area (Pt ARG AREA) of the virtual canvas, and use its
size member as the source size in the print context.
☞
You can’t print a scrollarea’s virtual canvas by damaging it; you must
use PpPrintWidget().
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);
☞ You can reuse the print context for new print jobs, eliminating the
need to create and initialize it again.
PpPrintStart(pc1);
// Print widget 1...
PpPrintStop(pc1);
PpPrintStart(pc2);
// Print widget 2...
PpPrintStop(pc2);
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>
PtRealizeWidget(window);
PtMainLoop();
return (EXIT SUCCESS);
}
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
Upper-left Upper-right
quadrant quadrant
(0, 0)
VGA
display
(640, 480)
Lower-left Lower-right
quadrant 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).
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.
Root region
Child's origin
(0, 0)
(100, 100)
Parent's origin
Root region
Child's origin
(-50, -50)
(50, 50)
Parent's origin
Root region
Child's origin
(0, 0)
Parent's origin
¯ 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
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
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
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.
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
Root region
Parent region
Child region 1
Child region 2
Root region
Parent region
Child region 1
(forced to front)
Root region
Parent region
Child region 2
Child region 1
(forced to front)
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.
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.
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:
¯ setting the parent, bro front, and bro behind members of the
PhRegion t structure
Specifying brothers
System information
You can get the following information about your system:
☞ 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).
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 valid fields field is a set of flags that indicates which of the other
fields are valid. The flags include:
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
In this chapter. . .
Pointer events 489
Emitting events 491
Event coordinates 496
Collecting events 496
Event compression 496
Dragging 496
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:
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
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>
#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 )
}
return( Pt CONTINUE );
}
Emitting events
The most general way for your application to emit an event is to call
PhEventEmit():
PhRect t *rects,
void *data );
0 Successful completion.
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.
Inclusive event
For an inclusive event, do the following:
Direct event
For a direct event, do the following:
¯ The widget still has focus — there might be other events enqueued
before yours.
¯ 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;
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.
opaque dragging
The application moves the widget as the dragging progresses.
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:
rid The region that rect and boundary are relative to.
You can get this by calling PtWidgetRid().
cbinfo->event->input group
¯ Ph TRACK LEFT
¯ Ph TRACK RIGHT
¯ Ph TRACK TOP
¯ Ph TRACK BOTTOM
Outline dragging
The following example shows an Arm (Pt CB ARM) callback that
initiates outline dragging:
/* 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 */
#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];
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():
☞ 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.
Ph EV DRAG START
the user has started to drag
Ph EV DRAG MOVE
the dragging is in progress (opaque dragging only)
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.
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 */
#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;
return( Pt CONTINUE );
Opaque dragging
The callback for opaque dragging is similar to that for outline
dragging — the only difference is the subtype of event handled:
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
Window-management flags
The PtWindow widget defines various types of flags:
☞ 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.
continued. . .
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).
{
PhWindowEvent t *we = cbinfo->cbdata;
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 );
continued. . .
PtForwardWindowEvent()
Change the state for your application’s windows.
PtForwardWindowTaskEvent()
Change the state for another application’s windows.
PhWindowEvent t event;
PhWindowEvent t 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.
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
PhWindowOpen()
Create a window region
PhWindowQueryVisible()
Query a visible extent
PtConsoleSwitch()
Switch to another virtual console
PtForwardWindowEvent()
Forward a window event
PtForwardWindowTaskEvent()
Forward a window event to a task
PtWindowConsoleSwitch()
Switch to the console a given window’s displayed
on
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
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().
-lphoton s
To link against the static library, specify the following link option:
-lphoton
☞ You’ll also need to link against the math library, libm.so or libm.a.
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>
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:
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
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:
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.
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.
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.
PtArg t args[3];
PtWidget t *window;
int push button cb( PtWidget t *, void *,
PtCallbackInfo t *);
PtCallback t callbacks[] = {{push button cb, NULL}};
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 );
return( Pt CONTINUE );
}
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
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
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
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.
Region
C Tile Tile Tile
Region 1 2 3
D
Tile
4
Region
A
Region
B Event received by
Region D
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.
☞ 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.
Root
Workspace (PWM)
Application
or Window
Focus (PWM)
Device
Input Group
Pointer/Keyboard
Graphics
¯ sensitivity
¯ opacity
You can set these independently for each different type of event.
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.
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.
Upper-left Upper-right
quadrant quadrant
(0, 0)
VGA
display
(640, 480)
Lower-left Lower-right
quadrant quadrant
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.
Event types
Events are emitted for the following reasons:
¯ boundary crossings
¯ drag operations
¯ drawing functions
¯ 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.
☞ 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
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.
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.
¯ 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.
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.
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.
¯ a focus region
¯ a workspace region
¯ a backdrop region
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
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.
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.
PtArc Arc
PtButton Pushbutton
PtCalendar Calendar
Pt Calenda
Pt Clock
PtClock Analog, digital, or LED
clock
continued. . .
t DBCont ain
PtDBContainer Double Buffer container,
useful for drawing
flicker-free images and
animations
PtEllipse Ellipse
PtGrid Grid
continued. . .
continued. . .
PtRect Rectangle
N/A PtRegion Photon region — must be
created with
PtCreateWidget()
continued. . .
PtScrollBar Scrollbar
Pt Tab
PtTab Tab button
PtTimer Timer
continued. . .
In this appendix. . .
Wide and multibyte characters 557
Unicode 559
UTF-8 encoding 559
Other encodings 561
Keyboard drivers 562
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.
Unicode
Unicode is a 16-bit encoding scheme defined in the ISO/IEC 10646
standard:
¯ Codes between 128 and 255 define the same characters as in the
ISO 8859-1 character set.
Glyphs Range
Nondisplayable keys 0xF000 – 0xF0FF
Cursor font 0xE900 – 0xE9FF
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:
¯ 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:
¯ 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)
PxTranslateFromUTF()
Translate characters from UTF-8
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).
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.
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
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.
color depth
The number of bits per pixel for a screen or pixmap.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
mouse driver
A program that gets information from the pointer hardware, builds
Photon raw pointer events, and emits them towards the root region.
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.
PhinX
Photon in X. An application that accesses Photon from an X Window
System environment.
Photon Terminal
An application (pterm) that emulates a character-mode terminal in a
Photon window.
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.
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.
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.
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.
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.
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 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.
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.
! 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
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