Previous Next Contents Generated Index Doc Set Home


CHAPTER 6

Activating the Interface: Adding Your Own Code





Introduction

The aim of Sun WorkShop Visual is to let you develop as much of your application as possible without writing code. You still need to write code, however, to make your application work as you intend and to link it to the user interface. You must also write code to control the behavior of the user interface. The following Sun WorkShop Visual features make some of this easier:

Callbacks. You can name a callback function or method for individual widgets and generate a skeletal procedure for it.
Links. Some commonly used callback events are known to Sun WorkShop Visual, enabling you to add them graphically and immediately view the effect.
Drag and Drop. You can set up a widget to receive data via the Motif drag and drop mechanism.
Translations and Actions. You can change the way individual widgets respond to events.
Xt Procedures. Sun WorkShop Visual provides a quick and easy means of adding Xt Work, Input, Timeout, Action and Language procedures and Event handlers to your design.
This chapter uses the tutorial example built in the preceding chapters to demonstrate how to add a callback and how to add links to your design. The above topics are also examined separately in some detail.


Callbacks

A callback list is a list of one or more callback functions designated to be triggered by user actions in your application. User actions include mouse button presses, keyboard selections and movements of the pointer. By setting up a callback, you can instruct your interface to call the functions on the callback list whenever a certain user action occurs within a widget. The callbacks dialog is shown in Figure 6-1.

FIGURE  6-1 Callbacks dialog

An "M" or "C" displayed to the right of a callback indicates that a method or callback respectively has been declared.

