summaryrefslogtreecommitdiff
path: root/CoreStructures
blob: 348ee57911ceaf5f975ceb00d207d81d322d8694 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
==========================================================
Beryl's core structures - version this-is-not-complete-yet
==========================================================

.. contents:: Table of Contents

0. State of this document - Compiz Fusion
=========================================
This document was written for the Beryl project, so not all of this applies
to Compiz Fusion. Most of it does. 

1. Scope of this document
=========================
This document attempts to clear up some confusion about the most important data
structures in Compiz Fusion. I will not describe every part of the structures,
but rather clear up some trickier parts.

The Beryl project had a debug plugin which was capable of displaying the
content of many of these structures on the fly. It might get ported for Compiz
Fusion. 

2. CompDisplay vs CompScreen
============================
If you've seen the DISPLAY variable, it'll look something like this for most 
people: DISPLAY=:0.0 . The first 0 here is the display, and the second 0
is the screen. Each X server has ONE display, but can have multiple screens.

Do not confuse a screen with a monitor, though. In bigscreen multihead
environment (the most common multihead setup, xinerama, xrandr, twinview,
mergedfb, they all supply this), the X server presents just one screen to the
programs, but gives us hints about where the head/monitor stops and starts. 

Usually, there isn't any real work needed in a plugin to support multiscreen.
All you need to do is make sure you deal with CompScreen and never assume
that you can get the right CompScreen from display->screens. There are 
functions in core that let you find a screen based on the root window. Use
these, even if display->screens is very tempting.

Generally, we keep bindings in Display-scope. This can add some complications,
but make sure you find the right screen if you want your binding to only
affect one screen. Take a look at rotate.c to see how this is done as an
example. 

The rule of thumb is that input is display scope, and output is screen-scope:
You can only input to one screen at the time, but output to multiple.


3. CompDisplay
==============
CompDisplay is mostly dealt with by core. It is the DataStructure that glues
all the possible screens together. Chances are, you will mostly just work with
d->activeWindow which defines the currently active (focused) window, and the
d->pointerX/Y which tells you where the pointer is. Also, it stores the atoms
fetched by core. 

4. CompScreen
=============
CompScreen is _the_ structure. You will get to know this whether you want to
or not if you intend to do development on Beryl.

First of all, it is a linked list item, so it contains a link to the next
CompScreen. It also has a link to the CompDisplay structure it belongs to.
Because of that fact, you never need to pass both CompDisplay and 
CompScreen to a function, and you are better off passing CompScreen than
CompDisplay, because the latter can have several CompScreens.

Each screen has a unique root window, which is often used in identifying the
screen when you get events. This is process is usually handled by core when
you call findScreenAtDisplay().

'height' and 'width' is the height and width of the entire screen. It is
very tempting to use these a lot, but they are dangerous. The reason they
are dangerous is that they span across all heads associated with that screen.
Therefore, you want to familiarise yourself with the CompOutput structure.
The CompScreen has an array of nOutputDev CompOutput structures; in other
words, one per monitor. It also has a convenient currentOutputDev which core
tries to set, but is not always accurate. 

Luckily, the CompOutput struct is very simple. It has a width, height, region
and workArea variable that we care about. The region helps us establish
where an outputDev starts in the screen. region.x1 defines where the X-coordinate
of that specific window starts, and region.x2 describes where it ends. The same
with region.y1/y2 respectively for the Y coordinate.
For a single monitor with 1024x768, the outputdev will look like this:

x1: 0 
x2: 1023

y1: 0
y2: 767

Keep in mind that x + width puts you 1 pixel beyond the device. (0-1023 is 1024
numbers. A classic programming error is to forget that 0 is a valid number).
Currently, we don't really use the rects of the regions, so for now we can
ignore those. 

workArea is the extents of the head, but is supposed to take struts into 
consideration. Just like s->workArea. There have been changes in this area in
the past, Beryl and Compiz diverge somewhat as two different solutions were
initially used to solve multihead struts and floating struts. A strut is an
area of the screen that should not be covered by windows, usually because it
is covered by a panel. 

So when do you use s->width and when do you use
s->outpudDev[s->currentOutputDev].region.x1/x2 ? There is no universal answer
to this, but the simple answer is to use s->width when you are concerned with
the entire screen, and the outputDev when you want to constrain yourself to the
monitor. Examples are maximization, which deals with outputDev, and edge-
detection, which wants to find the edge of the screen, not the monitor.
Snapping wants to snap to the edge of the head, and so on.

More obvious variables are hsize and vsize, which define the horisontal
and vertical size, x and y, which define which of these you are currently on,
screenNum, which defines which screen you are on (usually 0), and the WorkArea
rectangle, which defines the work area for the screen (avoid using this, as
it will be quite strange on bigscreen-hinted multihead, specially for
asymetric resolutions)

Here's a drawing of an asymetric multihead setup:

+--------+-------------+
|        |             |
|   A    |             |
|        |      B      |
+--------+             |
|   C    |             |
+--------+-------------+

A and B are monitors, C is part of the screen, but is not visible (The screen
has to be rectangular). If you have a strut on the bottom of A, This will mean
that s->workArea cuts off everything on B that's below that strut too, which
we obviously don't want to use too much. 

Each CompScreen also has a list of windows (s->windows) and the reversed
version. Windows are stored in a bottom-up fashion, so the first window in
s->windows will be the bottommost window. 

TODO: Window walking interface.

During drawing, you also have to deal with which output device is being drawn
to. This is very important for multihead, and there is a special device called
s->fullscreenOutput which sets the OpenGL viewport to the entire screen,
unlike the normal operation which draws each head separately. This is
discussed further in the multihead documentation.

5. CompWindow
=============
Each window has a CompWindow structure. However, you should not store this link
unless you also make sure you listen for events which would destroy it and 
update your version accordingly. If you want your plugin to remember a window,
it is often wise to use the w->id instead, and locate the CompWindow when you
need it, but this depends on how you use the CompWindow. Storing the CompWindow
pointer is faster, but slightly more complex. Keep in mind that the CompWindow
pointer can become invalid if you do not pay attention to window destruction
events, while the w->id will never become invalid, it will just stop
identifying the window. That's the difference between a SIGSEG and not finding
the window.

6. Regions