[Bf-committers] Blender Window manager doc
Ton Roosendaal
ton at blender.org
Fri Dec 3 14:54:12 CET 2004
Hi,
Checking on a bug report I noticed again the flaws in the python Window
module...
This module was added sometime long ago, and expanded with calls
later... it has become one of the most popular modules to play with,
but its design really conflicts with how Blender's window manager is
intended to work.
This - of course - as a result of a total lack of any documentation on
this issue, something that should be solved once. So here we go! :)
1) Screens/Areas/Windows
Blender has its own full functional window manager. The subdividision
UI concept Blender was based on demanded development of such a system.
On the top level of the window manager you can find the "Screen", which
actually just is the "window" in the OS Desktop environment. The Screen
again is subdivided into "Areas", which act as a "sub window". (Back
then I've choosen the words "Screen" and "Area" mostly to prevent
confusement with much the abused word "window".)
In the very first incarnation of Blender (1.0) control over drawing of
Areas was left to the "sub window" feature the Irix window manager
offered. This is available in X11 and other windowmangers too btw.
After a while I decided to drop this, mostly because using many
sub-windows within a main window is handled extremely slow. Speed is
comparable to a single application trying to manage like 10-20 separate
windows, causing a lot of system overhead. One full redraw of a new
Screen setup took seconds (a slowness you can now still watch in Modo
btw, they apparently didn't copy Blender completely yet ;-).
Instead I found a way to completely mimic sub-windows with OpenGL
features. By using the glScissor() and glViewPort() combo you can
effectively achieve that. Code for that resides in the src/mywindow.c
file. Note that there you find still find wrappers for the former
sub-window system, introducing a 'bWindow' layer.
So in this stage, the first confusion was already introduced, mixing up
"Area" features with "bWindow" ones... and to make the whole system
even more interesting, the port to Glut was added on top of that again,
and later on the port to Ghost. The wrapping from "bWindow" to
GhostWindow is done with another "Window" being defined in
ghostwinlay.c. So we now have the very interesting series of wrappers:
System Window <-> GHOST_Window <-> Window <-> bWindow <->
ScrArea
(OS specific) (Ghost lib) (ghostwinlay.c) (mywindow.c)
(editscreen.c)
Especially the way how the renderwindow is hacked into this system is a
total nightmare, with even code comments like "Do not ever release this
after 2.23!"). This was part of a restructuring process never even
finished...
The obvious wrapper series should be something like this:
System Window <-> GHOST_Window <-> Screen
Making the "render output window" just an Area in a Screen, or as a new
(system) Window with a Screen, and thus allowing multiple Screens to be
opened in separate windows (dual monitor purpose for example).
2) Areas and Spaces
Within the Blender universe the "active window" therefore is just the
active Area, the part within the subdivided Screen where input goes to
or output has to be drawn. The editscreen.c code manages this, defining
which area is currently active for input, and what areas need to be
redrawn, and in what situations a full or partial swapbuffers should be
done.
For that reason Areas have their own event queues, and (function
pointers) callbacks for queue handling and drawing. The Screen system
reads the main queues, distributes it to the areas, executes the queue
callbacks, and for proper swapbuffering also can execute redraws.
This all goes well balanced, buffering queue overloading to prevent 100
redraws to be executed 100 times as well.
The Blender "Space" is another new definition to prevent the word
"window". Decided was to fully separate the application that runs
within an Area from the Screen/Area system itself. This allows each
Area to transparently run any application, which is an important
feature in Blender (changing "window" type). A space is simply
definined by the following items;
- a SpaceXXX struct to hold persistant data. Data that's relevant for
saving in a file, for copying or restoring.
- functions to allocate, free or copy SpaceXXX structs
- a winhandle() callback for handling the Area events
- a windraw() callback for the full (re)drawing
- a winchange() callback for reinitializing windowsize or other changes
Each area is allowed to store a SpaceXXX struct for each Space type (in
a list), which enables proper restoring when applications change in an
area. For example when you invoke the SpaceFile, it can safely return
to its previous SpaceView3D type without any change in its settings.
Another important aspect is that any Space is supposed to run fully
local. It is not (should not) be aware of any other editors that are
open, nor read data from it, nor access them to change data. The Spaces
should be treated as individual applications, storing settings in their
own SpaceXXX structs, and only working on what the Blender database is
providing, or what the Screen defines to be the active context (like
active Scene, Object, etc).
(Read the notes on the Blender architecture for more about this).
There's still no good protocol or document on adding new Space types,
but in theory it is possible to hook up any application with Blender
this way. Using the callback structure it can even be plug-inned...
think for example what would happen to have a web browser or text
editor or terminal running there. Your own deskop environment! :)
Blender is far from perfect, so you can also find ancient abuses of the
system, especially in using global settings... like for example Edit
Mode or FaceSelect. The implementation of tools in the Buttons window
is another exception, the tools actually work in a 3d window, but are
accessed from another Space type. Cleaning up such issues is also part
of the 2.3 UI project, with attempts to keep the used context as clean
as obvious as possible.
In most situations it works well though, with individual Spaces only
communicating with each other by sending out events to the Screen
manager, which distributes it over the other Areas again.
3) The ugly struct Global
The goal of any good structured program is to limit usage of global
variables to an absolute minimum (yes, lessons learnt :). One reason
why it's good to have them in struct Global is as punishment, since it
forces a full recompile. Another reason is to keep things together that
way, prevents unpleasant surprises.
Since - right now - only 1 screen is in use or displayed in a time,
Blender's Screen manager puts "helpful" global variables in the G
struct too.
What you can see all over the code is usage of "G.vd" or "G.sipo" and
so on... these are the pointers to the *active* SpaceXXX structure, and
is being set by the Screen manager on mousemoves and when the Areas
handle their queues or redraws.
Any code that uses these variables has to be 100% certain belong to its
own Space type. No G.vd (View3D) access should be allowed in Buttons,
or Fileselect, or Script space, since that's undefined then (or can
even be zero). It's a common mistake in Blender code - I even violated
it sometimes - and it always were reasons for bugs or crashes. The
Python Window module also abuses that, and this should be removed
a.s.a.p. :)
These variables actually belong to the "Screen context", and will be
recoded to go there once.
4) How to move on
There's clearly work to be done on the following areas:
- remove the ridiculous 5 level deep wrapping of the "window" concept.
- design a new method for Spaces to handle queues (using dynamic event
handlers)
- design a method for how Python scripts can be attached to any Space
type (probably by just becoming an event handler!)
So, that's the lecture for today, back to the bugs! :)
-Ton-
------------------------------------------------------------------------
--
Ton Roosendaal Blender Foundation ton at blender.org
http://www.blender.org
More information about the Bf-committers
mailing list