Callbacks which apply to Java code are listed with the letter `J' after them, as shown in Figure 6-1. Callback functions are not generated into the Java code, so you should use callback methods if you wish to use them in your Java application. For more information on using Sun WorkShop Visual to generate Java code, see Chapter 10, "Designing For Java".

An asterisk (*) next to a callback indicates that the callback is not supported by Microsoft Windows.

The area in the lower left of the Callbacks dialog allows you to set up a Smart Code callback. These are callbacks which give you toolkit independence by "wrapping" specified widgets in an extra layer of code. Smart Code is most useful when you are creating a thick client, or a thin client and server, from your design. See Chapter 16, "Get/Set Smart Code", starting on page 487 for more information on Smart Code. For this tutorial, you will not be using Smart Code. However, there are a number of tutorials which do use Smart Code in later chapters.


Designating a Callback

In the following steps you will designate the simplest example of a callback by using the design from the tutorial of the preceding chapters. Clicking on the "Exit" button (exit_button) will trigger a callback list with just one function, quit(), which terminates the program.

The "Callbacks" dialog lets you associate lists of functions with user actions. You can associate quit() with exit_button now, even though quit() has not yet been written.

quit() and other callback routines are written in C or C++ and linked in with the code generated by Sun WorkShop Visual. You will write your quit() routine in "Adding Callback Functionality" on page 232. The topic of writing callbacks is discussed in greater depth in "Callback Functions" on page 184.

  1. Open your saved tutorial design.
  2. Click on the "Exit" button (exit_button).
  3. Click on the "Callbacks" toolbar button or select "Callbacks" from the Widget menu.
You are going to associate quit() with the "Activate" callback. Activating means that the user presses and then releases a mouse button while the pointer is located inside the widget. The user can also activate with the <Return> key, or other keys as described in the Motif User Guide.

When a callback in the "Callbacks" dialog is selected, the list of callback functions you have associated with it are displayed. To add an Activate callback:

  4. Click on "Activate" in the list of Callback types.
This displays, in the list of callback routines, both those callbacks local to the widget and those inherited by it. Inherited callbacks are explained in "Inherited Callbacks" on page 180.

You may only change callbacks which have not been inherited. Figure 6-2 shows two typical examples. Example A of the figure shows the callback list for the "Exit" button in the tutorial interface; Example B shows a slightly more complex list.

FIGURE  6-2 Callback Text box and Two Examples of Syntax


Inherited Callbacks

Widgets which are instances of definitions can inherit callbacks from the corresponding widget in the definition.

Inherited callbacks are shown enclosed in square brackets ([]), as shown in Figure 6-3.

FIGURE  6-3 Inherited Callbacks


Callback Syntax

In general, the syntax for each function call in the callback list is the same as C syntax. You do not, however, type them in as C code. Function brackets () are not required as these are added automatically.


Note - If you add function brackets or parameters to the name of the callback function or method these will be treated as part of the name - they will not be recognized as syntactically separate.
When we specify the name of the callback, we must also choose which language we are using.

  1. If it is not already selected, choose "Function name" from the option menu.
  You should choose "Function name" if you are using the C language (as we are in the tutorial) or "Method name" if you are using C++.
  2. Click in the "Function name" text box.
  3. Type: quit
  4. Click on "Add".
  Pressing Return has the same effect.
  5. Close the dialog.
  6. Save your design.

Order of Execution

While the callback list looks like C code, it has no logical flow. This means that you can neither use C's logical operators such as if...else and while, nor can you rely on your callbacks being executed in any particular order. All routines in your list will be executed whenever the specified event occurs but not necessarily in the order you type them. If the execution sequence is important, you can write a single callback function which contains subroutine calls in the order you want.


Client Data

The "Client Data" text box allows you to specify data to be passed in to the callback. It is better practice to use this mechanism when a callback needs to use some data than to use a global variable. Enter the string you wish to appear as the parameter here. You may also add a type cast in the usual C/C++ syntax. You do not, however, need to type the function parameter brackets () as these will be added for you automatically. See "Callback Function Parameters" on page 185 for more details about the parameters passed to callback functions and an example.


Note - You can only add client data to function callbacks, not to method callbacks. See "Callback Methods" on page 264 for more details about this.

Methods

If the selected widget is enclosed in a C++ class and "Method name:" is selected from the pulldown menu to the left of the name text field, a "Methods..." button is shown to the right of the name text box. With "Function name:" selected, this button is not shown. When pressed, the "Methods..." button displays a list of callback methods already defined for the selected widget's enclosing class.

Selecting one of these and pressing "OK" will place the selected item in the "Method name" text field. See "C++ Classes" on page 260 for details about the way in which widgets are enclosed in classes.


Edit Code

Pressing this button allows you to edit your stubs file (the generated file containing the specified callbacks) without leaving Sun WorkShop Visual. This is dealt with in more detail in "Adding Callback Functionality" on page 232. See also "Setting up Callback and Prelude Editing" on page 706 for details on how to set up the editing feature so that you can use the editor of your choice.


Flavor Option Menu

The option menu next to the "Edit Code" button contains the possible code generation "flavors". The options are:

Motif C
Motif CPP
Motif XP
Microsoft Windows MFC

Note - The last two options are only shown in Microsoft Windows mode. See "The Flavor Menu" on page 366 for information on these.
The Flavor Option Menu works in conjunction with the "Edit Code" button. When you edit your stubs file, you must specify which language you are using. Sun WorkShop Visual will try to work this out for you and set the menu accordingly when you invoke the dialog. Sometimes this is not possible if, for example, you are working with two languages in the same design. You should, therefore, always check that the appropriate option is chosen from this menu.


Update

Use the "Update" button to change the settings of an existing callback.

If you wish to change a non-Smart Code callback to a Smart Code callback you can only do so if the callback is used in just one place. This is because the same callback cannot be both at the same time. If you select a non-Smart Code callback that is being used elsewhere, the Smart Code toggle remains insensitive.

If an existing callback has been changed into a Smart Code callback and you have already generated a stubs file, you should go to the file and remove or rename the non-Smart Code callback stub so that Sun WorkShop Visual will generate the new Smart Code for you


Clear Settings

Using the "Clear Settings" button is most useful if you have one or more Smart Code callbacks and you wish to add a new callback routine without accidentally picking up the Smart Code settings of the previously selected callback. "Clear Settings" deselects all callbacks and any other non-default settings.


Remove

The "Remove" button removes the currently selected callback. Be careful when using this button as the operation cannot be undone.

The tutorial example continues in "Links" on page 189. The chapter now continues with a more thorough explanation of callbacks and how they may be used.


Callback Functions

"Creation Procedures" on page 238 describes how Sun WorkShop Visual creates the widgets in your application and sets their initial resource values. However, it is the callback functions and translations that make the application work. See "Translations and Actions" on page 196 for more information on translations.

Most callback functions have a similar structure. A typical callback function does some or all of the following:

Extracts information from widgets, such as the text in a Text widget or the state of a ToggleButton
Uses this information as parameters for calls to application functions
Uses the results of these functions to change widget attributes. These attributes include not only values (such as the text in a Text widget) but also sensitivity (responsiveness to user input), visibility and even existence

Callback Function Parameters

A callback function receives three parameters:

The widget from which the callback was invoked
The call data
The client data
The call data is a pointer to a data structure defined by the widget developer. Call data structures are described in your Motif documentation or documentation supplied by the developer of the widget toolkit. See "Books on X and Motif" on page 890 for details of some useful Motif documentation.

The client data is a pointer that you can use to pass the address of any variable or structure. When you register a callback, you can specify the value for the client data parameter that is passed to the callback function.

In Sun WorkShop Visual, the client data is specified in the callback dialog as a single optional parameter of the callback function. See "Client Data" on page 182 for details on how to do this. This could be a pointer to a structure, which can be defined and initialized in a suitable prelude. For example, a typical prelude might be:

/* Pre-manage prelude for main dialog Shell */
/* Define and initialize client data for the rungrep callback */
static rcdata_t rcdata = {
	&hitstring,
	&errorshell,
	&errorform,
	&errortext,
	&mainshell
};
/* End of Shell pre-manage prelude */
The callback is specified as:

rungrep((XtPointer)&rcdata)
To enter this in the Callbacks dialog, the function name rungrep is typed into the text field labelled "Function name" and the parameter, including the cast, is typed into the "Client data" text field: (XtPointer)&rcdata.

The declaration of the structure rcdata_t would normally be in a header file that would be included in the generated code (by adding "#include ..." as the module prelude) and in the callback function module. The callback function can then cast the client data to (rcdata_t *) and so access the data.

Note that the structure rcdata is defined to contain pointers to the widget variables, rather than the values of the variables themselves. This lets rcdata be initialized before the widgets are created. You can also define a structure into which the values of the widget variables are copied. However, this cannot be initialized until all the widgets have been created, which can be tricky.


Callbacks in C++

Ideally it would be desirable to add class member functions to widgets as callback functions. Unfortunately this is not possible because callback functions are called by a C library and they cannot provide the instance context (the this pointer) required by a class member function. Sun WorkShop Visual provides an automatic way of calling a class member function from a callback. These are called callback methods and are discussed in "Callback Methods" on page 264.


Accessing Widgets in Callbacks

All callbacks are passed the address of the widget to which they belong. This is a variable of type Widget. In the Sun WorkShop Visual generated code, the variable name of the widget is used for the name of this pointer. If you want a callback function to access widgets in your design other than the widget to which the callback belongs, you have the following choices:


Client Data Structure

Pass the other widgets as part of the client data structure. See "Callback Function Parameters" on page 185 for a description of this structure.


Global Widget Variables

The simplest technique is to have Sun WorkShop Visual define the widget variables as global. You can then access them from a callback function by declaring them as extern in the callback function module. You could include Sun WorkShop Visual's generated "Externs" file in the stubs file in order to do this.

Sun WorkShop Visual declares named widgets as global by default. You can change this behavior by setting the Storage Class of the widget in the Core resource panel.

The strength of the global variable approach is its simplicity. However, having many global variables does nothing for the structure of your program and you must pay attention to naming conventions to ensure meaningful names and avoid duplicates.


Inclusion of Generated Code

You can reduce the need for global variables by including the primary module in the callback function module, using #include. The primary module should be generated without includes of the X and Motif header files.

If you do this, Sun WorkShop Visual still declares named widgets as global. You may want to change their storage class to static, which makes them local to the callback function module.

This technique works well where a callback function needs access to widgets that are all or mostly within a single design. In more complex situations, you can add accessor functions to the callback function module. A callback function that needs to manipulate a widget which is local to another callback module can do so via the accessor functions.

You can also access widgets using the X toolkit convenience function XtNameToWidget(). Pass the widget name to this function and a pointer to the widget is returned. See your X toolkit documentation for more information.


Manipulating Widgets

"Accessing Widgets in Callbacks" on page 186 gives you some ways to access the widgets in your design. Once you have a widget, there are many ways you can manipulate it. This section outlines a few of them. It is not a detailed description, but is only intended to point you to the appropriate functions and their documentation.


Toolkit Convenience Functions

The Motif toolkit provides a large number of convenience functions for getting and setting attributes of some widgets. These are all named after the widget class that they affect, such as XmTextSetString(), XmTextGetString(), XmToggleButtonGetState(). These are documented in the Motif Programmer's Reference.

Convenience functions are the first place to look. They are the easiest to use and are likely to be efficient.

One point to note is that convenience functions take a Widget parameter and expect this to be a pointer to a widget of the appropriate class. If the widget is of the wrong class, they commonly core dump. There are also both widget and gadget versions of some of the convenience functions and you may get a core dump if you use the wrong one.


Setting and Getting Resources

If there is no convenience function, you may have to get or set one or more of the resources of the widget directly using XtGetValues() or XtSetValues(). This is fundamental to widget programming and any book on Xt or Motif should cover it adequately.

Not all resources can be set after a widget has been created. The Motif Programmer's Reference documents the access controls on each resource of every widget class.


Enabling and Disabling Widgets

To disable a widget (that is, to make it insensitive to user input), or enable it again, use XtSetSensitive(). You should not set the resource XmNsensitive directly.

When a widget becomes insensitive, so too do all its descendants. Insensitive widgets are usually grayed out.

If you make a Text or TextField widget insensitive, the user cannot use key input to pan and scroll the text and so has only a limited view. It may be better to set the resource XmNeditable to False.


Showing and Hiding Widgets

There are two ways to make a widget appear or disappear: managing and mapping.

If a widget is unmanaged, its parent does not reserve any space for it and it is not visible on the screen. A widget is unmanaged using XtUnmanageChild() or XtUnmanageChildren() and managed using XtManageChild() or XtManageChildren(). Sun WorkShop Visual generates code to manage widgets after they have been created, but the Managed toggle in the Core resource panel changes this.

If a widget is managed but not mapped, its parent reserves space for it. However, it is still not visible; there is a blank hole. Widgets are normally mapped automatically when they become managed. This is controlled by the resource XmNmappedWhenManaged which can be found on the "Settings" page of the Core Resource panel.

Mapping and unmapping is commonly used to change the visibility of widgets within a dialog without causing its layout to change. Managing and unmanaging cause layout changes.

You can make a complete dialog appear or disappear by managing or unmanaging the child of the Dialog Shell. If the dialog uses a Top level Shell, use XtPopup() and XtPopdown() on the Shell instead.


Note - "Links" on page 189 describes an automatic and dynamic means of showing and hiding widgets using Sun WorkShop Visual`s built-in links facility.

