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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
FBCOMPOSE PLUGIN DEVELOPMENT GUIDE
Author: Gediminas Liktaras <gliktaras at gmail dot com>
What Is a Plugin
An fbcompose plugin is an .so file, which the compositor loads and uses to
alter the way it renders the desktop.
Getting Started
The easiest way to start is to use one of the existing fbcompose plugins:
1) Decide which renderer the plugin will be for.
2) Make a copy of the directory of one of the plugins for that renderer.
3) Rename .hh and .cc files inside to match your plugin.
4) Update Makefile.am inside your plugin directory to match your new plugin.
Do not forget to change the name of the shared library (i.e. the *.la
name).
5) Update SUBDIRS variable in Makefile.am file one directory up so it
includes your plugin directory and add your makefile to configure.in file
the root directory of the repository.
Then when you want to build your plugin, simply build fluxbox as usual. The
.so file will be located in .libs subdirectory. To test it, cd into
util/fbcompose, start the compositor from there and use --plugin flags to
load the plugin as usual.
If you do not want to build fluxbox every time you want compile your plugin,
just change the Makefile.am file to point to wherever fluxbox source code and
libFbTk.a are located. In this case you will have to specify the full path to
the .so file with the --plugin parameter.
The sections below will explain what the compositor expects from the plugin
in detail.
Plugin Shared Object Requirements
All plugins must provide two functions with very specific prototypes, as
detailed below:
* Plugin object creation function.
This function must return an instance of a plugin class, which will perform
all the work of altering the screen's contents. When writing your own
plugin, you should create a class that derives either OpenGLPlugin or
XRenderPlugin (depending on the plugin's type), override its functions as
necessary and finally instantiate and return it in this function. Detailed
information about these two classes can be found below in the "Plugin
Classes" section.
The first parameter is a reference to the screen object that the plugin
object will manipulate and the second parameter is a vector of strings,
which contains the user's plugin configuration. They should be passed to
the plugin object's constructor.
Prototype:
extern "C" FbCompositor::BasePlugin
*createPlugin(const FbCompositor::BaseScreen &screen,
const std::vector<FbTk::FbString> &args);
* Plugin type function.
This function must return one of the values of the PluginType enumeration,
which should match the type of the plugin. This function ensures that the
appropriate plugins are loaded for each renderer.
For an OpenGL plugin it should return Plugin_OpenGL.
For an XRender plugin it should return Plugin_XRender.
Prototype:
extern "C" FbCompositor::PluginType pluginType();
Plugin Classes
As mentioned above, all plugin objects must inherit some plugin classes.
There are three such classes, whose relationship is the following:
BasePlugin
^
+--------+--------+
| |
OpenGLPlugin XRenderPlugin
BasePlugin
All plugin objects will inherit this class.
This class requires the programmer to define the pluginName function, which
should return the name of the plugin. I highly recommend making sure that
this function returns the name of the plugin's library object. So, if your
plugin will be compiled into foobar.so, pluginName should return "foobar".
All the window* functions are called as soon as the appropriate events are
processed and should be used to keep track of the current window status.
setRoot* functions are called when changes occur to the root window. These
functions should be overriden as necessary.
The screen object and the string vector required by the constructor are
provided with the call to createPlugin function, detailed above.
This class also provides some accessors that may prove useful.
Relevant fbcompose classes: BaseCompWindow, BaseScreen.
OpenGLPlugin
If a plugin wants to work with OpenGL renderer, its objects must come from
a class that inherits OpenGLPlugin.
First, the plugin must return some vertex and fragment shader code. That
code must contain a function, whose name matches the return value of
pluginName function. So, if your plugin is named foobar, the corresponding
vertex shader code that would be
"void foobar() { /* SHADER CODE. */ }"
Even if you do not want to do anything with a particular shader, you must
still declare this shader function.
Attributes, uniforms and samplers can be declared as needed, but it is a
good idea to declare them only as necessary, since it is possible that GPUs
will hit their attribute/uniform/sampler limit with a large number of
plugins loaded. To avoid name clashes, name your
attributes/uniforms/whatever pluginName_VarName (eg. foobar_ShadowTexture,
to continue the previous example).
Rendering action functions fall into four groups:
* Initialization functions that should prepare the plugin shader code
before some part of the screen is rendered.
* Cleanup functions that should do whatever cleanup actions needed after
some part of the screen is rendered.
* Hooks for extra rendering jobs/actions.
* Null rendering job initialization. This function should make sure the
plugin will not interfere with the next rendering job.
The screen is rendered in this order: desktop background, windows,
reconfigure rectangle, extra jobs. The order of the functions within these
groups should be self-evident.
Extra rendering jobs are described with the OpenGLRenderingJob struct,
located in OpenGLPlugin.hh file. All extra jobs are in GL_TRIANGLE mode and
expect to be given four elements, as well as main and shape textures. The
OpenGLScreen object that can be accessed with the appropriate function in
OpenGLPlugin class provides some default buffers and textures, so you don't
have to explicitly create "null" OpenGL objects.
To obtain shader variable locations, extract them from a shader program
wrapper, that is passed to the plugin via initOpenGL function.
Relevant fbcompose classes: OpenGL*.
XRenderPlugin
For a plugin to work with the XRender backend, its objects must inherit the
XRenderPlugin class.
Rendering action functions fall into three groups:
* Plugin damaged area function.
* Initialization functions that can modify the how some particular part of
screen is rendered.
* Hooks for extra rendering jobs/actions.
The screen is rendered in this order: desktop background, windows,
reconfigure rectangle, extra jobs. The order of the functions within these
groups should be self-evident.
Damaged area function should return a vector of all the rectangles that
should be updated in the next frame, since the XRender backend only updates
the damaged areas for performance purposes. It is called before any
rendering is done.
Rendering jobs are described with the XRenderRenderingJob struct, located
in XRenderPlugin.hh file. It essentially contains all the parameters of the
XRenderComposite function. If operation equals PictOpClear, the rendering
job is ignored.
Plugin Distribution
In addition to sharing the source code of a plugin, you could also distribute
precompiled .so files, which the users simply have to place into an
appropriate directory to use them.
If you choose this option, do pay attention to your machine architecture. If
you can, try to provide both 32 bit and 64 bit binaries. If you are on a 64
bit machine, you can create a 32 bit binary with -m32 g++ flag, for example.
Miscellaneous Notes
* Make sure your plugin names begin with a letter and consist only of
alphanumeric characters and underscores. Also make sure that this name does
not match any of the keywords in GLSL and matches both the name of the .so
file and the string returned by the BaseScreen::pluginName function.
* It is not necessary to keep plugin rendering action function stateless, as
long as you keep in mind when and in what order the functions are called.
|