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

Regions

In Photon, all applications consist of one or more rectangles called regions, which reside in an abstract, three-dimensional event space.

This chapter discusses:

Photon coordinate space

The Photon coordinate space looks like this:


Photon coordinate space


Photon coordinate space.



Note: Unlike the typical Cartesian layout, the lower-right quadrant is the (+,+) quadrant.

The root region has the same dimensions as the entire coordinate space. As a rule, graphics drivers map the display screen to the location shown in the above diagram and place the Photon origin at the upper-left corner of the display screen. (Graphics drivers equate a single Photon coordinate to a single pixel value on your display screen).

Region coordinates

Region origins

When an application specifies coordinates within a given region, these are relative to the region's origin. The application specifies this origin when it opens the region.

Initial dimensions and location

The initial dimensions of a region (i.e. rect argument in PhRegionOpen()) are relative to its origin. These dimensions control the range of the coordinates that the application can use within the region.

Let's look at some examples to get an idea of the relationship between a region's origin and its initial rectangle coordinates. These examples illustrate how opened regions are placed in relation to the root region, which has its origin in the center of the Photon coordinate space.

Origin at (0,0) and initial rectangle at (0,0)

As a rule, applications use the following approach for regions. (These kinds of regions are described in the section "Photon window manager" of the Photon Architecture appendix.)

Coordinates:
Origin = (0,0)

Upper left of initial rectangle = (0,0)

Lower right of initial rectangle = (100,100)

region coordinates 1

Origin at (0,0) and initial rectangle not at (0,0)

The following example shows an approach typically used for regions that fill the entire coordinate space. For example, for the device region and the workspace region, the upper left is (-32000,-32000) and the lower right is (32000,32000).

Coordinates:
Origin = (0,0)

Upper left of initial rectangle = (-50,-50)

Lower right of initial rectangle = (50,50)

region coordinates 2

Origin not at (0,0) and initial rectangle not at (0,0)

The following example shows how a child's origin can differ from its parent's origin.

Coordinates:
Origin = (-50,-50)

Upper left of initial rectangle = (0,0)

Lower right of initial rectangle = (100,100)

region coordinates 3

About child regions

Coordinates are always relative to a region. So when a region is moved, all its children automatically move with it. Likewise, when a region is destroyed, its children are destroyed.


Note: To become larger than any other of the application's regions, a region must make itself a child of the root region, using PhRegionOpen() or PhRegionChange(). This action severs the region's relationship with its former parent.

Regions and event clipping

A region can emit or collect events only where it overlaps with its parent. For example, in the following diagram:


Regions and event clipping


Regions and event clipping.


Because of this characteristic of regions, any portion of a region that doesn't overlap its parent is effectively invisible.

Placement and hierarchy

Region hierarchy

In Photon, every region has a parent region. This parent-child relationship results in a region hierarchy with the root region at the top. The following diagram shows the hierarchy of a typical Photon system:


region hierarchy


Hierarchy of regions for a typical Photon system.


Parent region

The Photon Manager always places child regions in front (i.e. on the user side) of their parents:

parent region


Note: When opening a region, an application specifies the region's parent. If an application opens a region without specifying its parent, the region's parent is set to a default - basic regions become children of the root region and windows become children of the window manager's backdrop region.

Brother regions

Besides having a parent, a region may have "brothers," i.e. other regions who have the same parent. A region knows about only two of its brothers - the one immediately in front and the one immediately behind.

The following diagram shows a parent with three children, and the relationship that child region 2 has with its brothers:

region with brothers

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.


Note: If an application opens a region, specifying both brothers, and this action results in an ambiguous placement request, the resulting placement is undefined.

Default placement

If an application opens a region without specifying brothers, the Photon Manager places that region using default placement rules. In most cases, these rules cause a newly opened region to be placed in front of its frontmost brother, which then becomes "brother behind" of the new region. (To use different placement rules, you can specify the Ph_FORCE_FRONT flag.)

For example, in the following diagram, child region 1 is the frontmost region:

default placement 1

When the application opens child region 2 with default placement (next diagram), region 2 is placed in front of region 1. Region 1 becomes region 2's brother "behind." Region 2 becomes region 1's brother "in front."

default placement 2

Ph_FORCE_FRONT flag

An application uses the Ph_FORCE_FRONT flag when it wants a region to remain in front of any subsequent brothers that rely on the Photon Manager's default placement.

As mentioned earlier, when a region is opened with default placement, it's placed ahead of its frontmost brother. But if any brother has the Ph_FORCE_FRONT flag set, then the new region is placed behind the farthest brother that has the Ph_FORCE_FRONT flag set.

For example, let's see what would happen in the following example if child region 1 had the Ph_FORCE_FRONT flag set:

default placement 3