Creating and Destroying Widgets

Sun WorkShop Visual generates code to create the widgets for your dialogs. The default main() program calls all the creation functions at start-up time. Since widget creation is relatively expensive, this may cause an unacceptable delay. It is common practice to defer creation of a dialog until the first time it is popped up. A static Boolean flag in the callback function that performs the popup can be used to determine if the dialog has already been created.

As well as generating code to create complete dialogs, Sun WorkShop Visual can generate creation functions for dialog fragments, as described in "Children Only Place Holders" on page 271. You can call these from a callback function, so as, for example, to create another instance of some reusable component.

To destroy a widget (and all its children), use XtDestroyWidget(). It is inefficient to destroy a widget and then recreate it; you should unmanage it, then manage it again when it is needed.


Links

Sun WorkShop Visual has predefined callback procedures called links. There are six links available:

Show - makes a widget and its children appear on the screen
Hide - makes a widget disappear. The widget is not destroyed, just hidden
Manage - manages a widget which has already been created
Unmanage - unmanages a widget
Enable - enables a button or command
Disable - disables (grays out) a button or command

Distinction between Links and Callbacks

Only PushButtons, ArrowButtons and CascadeButtons can be the source of a link. All links are triggered by an "Activate" event. A link can show, hide, manage, unmanage, enable, or disable any widget in the design. One button can have multiple links.

