[Previous] [Contents] [Index] [Next]

Events

The interactions between applications, users and the Photon server are represented by data structures called events.

This chapter discusses:

For more information on the PhEvent_t structure, see the Photon Library Reference.

Emitting events

This section describes how to use PhEventEmit(), as well as:

The most general way for an application to emit an event is by calling PhEventEmit():

int PhEventEmit( PhEvent_t *event,
                 PhRect_t *rects,
                 void *data );

The arguments are as follows:

event
A pointer to a PhEvent_t structure. The application emitting the event needs to set the following members:

The Photon Manager sets the following members of the event structure after a copy of the event is enqueued to an application:

rects
An array of rectangles indicating the event's initial rectangle set. If the application sets this argument to NULL, the initial rectangle set defaults to a single rectangle that has the dimensions of the emitting region (i.e. event->emitter).
data
Valid data for the type of event being emitted. Each type of event has its own type of data, as described for the PhEvent_t structure in the Photon Library Reference.

If the event-specific data isn't in contiguous memory, you may find PhEventEmitmx() more useful than PhEventEmit():

int PhEventEmitmx( PhEvent_t *event,
                   PhRect_t *rects,
                   int mxparts,
                   struct _mxfer_entry *mx );
    

The return codes for PhEventEmit() and PhEventEmitmx() are:

0
Successful completion.
-1
An error occurred, or no further events are pending. Check the value of errno:

These return codes are useful for applications that spend most of their time emitting events and want to retrieve an event only if there's one pending for them.

Targeting specific regions

Sometimes an application needs to target an event directly at a specific region, without making the event travel through the event space before arriving at that region. You can use an inclusive event or a direct event to ensure that the targeted region sees the event.

Inclusive event

For an inclusive event, do the following:

If you don't want an inclusive targeted event to continue through the event space, you must make the emitting region opaque to that type of event.

Direct event

For a direct event, do the following:

Targeting specific widgets

If you want to send an event to a specific widget, you could call PhEventEmit() as described above, but you'll need to look after a lot of details, including making sure:

It's easier to call PtSendEventToWidget(). This function gives the event to the specified widget directly and without delay. It's much more deterministic and efficient than PhEventEmit().

The prototype is:

int PtSendEventToWidget( PtWidget_t *widget, 
                         PhEvent_t *event );

Emitting key events

Sometimes you might need to simulate a key press in your application. Depending on what exactly you want to achieve, you can choose from several ways of generating key events:

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.


Note: 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.

Dragging is done in two steps:

  1. Initiating the dragging, usually when the user clicks on something.
  2. Handling drag (Ph_EV_DRAG) events.

These steps are discussed in the sections that follow. For a more complex example, download the exdrag files from the /usr/free/qnx4/photon/examples directory in QUICS.

Initiating dragging

Where you initiate the dragging depends on how the user is meant to drag widgets. For example, if the user holds down the left mouse button on a widget to drag it, initiate dragging in the widget's Arm (Pt_CB_ARM) callback. Make sure that Pt_SELECTABLE is set in the widget's Pt_ARG_FLAGS resource.

Dragging is started by calling the PhInitDrag() function:

int PhInitDrag( PhRid_t rid,
                unsigned flags,
                PhRect_t *rect,
                PhRect_t *boundary,
                unsigned int input_group,
                PhDim_t *min,
                PhDim_t *max,
                PhDim_t *step );

The arguments are used as follows:

rid
The region that rect and boundary are relative to. You can get this by calling PtWidgetRid().
flags
Indicate whether outline or opaque dragging is to be used, and which edge(s) of the dragging rectangle track the pointer, as described below.
rect
Rectangular area to drag.
boundary
Rectangular area that limits the dragging
input_group
Get this from the callback's cbinfo parameter:
cbinfo->event->input_group
    
min, max
Minimum and maximum sizes of the drag rectangle.
step
Dragging granularity.

If Ph_DRAG_TRACK is included in flags, then opaque dragging is used; if Ph_DRAG_TRACK isn't included, outline dragging is used.

The following flags indicate which edge(s) of the dragging rectangle track the pointer:

Outline dragging

The following example shows an Arm (Pt_CB_ARM) callback that initiates outline dragging:

/* Start dragging a widget                               */
/*                            AppBuilder Photon Code Lib */
/*                                         Version 1.11  */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
start_dragging( PtWidget_t *widget, 
                ApInfo_t *apinfo, 
                PtCallbackInfo_t *cbinfo )