When child region 2 is opened with default placement (next diagram), it's placed behind region 1, and region 1 becomes its "brother in front." Because region 2 was placed using default rules, it doesn't inherit the Ph_FORCE_FRONT setting of region 1:

default placement 4

Then, if child region 3 is opened with default placement, it's placed as follows:

default placement 5


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

Remember that the Ph_FORCE_FRONT flag affects placement only among brother regions - a child region always goes in front of its parent.

Specific placement

In contrast to default placement, if any brother is specified when a region is opened, then that specification controls the placement of the new region. We refer to this as specific placement.

If a "behind" brother is specified, then the newly opened region automatically is placed in front of that brother.

If an "in front" brother is specified, then the newly opened region is automatically placed behind that brother.


Note: The Ph_FORCE_FRONT setting of the specified brother is inherited by the new region. If an application opens a region, specifying both brothers, and this results in an ambiguous placement request, then the resulting placement is undefined.

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:

To retrieve this information, you can use PhRegionQuery().

Changing region placement

An application can specify a region's placement when it opens the region, or it can change the placement later on. To change a region's placement, the application must change the relationship between the region and the region's family.

The application does this by doing any or all of the following:


Note: Since an application can be sure of the position of only the regions it owns, it shouldn't change the position of any other regions. Otherwise, by the time the application makes a request to change the position of a region it doesn't own, the information retrieved by PhRegionQuery() may not reflect that region's current position. That is, a request to change a region's placement may not have the results the application intended.

Changing the parent

You can change a region's parent in two ways. The first and simplest way is to specify the parent in the parent member of the PhRegion_t structure. This makes that region the parent of the region specified in the rid member of PhRegion_t. However, if you set parent to 0, then the region's parent is set to a default. For a basic region, the root region becomes the parent. For a window frame region, the window manager's backdrop region becomes the parent.

The other way to change a region's parent is to specify a child of another parent as the region's brother. This makes the region a child of that parent.

Specifying brothers

If you set: Then:
bro_behind The region indicated in the rid member of PhRegion_t moves in front of the bro_behind region
bro_in_front The region indicated in the rid member of PhRegion_t moves behind the bro_in_front region

As discussed in "Changing the parent," a region inherits the parent of any specified brothers that are children of another parent.

System information

You can get the following information about your system:

There are two functions that you can use to get system information:

PhQuerySystemInfo()
Get the information for a given region.
PtQuerySystemInfo()
Get the information for a widget (usually a window).

PhQuerySystemInfo() sends a message to the server each time that you call it.

PtQuerySystemInfo() calls PhQuerySystemInfo(), but buffers the information. When a region that intersects your widget changes (for example, it's moved), the buffer is marked as invalid. The next time you call PtQuerySystemInfo(), it calls PhQuerySystemInfo() again. By using the buffer whenever possible, PtQuerySystemInfo() keeps the number of messages to a minimum.

Both PtQuerySystemInfo() and PhQuerySystemInfo() fill in a structure of type PhSysInfo_t that your application has allocated. This structure contains at least the following:

PhGeneralSysInfo_t gen
general information. Always examine this.
PhGrafxInfo_t gfx
information on graphics regions
PhKbdInfo_t kbd
information on keyboard regions
PhPtrInfo_t ptr
information on graphics regions
PhIgInfo_t ig
information on input-group regions

Note: Always examine the general information gen first, to see which of the other structures contain data.

The gen structure contains at least the following:

ulong_t valid_fields
Indicates which of the other fields are valid, as described below.
ushort_t version
the version of the Photon server
ulong_t bandwidth
the estimated bandwidth between your process and the Photon server
ulong_t capabilities
not in use
ushort_t num_gfx
the number of graphics regions
ushort_t num_kbd
the number of keyboard regions
ushort_t num_ptr
the number of pointer regions
ushort_t num_ig
the number of input-group regions

The valid_fields field is a set of flags that indicates which of the other fields are valid. The flags include:

For example, before referring to gfx in the PhSysInfo_t structure, you should check that it's valid:

if (sysinfo.gen.valid_fields & Ph_GEN_INFO_NUM_GFX)
{
  /* It's valid. */
  ...
}

The other fields in the PhSysInfo_t structure are similar. Each has a valid_fields field that you should check before using the data. For details on these structures, see the <photon/PhT.h> header file.

One field that's of particular interest is the graphics bandwidth, in gfx.bandwidth. This value can be used to modify the behavior of an interface based on the connection speed. For example, a simple state change could be substituted for an elaborate animation if the bandwidth is Ph_BAUD_SLOW or less. It's also a good idea to see if shared memory can be used for drawing; the Ph_GCAP_SHMEM flag is set in gfx.capabilities if all the graphics drivers support the ...mx() functions and they're all running on your node.


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