Links are callbacks which Sun WorkShop Visual sets up for you. Unlike callbacks, however, links work in the dynamic display and can therefore be used for prototyping window behavior. When you generate code, you can either include links, which work exactly as they do in the dynamic display, or substitute more complex callbacks for the simple links.


Restrictions on Adding Links

Links can only be added if at least one of the following criteria is met. If none are met, the "Add" button is disabled and no links can be made. The requirements are:

The target widget of a link - that is, the widget to be shown, hidden, managed, unmanaged, enabled, or disabled - must have an explicit variable name. The source widget does not have to be explicitly named.
If the target widget is a Shell, its immediate child must also be explicitly named.
The widgets on either end of a link must not be designated as static or local variables. See "Changing Declaration Scope" on page 272 for a discussion of static and local widget variables.
The target widget must not be declared "children only". See "Children Only Place Holders" on page 271 if you are not sure what this means.
If the target widget is part of an instance of a definition, the root widget of the instance must also be named. See "Instances" on page 279 for more information on instances.
If the target widget is part of an instance of a definition which is a C++ class, it must be declared "Public". See "C++ Classes" on page 260 for more information on C++ classes and member access.
If you are generating Java code, the source widget must be contained within a class and not be abstract. The term `abstract' refers to the `extra' widgets which appear in the hierarchy when composite widgets are selected - such as the ScrolledText in a FileSelectionBox. For more information on using Sun WorkShop Visual for Java code generation, see Chapter 10, "Designing For Java".

Note - If the variable name of a target widget changes, any links defined to that widget are no longer effective.

Setting Links in the Tutorial

You are now going to set a common configuration of links to display the help screen you have just built and make it disappear again at the proper time. To do this you will:

Set a "Show" link on the "About This Layout" button in the Help Menu
Set a "Hide" link on the "OK" PushButton in the help screen
The "OK" PushButton is currently visible in the construction area and so begin by setting the "Hide" link on this PushButton.

  1. Select the PushButton.
  2. Double-click in the "Variable name" field.
  3. Type: ok_button and press <Return> to register the new name.
  4. Pull down the Widget Menu and select "Edit links".
This displays the panel shown in Figure 6-4.

FIGURE  6-4 Default Links Panel

The target of the "Hide" link should be the widget help_window so that when the "OK" button is activated, the entire help screen disappears.

To select the target widget:

  5. Select the Shell help_window in the design hierarchy.
The name of the Shell, help_window, appears in the "Widget" field of the Links panel. However, the "Add" command is still disabled. This is because you have not yet named the DialogTemplate which is the immediate child of the Shell. As discussed above, the child of a Shell must be named explicitly before you can set a link to the Shell.

You can leave the Links panel open while you name the DialogTemplate:

  6. Select the DialogTemplate.
  7. Double-click in the "Variable name" field and type: dialog_2
  8. Reselect the Shell help_window.
The Shell is now a valid target widget and so "Add" is enabled.

Now select the type of link:

  9. Select "Hide" from option menu of link types.
  10. Click on "Add".
The new link appears in the link display area, as shown in Figure 6-5.

FIGURE  6-5 Links Panel with New "Hide" Link

  11. Click on "Close".
To demonstrate the new link:

  12. Click on the "OK" button in the dynamic display.
The help screen vanishes. You can restore it by resetting the Shell.

You can also set up a "Show" link to display the help screen when a button is pressed in the main window. To do this:

  13. Click on the MyFirstShell icon in the window holding area.
The hierarchy for the main window is displayed in the construction area.

Set the new link on the PushButton in the Help Menu:

  14. Select the help_button widget, the PushButton child of the second Menu.
The Links panel, unlike resource panels and the Layout Editor, does not automatically start adding links to the currently selected PushButton. To edit links for the currently selected button, you must:

  15. Pull down the Widget Menu and select "Edit links".
The Links panel now displays the name and the links (none, so far) of the current PushButton. Select the target widget, which is the Shell for the help screen:

  16. Click on the help_window icon in the window holding area.
In the Links panel:

  17. Select the "Show" link type.
  18. Click on "Add".
The new link appears in the link display area.

To demonstrate the behavior of these two links:

  19. Click on the MyFirstShell icon in the window holding area.
  20. Pull down the Help Menu in the dynamic display and select "About This Layout".
The Show link on this pushbutton makes the help screen appear.

  21. Click on the "OK" button in the dynamic display of the help screen.