{
    PhDim_t *dimension;
    PhRect_t rect;
    PhRect_t boundary;
    PtArg_t args[1];

    /* eliminate 'unreferenced' warnings */
    widget = widget, apinfo = apinfo, cbinfo = cbinfo;

    /* Set the dragging rectangle to the position and size of
       the widget being dragged. */

    PtWidgetExtent (widget, &rect);

    /* Set the boundary for dragging to the boundary of the
       window. */

    PtSetArg (&args[0], Pt_ARG_DIM, &dimension, 0);
    PtGetResources (ABW_base, 1, args);
    boundary.ul.x = 0;
    boundary.ul.y = 0;
    boundary.lr.x = dimension->w - 1;
    boundary.lr.y = dimension->h - 1;

    /* Initiate outline dragging (Ph_DRAG_TRACK isn't 
       specified). */

    PhInitDrag (PtWidgetRid (ABW_base), 
                Ph_TRACK_DRAG,
                &rect, &boundary,
                cbinfo->event->input_group,
                NULL, NULL, NULL);

    /* Save a pointer to the widget being dragged. */

    dragged_widget = widget;

    return( Pt_CONTINUE );
}

The above callback is added to the Arm (Pt_CB_ARM) callback of the widget to be dragged. It can be used for dragging any widget, so a pointer to the widget is saved in the global variable dragged_widget.

Opaque dragging

If you want to use opaque dragging, add the Ph_DRAG_TRACK flag to the call to PhInitDrag():

PhInitDrag( PtWidgetRid (ABW_base), 
            Ph_TRACK_DRAG | Ph_DRAG_TRACK,
            &rect, &boundary,
            cbinfo->event->input_group,
            NULL, NULL, NULL );

Handling drag events

To handle drag (Ph_EV_DRAG) events, you need to define a Raw (Pt_CB_RAW) callback.


Note: The raw callback must be defined for the widget whose region was passed to PhInitDrag(), not for the widget being dragged. For the example given, the Raw callback is defined for the base window.

As described in "Raw-event callbacks" in the Editing Resources and Callbacks in PhAB chapter, you use an event mask to indicate for which events your callback is to be called. For dragging, the event is Ph_EV_DRAG. The most commonly used subtypes for this event are:

Ph_EV_DRAG_START
the user has started to drag
Ph_EV_DRAG_MOVE
the dragging is in progress (opaque dragging only)
Ph_EV_DRAG_COMPLETE
the user has released the mouse button

Outline dragging

If you're doing outline dragging, the event subtype you're interested in is Ph_EV_DRAG_COMPLETE. When this event occurs, your callback should:

  1. Get the data associated with the event. This includes the location of the dragging rectangle, in absolute coordinates.
  2. Calculate the new position of the widget, relative to the dragging region. This is the position of the upper left corner of the dragging rectangle, translated by the amount given in the event's translation field.
  3. Set the widget's Pt_ARG_POS resource to the new position.
    Note: Remember, the callback's widget parameter is a pointer to the container (the base window in the example), not to the widget being dragged. Make sure you pass the correct widget to PtSetResources() when setting the Pt_ARG_POS resource.

For example, here's the Raw callback for the outline dragging initiated above:

/* Raw callback to handle drag events                    */
/*                            AppBuilder Photon Code Lib */
/*                                         Version 1.11  */

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Toolkit headers */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>

/* Local headers */
#include "globals.h"
#include "abimport.h"
#include "proto.h"

int
end_dragging( PtWidget_t *widget, 
              ApInfo_t *apinfo, 
              PtCallbackInfo_t *cbinfo )

{
    PhDragEvent_t *dragData;
    PtArg_t args[1];
    PhPoint_t new_pos;

    /* eliminate 'unreferenced' warnings */
    widget = widget, apinfo = apinfo, cbinfo = cbinfo;

    /* Ignore all events until dragging is done. */

    if (cbinfo->event->subtype != Ph_EV_DRAG_COMPLETE)
    {
      return (Pt_CONTINUE);
    }

    /* Get the data associated with the event. */

    dragData = PhGetData (cbinfo->event);
    
    /* The rectangle in this data is the absolute 
       coordinates of the dragging rectangle. We want to 
       calculate the new position of the widget, relative to 
       the dragging region. */

    new_pos.x = dragData->rect.ul.x 
                + cbinfo->event->translation.x;
    new_pos.y = dragData->rect.ul.y 
                + cbinfo->event->translation.y;
    printf ("New position: (%d, %d)\n", new_pos.x, new_pos.y);

    /* Move the widget. */

    PtSetArg (&args[0], Pt_ARG_POS, &new_pos, 0);
    PtSetResources (dragged_widget, 1, args);

    return( Pt_CONTINUE );

}

Opaque dragging

The callback for opaque dragging is similar to that for outline dragging-the only difference is the subtype of event handled:

if (cbinfo->event->subtype != Ph_EV_DRAG_MOVE)
{
  return (Pt_CONTINUE);
}


[Previous] [Contents] [Index] [Next]