# 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.

```
```

 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)

### 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)

### 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)

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

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

# Regions and event clipping

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

• Child 1 can emit or collect events anywhere in its region
• Child 2 can emit or collect events only in the smaller gray area that overlaps with its parent region

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:

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:

 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:

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.

 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:

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."

### 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:

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:

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

 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.

 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.

## Placing regions

While a region is always in front of its parent, the region's placement relative to its brothers is flexible. See "Placement and hierarchy" for more information about "default" and "specific" placement.

The PhRegion_t structure contains the following members. These indicate the relationship of a region with its siblings:

• bro_in_front - indicates the sibling immediately in front
• bro_behind - indicates the sibling immediately behind

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

### Changing region placement

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

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

• setting the parent, bro_front, and bro_behind members of the PhRegion_t structure
• setting the corresponding fields bits to indicate which members are valid (only those fields marked as valid will be acted on)
• calling the PhRegionChange() function

 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

• the version of your Photon server
• the bandwidth of communication between your window and the Photon server
• graphics regions
• keyboard regions
• pointer regions
• input group regions

 You don't get information about each region. Instead, you get the minimum value of each type of information. For example, if several regions overlapping your window have different bandwidths, the bandwidth given is the minimum of them.

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

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

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

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

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

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

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

The gen structure contains at least the following:

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

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

• Ph_GEN_INFO_BANDWIDTH
• Ph_GEN_INFO_CAPABILITIES
• Ph_GEN_INFO_NUM_GFX
• Ph_GEN_INFO_NUM_KBD
• Ph_GEN_INFO_NUM_PTR
• Ph_GEN_INFO_NUM_IG

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

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

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

One field that's of particular interest is the graphics bandwidth, in gfx.bandwidth. This value can be used to modify the behavior of an 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.