The Hide link on this pushbutton makes the help screen disappear. You can repeat the previous two steps as many times as you want.

  22. Save your design.

Removing Links

To remove a link:

   Select the link's icon in the link display area and click on "Remove".
The tutorial continues in Chapter 7, "Generating Code". The remainder of this chapter looks at other ways of adding functionality to your application using Sun WorkShop Visual.


Drag and Drop

Motif 1.2 provides a sophisticated drag and drop mechanism that lets applications communicate data via the X selection mechanism. Sun WorkShop Visual provides some simple support to let you specify drop sites in your application. Because the initialization of a drag is a dynamic function that would normally be done from within a callback or action function, Sun WorkShop Visual does not provide any explicit support.

A drop site is a widget that is prepared to receive certain types of data from the transfer mechanism. Sun WorkShop Visual provides its support through the Drop site page of the Core resource panel.

FIGURE  6-6 The Drop Site Page

To designate a widget as a drop site, simply set the "Drop site" toggle on and specify the import targets and drop procedure. The "Import targets" field is a list of strings that are converted into atoms to designate types that can be handled by the drop procedure. The list is specified as strings separated by commas or spaces.

By default Motif makes Label (and derived) widgets start a drag operation to transfer the labelString or labelPixmap if Button 2 is pressed over them. Sun WorkShop Visual takes advantage of this by adding a drop procedure to the drop site widget that imports these types if specified in the import targets. The following tutorial lets you see how the drop site operates.

  1. Create a dialog containing an Application Shell with a RowColumn containing two Push Buttons.
  2. Name the widgets: shell, rowcolumn, MyButton1 and MyButton2 respectively.
  3. Pop up the Drop site page of the core resources for MyButton1.
  4. Set the drop site toggle on and set animation style to "shadow in".
  5. In the "Import targets" field, type: COMPOUND_TEXT
  6. In the "Drop procedure" field, type: drop_button1
  7. Apply your changes and close the dialog.
The drop and drag procedure fields specify the names of functions to be called to handle the drop and dynamic drags respectively.

  8. Try dragging the text from any label (press mouse button 2 and drag) across MyButton1 in the dynamic display window.
The button is "shadowed in" i.e looks selected, to indicate that it is a valid drop site for the target being dragged.

  9. Release the mouse button to drop the text into the widget.
The drop procedure provided by Sun WorkShop Visual simply copies the label into the widget.

  10. Select MyButton2 and repeat Step 4.
  11. In the "Import targets" field, type: PIXMAP
  12. In the "Drop procedure" field, type: drop_button2
  13. Try dragging a pixmap from the tool bar across MyButton2 in the dynamic display window.
For further examples of using drop sites and for information on starting drags, refer to the Motif documentation.

Code is generated for C and C++, with a call to XmDropSiteRegister() being generated for widgets that are not normally drop sites. Text widgets are drop sites by default, which can import COMPOUND_TEXT. This can be disabled by setting the drop site toggle off, or modified by simply changing the appropriate resources.

You must write the drop procedures to handle the transfers. They are simply declared as external functions in the generated code.


Translations and Actions

Widgets have behavior. For example, when a user presses mouse button 1 over a PushButton, it highlights. When the user releases the mouse button, the PushButton's appearance reverts to normal and the functions on the Activate callback list are invoked.

This behavior is not hard-wired into the PushButton widget. Instead, it is determined by the widget's translation table, which maps events to the actions to be taken in response to the events. When a widget is created, its translation table is initialized to contain a default set of entries. For example, the PushButton widget's default translation table includes these entries:

<Btn1Down>:Arm()
<Btn1Up>:Activate() Disarm()
To the left of the colon is an event specification; to the right are the names of the actions that the widget performs in response. A second table, the action table, is used to map the action name to the address of a function that performs it.

For example, the PushButton's default action table includes:

"Arm",	Arm
"Activate",	Activate
"Disarm",	Disarm
The first item in each entry is an action name and the second is the name of a function. Convention and common sense dictate that the action and function names should be the same, or at least related in a well-defined way.

You can change the translation table of any widget within Sun WorkShop Visual. You cannot change the action table of a widget. However, you can define new actions in an application-global action table which is searched after the one associated with the widget. This requires some coding, as described below.


Note - Translations are not supported on Microsoft Windows. For this reason, the Apply button in the Translations dialog turns pink when in Microsoft Windows mode.

Modifying a Translation Table

Modifying the translation table of a widget in Sun WorkShop Visual is straightforward. To understand the procedure, do the following simple exercise in Sun WorkShop Visual.

  1. Create a simple widget hierarchy containing a PushButton.
  2. Select the PushButton icon in the widget hierarchy.
  3. From the "Widget" menu, select "Translations...".
This displays the translations dialog, shown in Figure 6-7.

FIGURE  6-7 Translations Dialog

  4. Click in the lower section, under "Augment", and type: Ctrl<Key>q: ArmAndActivate()
  5. Click on "Apply".
This adds the new translation to the PushButton widget and you can now try its effect.


Note - You may notice an error dialog indicating that the action has not been found. This is for information only, the change has been taken. See "Additional Actions" on page 203 for information about creating an action table within Sun WorkShop Visual.
  6. Place the mouse pointer over the pushbutton in the dynamic display window.
  7. Type: <Ctrl-Q>
The effect is identical to clicking with mouse button 1. Note that translations do not work if the window does not have the input focus and that the input focus behavior depends on the configuration of your window manager.

You can also change the translations you have specified so that the button triggers on other events. Note that if you do this, the previous translation remains effective in addition to the new one until you reset the widget.


Augment, Override and Replace

The translations dialog has sections labeled "Override" and "Augment". You can enter new translations in either section or both. They only differ if you specify a translation with the same event specification as an existing translation. If you type the new translation into the "Override" box, your new translation replaces the existing one. If you use "Augment", the existing translation takes precedence.

The existing default translations for the widget are not affected when you add translations unless you override them. This is important because Motif widgets have many default translations that produce their expected behavior.

If you set the "Replace" toggle, however, all existing translations are removed and replaced by the translations you enter. Use "Replace" with caution. Do not confuse "Replace", which removes all the default translations, with "Override", which replaces them one by one.


Translation Table Syntax

The syntax of translation tables is complex. The following sections detail the syntax as used in Sun WorkShop Visual. For a complete and definitive description, consult the X toolkit documentation.

Each entry in a translation table has the form:

[modifier_list]<event>[,<event>...][(count)][detail]: 
[action([arguments])...]
Square brackets ([]) indicate that an item is optional; an ellipsis (...) indicates that the item may be repeated.


Modifier List

The modifier list represents the state (pressed or not pressed) of the modifier keys (such as Control and Shift) and the mouse buttons (X believes that a mouse has five buttons). The most useful modifiers are Ctrl, Shift, Alt and Meta. These can be abbreviated as c, s, a and m.

If the modifier list is omitted, the state of the modifiers is unimportant:

<Key>Q matches <Q>, <Ctrl-Q>, <Alt-Meta-Q>, etc.

If a particular modifier is not mentioned in the list, its state is unimportant:

Ctrl<Key>Q matches <Ctrl-Q>, <Ctrl-Meta-Q>, <Ctrl-Alt-Meta-Q>,...

You can specify multiple modifiers in the modifier list:

Ctrl Meta <Key>Q matches <Ctrl-Meta-Q> but not <Ctrl-Q> or <Meta-Q>

To specify that a modifier must not be pressed, precede it with a tilde (~):

Ctrl ~Meta<Key>Q matches <Ctrl-Q> but not <Ctrl-Meta-Q>

To specify that the modifiers pressed must exactly match what you specify, start the modifier list with an exclamation mark (!):

!Ctrl<Key>Q matches <Ctrl-Q> but not <Ctrl-Meta-Q> or <Ctrl-Q> with a mouse button pressed.

The modifier "None" means that there must be no modifiers pressed at all.

None<Key>Q matches <Q> but not <Ctrl-Q> or <Alt-Meta-Q>, etc.

Normally, translations are not case-sensitive. <Key>Q matches both <Q> and <q>. You can specify that a translation is case-sensitive by preceding it with a colon (:).

:<Key>Q matches <Q> but not <q>


Event and Count

The event can be the name of an X event, or one of a number of aliases. Some of the most useful events are Key (a key press), BtnDown and BtnUp (for any mouse button) and BtnNDown and BtnNUp (where N is between 1 and 5). For a complete list of events and aliases, see the Xt documentation.

<Key>a matches <a>

<Btn1Up> matches a release of mouse button 1

You can specify a sequence of events in a translation, separated by commas.

<Key>Q,<Key>A matches <Q> followed by <A>, with no intervening event.

<Btn1Down>,<Btn1Up> matches a click of mouse button 1.

The count can be used with button press and release events to detect multiple clicks. The count is a number from 1 to 9, possibly followed by a plus (+).

<Btn1Down>(2) matches two presses of mouse button 1

<Btn1Up>(3+) matches 3 or more releases of mouse button 1

If a count is used, the button events must come close together (usually within 200 milliseconds of each other), or there is no match.


Detail

The final field in the event specification is the detail. This is normally used only with key events, where the detail specifies which key is to be pressed.

The value specified in the detail field is a keysym, as in the header <X11/keysymdef.h>, with the XK_ prefix removed. For most keys, this is the same as the character on the key.

<Key>a matches <a>

For non-alphanumeric keys, check the name of the keysym. The keysym for "+" is XK_plus, so

<Key>plus matches <+>

Since matching is case-insensitive, this also matches the other symbol on the plus key, which is <=> on most keyboards.

Motif adds another level of complexity by translating certain incoming key events into Motif virtual keysyms. You should use these virtual keysyms in your translation tables instead of the X ones.

<Key>osfDelete, not <Key>Delete

The virtual keysyms are listed below. For details of their interpretation, see the VirtualBindings(3X) section of the Motif Programmer's Reference.

TABLE  6-1   OSF Virtual Keysyms

osfActivate

osfAddMode

osfBackSpace

osfBeginLine

osfCancel

osfClear

osfCopy

osfCut

osfDelete

osfDown

osfEndLine

osfHelp

osfInsert

osfLeft

osfMenu

osfMenuBar

osfPageDown

osfPageLeft

osfPageRight

osfPageUp

osfPaste

osfPrimaryPaste

osfQuickPaste

osfRight

osfSelect

osfUndo

osfUp

 

You can also use the detail field with mouse button events to specify a particular mouse button. This is not commonly done since it is easier to specify the mouse button in the event field.

<BtnDown>Button1 is the same as <Btn1Down>


Actions

The actions on the right side of the translation table entry are simple. Usually each action is just a name followed by parentheses. Although any number of string arguments can be given between the parentheses, most action routines expect no arguments. Arguments should not be quoted. Typical additional translations for a ScrollBar widget might be:

<Key>d:IncrementDownOrRight(0)
<Key>u:IncrementUpOrLeft(0)
You can specify multiple actions or none at all. Overriding an existing translation with one that has the same event specification but no action is a useful way of disabling part of a widget's default behavior.

In many cases, the actions used are the ones predefined by the toolkit. The "Additional Actions" on page 203 discusses how to add your own actions.


Translation Table Ordering

When an event is received, the translation table is searched from the top down. The search terminates at the first entry whose event specification matches the event. This means you should organize your translation table with the most specific events first. For example, a translation table might contain the following entries:

<Key>q: action1()
Ctrl<Key>q: action2()
When the user types either <Q> or <Ctrl-Q>, the search terminates at the first entry and action1() is invoked in both cases. To make <Ctrl-Q> invoke action2, you must reverse the order of the entries.

For additional subtleties in ordering translation tables, see the X toolkit documentation.


Available Actions

By changing the translation table, you can make a widget perform actions in response to event sequences that would not normally trigger those actions. While you can write your own action routines, translations provide the most benefit when you can use one of the built-in actions of the widget.

The built-in actions of the Motif toolkit are documented in the Motif Programmer's Reference. Each widget description includes both the default translations and the actions they invoke. Some of the primitive widgets offer a particularly large set of actions.

If you add a translation that uses one of these actions, you can test it in Sun WorkShop Visual immediately. Alternatively, a few built-in actions, such as the PushButton's Activate() action, invoke the functions in one of the widget's callback lists. In this case, it may be easier to specify a translation to call that action on the appropriate event sequence and put the code in an ordinary callback function.


Additional Actions

If you cannot find a built-in action to suit your needs, you can write your own action routine to perform the action. Figure 6-8 shows an example translation. The example shown says that when <Ctrl-e> is pressed, the action "doActionE" is triggered.

FIGURE  6-8 Translation Example

If you define your own action routine, it needs to be added to the application's "action table". Sun WorkShop Visual does this for you automatically when you define the action procedures in the Action Procedures dialog, displayed by selecting "Action Procedures..." from the Module menu, as shown in Figure 6-9.

FIGURE  6-9 Action Procedures Dialog

In the example shown in Figure 6-8, "doActionE" is an action which needs to be defined for the application. Figure 6-9 shows the definition of this action. The "Action Name" is the name used in the Translations dialog, the "Procedure Name" is, as you might expect, the name of the procedure which will be called. In the interests of clarity, these names are usually the same.

Action procedures do not have any client data associated with them, but they are passed the parameters defined for the action in the Translations dialog. You can provide any number of parameters in that dialog and within the parentheses, so long as they are all strings.

You may have any number of action procedures defined within your design. Sun WorkShop Visual generates their stubs and the associated action table into the main code file.


Xt Procedures

Sun WorkShop Visual allows you to add the following types of Xt procedure:

  1. Additional event procedures. This includes input sources and timeouts which may be treated as though they are the source of events, as well as Xt Work procedures which are called when there are no events to process.
  2. Language procedures. One of these is called at the beginning of an X application as a means of customizing the localization of the application, although you may specify any number of them.
  3. Event handlers. These procedures are called when one of a number of pre-defined actions occurs (e.g. "mouse button 1 pressed"). These bypass the translation table.
The first two types of Xt procedure listed above are specified on an application-wide basis. The fourth is specified on a per-widget basis. All are described in the following sub-sections.


Alternate Event Sources for X

An Xt (X toolkit) application normally waits for events from the X server. User actions, such as keyboard presses and mouse clicks, arrive at the Xt application via the X server. If, for some reason, a user is sitting quietly and not typing or clicking, then the application just waits. This means that an Xt application can spend a considerable amount of time waiting. For this reason, Xt allows you to register procedures to be called when there are no other events to process. You may also register procedures which respond to certain events not originating from the X server. Here are the "extra" procedure types which may be added:

  1. Xt Work Procedure.
  2. Input Procedure.
  3. Timeout Procedure.
As with widget callback procedures added inside Sun WorkShop Visual, any Xt procedures that you have added are generated as stubs into the stubs file. You may then edit them from within Sun WorkShop Visual in the same way as widget callbacks may be edited. The code for adding your procedures is generated by Sun WorkShop Visual into the main module.


Note - If you are not generating a main module, your Xt procedures will not be added to your application.
These procedures are added by selecting the corresponding item in the Module menu. The following sub-sections describe each procedure type individually.


Xt Work Procedures

A work procedure is a function that is called when Xt has no other events to process. Work procedures are, therefore, a convenient means of setting up a background batch process without interfering with events from the X server. One common use of work procedures is in program initialization. There are often many widgets which need to be created when an application is started. Since this is a time-consuming process, using work procedures allows the application to respond to user actions almost immediately.

Work procedures should return True or False. A value of True indicates to the X toolkit that your procedure should be removed from the work queue once executed. False indicates that it should be called again the next time the queue is empty of user events. You can have any number of work procedures registered at any time.

To add a work procedure, select "Work Procedures..." from the Module menu. The dialog shown in Figure 6-10 appears. You may add any number of work procedures but you should remember that your application cannot handle any other event while executing a work procedure. For this reason, work procedures should return quickly. Priority is generally given to work procedures in the order registered.

FIGURE  6-10 Work Procedures Dialog


Input Procedures

Use input procedures to set up a file or pipe as a source of events. The input procedure is called when the file is ready for reading (or writing). To add an input procedure, select "Input Procedures..." from the Module menu. The dialog shown in Figure 6-11 is displayed.

FIGURE  6-11 Input Procedures Dialog

To define an input procedure, you will need to provide the file descriptor of the file or pipe. The Input Mask specifies the type of access the file should have. When the file is ready for the specified access, the input procedure is called. You may define any number of input procedures, they will be added in turn.


Timeout Procedures

A timeout procedure provides a means of performing a function after a specified amount of time has elapsed. Timeouts are called once only, so if you need a timeout procedure to be called at regular intervals, it will have to add itself as another timeout procedure before exiting. The following function call will do this:

XtAppAddTimeOut(appContext, timeoutPeriod, procedure, clientData);
To add a timeout procedure, select "Timeout Procedures..." from the Module menu. This causes the dialog shown in Figure 6-12 to be displayed.

FIGURE  6-12 Timeout Procedures Dialog

The "Timeout Period" is specified in milliseconds.

Timeout procedures work better in an X environment than time-interrupt programming using signals, which is often the preferred method with UNIX. You may define any number of timeout procedures; Sun WorkShop Visual generates them all into the main code file.


Language Procedures

An application operates within the context of a particular locale. The locale determines how to accept keyboard input, how to display characters and the format of date and time strings. This allows developers to customize their applications for use in different countries.

Sun WorkShop Visual generates a call to the X toolkit routine XtSetLanguageProc in the main code file. One of the parameters to this routine is the name of the procedure which will set up the locale. Xt provides a default language procedure, but you can define your own should you wish to have additional methods of setting the locale or only provide support for certain locales. To define a language procedure, choose "Language Procedures..." from the Module menu. The Language Procedures dialog, shown in Figure 6-13, is then displayed.

FIGURE  6-13 Language Procedures Dialog

You may specify as many language procedures as you like, but only one will be effective (as only one can be passed as a parameter to XtSetLanguageProc). Sun WorkShop Visual chooses the procedure at the top of the list in the Language Procedures dialog as the procedure to pass in. You can change which is the topmost procedure in this list by using the arrow buttons underneath. Simply select the required procedure and press the up arrow until it is at the top. Stubs for all language procedures in the list are generated into the stubs file.


Event Handlers

Event handlers provide an efficient means of performing low level input handling which bypasses the translation tables of the widget. They are particularly suited to high-volume events. A translation and associated action, however, can do almost anything that an event handler can do but may be easier to maintain.

Event handlers, unlike the other Xt procedures, are defined for individual widgets rather than for the whole application.

Add an event handler by selecting the widget whose events are wanted and then choosing "Event Handlers..." from the Widget menu. The dialog shown in Figure 6-14 is displayed.

FIGURE  6-14 Event Handlers Dialog

In this dialog there are text fields for entering a procedure and an event mask. The text fields have corresponding buttons which, when pressed, display sub-dialogs showing the procedures and event masks available. You may define a new procedure but the event masks should come from the valid set displayed. The event masks are annotated with the Java "coffee cup" if they are applicable to Java code, as shown in Figure 6-15.

FIGURE  6-15 Event Masks

If the "Non Maskable" toggle is set, the event handler will also receive the non-maskable events (ClientMessage, GraphicsExpose, MappingNotify, NoExpose, SelectionClear, SelectionNotify and SelectionRequest). This toggle would normally remain unset as these events are not particularly useful.

The "Raw" toggle is a means of telling Sun WorkShop Visual to add a raw event handler. This is an event handler which does not respond immediately to the events for which it is registered. Instead, the handler is triggered when its events are selected elsewhere (by another event handler, for example).

One possible use of raw event handlers is to "shadow" another event handler. If both are added with the same event mask, but one is "raw" and the other is not, then both handlers will be called when the appropriate events occur. The raw event handler can then log the events that the other handler receives.

As with callback functions, you can specify the same event handler for any number of widgets and then use the Client Data to set the context.

Typically, event handlers are used in situations where the widget has little in the way of built-in interaction support, or where large volume or crude input may need processing. DrawingAreas are obvious candidates for event handlers.

Event handlers are generated by Sun WorkShop Visual into the code file as part of the general widget configuration and a stub is generated into the stubs file.

There is a "Widget annotation" for event handlers. By selecting the event handler annotation from the pullright menu in the View menu, you can see at a glance which widgets have had event handlers defined for them.


Editing Xt Procedures

As with callbacks, the generated stubs for Xt procedures can be edited from within Sun WorkShop Visual using your favorite configured editor.




Previous Next Contents Generated Index Doc Set Home