2008-11-21 08:21:28 +00:00
|
|
|
|
<?xml version="1.0"?>
|
|
|
|
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
|
|
|
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
|
|
|
|
]>
|
2008-12-26 06:41:23 +00:00
|
|
|
|
<refentry id="chap-drawing-model">
|
|
|
|
|
<refmeta>
|
|
|
|
|
<refentrytitle>The GTK+ Drawing Model</refentrytitle>
|
|
|
|
|
<manvolnum>3</manvolnum>
|
|
|
|
|
<refmiscinfo>GTK Library</refmiscinfo>
|
|
|
|
|
</refmeta>
|
|
|
|
|
|
|
|
|
|
<refnamediv>
|
|
|
|
|
<refname>The GTK+ Drawing Model</refname>
|
|
|
|
|
<refpurpose>
|
|
|
|
|
The GTK+ drawing model in detail
|
|
|
|
|
</refpurpose>
|
|
|
|
|
</refnamediv>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<refsect1 id="drawing-overview">
|
2008-10-29 18:59:40 +00:00
|
|
|
|
<title>Overview of the drawing model</title>
|
|
|
|
|
|
2008-12-26 06:41:23 +00:00
|
|
|
|
<para>
|
|
|
|
|
This chapter describes the GTK+ drawing model in detail. If you
|
|
|
|
|
are interested in the procedure which GTK+ follows to draw its
|
|
|
|
|
widgets and windows, you should read this chapter; this will be
|
|
|
|
|
useful to know if you decide to implement your own widgets. This
|
|
|
|
|
chapter will also clarify the reasons behind the ways certain
|
|
|
|
|
things are done in GTK+; for example, why you cannot change the
|
|
|
|
|
background color of all widgets with the same method.
|
|
|
|
|
</para>
|
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<refsect2 id="drawing model windows">
|
|
|
|
|
<title>Windows and events</title>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<para>
|
|
|
|
|
Programs that run in a windowing system generally create
|
|
|
|
|
rectangular regions in the screen called
|
|
|
|
|
<firstterm>windows</firstterm>. Traditional windowing systems
|
|
|
|
|
do not automatically save the graphical content of windows, and
|
|
|
|
|
instead ask client programs to repaint those windows whenever it
|
|
|
|
|
is needed. For example, if a window that is stacked below other
|
|
|
|
|
windows gets raised to the top, then a client program has to
|
|
|
|
|
repaint the area that was previously obscured. When the
|
|
|
|
|
windowing system asks a client program to redraw part of a
|
|
|
|
|
window, it sends an <firstterm>exposure event</firstterm> to the
|
|
|
|
|
program for that window.
|
|
|
|
|
</para>
|
2011-03-28 13:03:38 +00:00
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<para>
|
|
|
|
|
Here, "windows" means "rectangular regions with automatic
|
|
|
|
|
clipping", instead of "toplevel application windows". Most
|
|
|
|
|
windowing systems support nested windows, where the contents of
|
|
|
|
|
child windows get clipped by the boundaries of their parents.
|
|
|
|
|
Although GTK+ and GDK in particular may run on a windowing
|
|
|
|
|
system with no such notion of nested windows, GDK presents the
|
|
|
|
|
illusion of being under such a system. A toplevel window may
|
|
|
|
|
contain many subwindows and sub-subwindows, for example, one for
|
|
|
|
|
the menu bar, one for the document area, one for each scrollbar,
|
|
|
|
|
and one for the status bar. In addition, controls that receive
|
|
|
|
|
user input, such as clickable buttons, are likely to have their
|
|
|
|
|
own subwindows as well.
|
|
|
|
|
</para>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
In practice, most windows in modern GTK+ application are client-side
|
|
|
|
|
constructs. Only few windows (in particular toplevel windows) are
|
|
|
|
|
<emphasis>native</emphasis>, which means that they represent a
|
|
|
|
|
window from the underlying windowing system on which GTK+ is running.
|
|
|
|
|
For example, on X11 it corresponds to a <type>Window</type>; on Win32,
|
|
|
|
|
it corresponds to a <type>HANDLE</type>.
|
2011-03-28 13:03:38 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
Generally, the drawing cycle begins when GTK+ receives an
|
|
|
|
|
exposure event from the underlying windowing system: if the
|
|
|
|
|
user drags a window over another one, the windowing system will
|
|
|
|
|
tell the underlying window that it needs to repaint itself. The
|
|
|
|
|
drawing cycle can also be initiated when a widget itself decides
|
|
|
|
|
that it needs to update its display. For example, when the user
|
|
|
|
|
types a character in a <link
|
|
|
|
|
linkend="GtkEntry"><classname>GtkEntry</classname></link>
|
|
|
|
|
widget, the entry asks GTK+ to queue a redraw operation for
|
|
|
|
|
itself.
|
2011-03-28 13:03:38 +00:00
|
|
|
|
</para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
|
2011-03-28 13:03:38 +00:00
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
The windowing system generates events for native windows. The GDK
|
|
|
|
|
interface to the windowing system translates such native events into
|
|
|
|
|
<link linkend="GdkEvent"><structname>GdkEvent</structname></link>
|
|
|
|
|
structures and sends them on to the GTK layer. In turn, the GTK layer
|
|
|
|
|
finds the widget that corresponds to a particular
|
|
|
|
|
<classname>GdkWindow</classname> and emits the corresponding event
|
|
|
|
|
signals on that widget.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
The following sections describe how GTK+ decides which widgets
|
|
|
|
|
need to be repainted in response to such events, and how widgets
|
|
|
|
|
work internally in terms of the resources they use from the
|
|
|
|
|
windowing system.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
2011-03-28 13:03:38 +00:00
|
|
|
|
</refsect2>
|
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<refsect2 id="frameclock">
|
|
|
|
|
<title>The frame clock</title>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
All GTK+ applications are mainloop-driven, which means that most
|
|
|
|
|
of the time the app is idle inside a loop that just waits for
|
|
|
|
|
something to happen and then calls out to the right place when
|
|
|
|
|
it does. On top of this GTK+ has a frame clock that gives a
|
|
|
|
|
“pulse” to the application. This clock beats at a steady rate,
|
|
|
|
|
which is tied to the framerate of the output (this is synced to
|
|
|
|
|
the monitor via the window manager/compositor). The clock has
|
|
|
|
|
several phases:
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem><para>Events</para></listitem>
|
|
|
|
|
<listitem><para>Update</para></listitem>
|
|
|
|
|
<listitem><para>Layout</para></listitem>
|
|
|
|
|
<listitem><para>Paint</para></listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
The phases happens in this order and we will always run each
|
|
|
|
|
phase through before going back to the start.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
The Events phase is a long stretch of time between each
|
|
|
|
|
redraw where we get input events from the user and other events
|
|
|
|
|
(like e.g. network I/O). Some events, like mouse motion are
|
|
|
|
|
compressed so that we only get a single mouse motion event per
|
|
|
|
|
clock cycle.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
Once the Events phase is over we pause all external events and
|
|
|
|
|
run the redraw loop. First is the Update phase, where all
|
|
|
|
|
animations are run to calculate the new state based on the
|
|
|
|
|
estimated time the next frame will be visible (available via
|
|
|
|
|
the frame clock). This often involves geometry changes which
|
|
|
|
|
drives the next phase, Layout. If there are any changes in
|
|
|
|
|
widget size requirements we calculate a new layout for the
|
|
|
|
|
widget hierarchy (i.e. we assign sizes and positions). Then
|
|
|
|
|
we go to the Paint phase where we redraw the regions of the
|
|
|
|
|
window that need redrawing.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<para>
|
|
|
|
|
If nothing requires the Update/Layout/Paint phases we will
|
|
|
|
|
stay in the Events phase forever, as we don’t want to redraw
|
|
|
|
|
if nothing changes. Each phase can request further processing
|
|
|
|
|
in the following phases (e.g. the Update phase will cause there
|
|
|
|
|
to be layout work, and layout changes cause repaints).
|
|
|
|
|
</para>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
There are multiple ways to drive the clock, at the lowest level
|
|
|
|
|
you can request a particular phase with
|
|
|
|
|
gdk_frame_clock_request_phase() which will schedule a clock beat
|
|
|
|
|
as needed so that it eventually reaches the requested phase.
|
|
|
|
|
However, in practice most things happen at higher levels:
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem><para>
|
|
|
|
|
If you are doing an animation, you can use
|
|
|
|
|
gtk_widget_add_tick_callback() which will cause a regular
|
|
|
|
|
beating of the clock with a callback in the Update phase
|
|
|
|
|
until you stop the tick.
|
|
|
|
|
</para></listitem>
|
|
|
|
|
<listitem><para>
|
|
|
|
|
If some state changes that causes the size of your widget
|
|
|
|
|
to change you call gtk_widget_queue_resize() which will
|
|
|
|
|
request a Layout phase and mark your widget as needing
|
|
|
|
|
relayout.
|
|
|
|
|
</para></listitem>
|
|
|
|
|
<listitem><para>
|
|
|
|
|
If some state changes so you need to redraw some area of
|
|
|
|
|
your widget you use the normal gtk_widget_queue_draw()
|
|
|
|
|
set of functions. These will request a Paint phase and
|
|
|
|
|
mark the region as needing redraw.
|
|
|
|
|
</para></listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
There are also a lot of implicit triggers of these from the
|
|
|
|
|
CSS layer (which does animations, resizes and repaints as needed).
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
2008-12-26 06:41:23 +00:00
|
|
|
|
</refsect2>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2008-12-26 06:41:23 +00:00
|
|
|
|
<refsect2 id="hierarchical-drawing">
|
2008-10-29 18:59:40 +00:00
|
|
|
|
<title>Hierarchical drawing</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
During the Paint phase we will send a single expose event to
|
|
|
|
|
the toplevel window. The event handler will create a cairo
|
|
|
|
|
context for the window and emit a GtkWidget::draw() signal
|
|
|
|
|
on it, which will propagate down the entire widget hierarchy
|
|
|
|
|
in back-to-front order, using the clipping and transform of
|
|
|
|
|
the cairo context. This lets each widget draw its content at
|
|
|
|
|
the right place and time, correctly handling things like
|
|
|
|
|
partial transparencies and overlapping widgets.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
When generating the event, GDK also sets up double buffering to
|
|
|
|
|
avoid the flickering that would result from each widget drawing
|
|
|
|
|
itself in turn. <xref linkend="double-buffering"/> describes
|
|
|
|
|
the double buffering mechanism in detail.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Normally, there is only a single cairo context which is used in
|
|
|
|
|
the entire repaint, rather than one per GdkWindow. This means you
|
|
|
|
|
have to respect (and not reset) existing clip and transformations
|
|
|
|
|
set on it.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
Most widgets, including those that create their own GdkWindows have
|
|
|
|
|
a transparent background, so they draw on top of whatever widgets
|
|
|
|
|
are below them. This was not the case in GTK+ 2 where the theme set
|
|
|
|
|
the background of most widgets to the default background color. (In
|
|
|
|
|
fact, transparent GdkWindows used to be impossible.)
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
The whole rendering hierarchy is captured in the call stack, rather
|
|
|
|
|
than having multiple separate draw emissions, so you can use effects
|
|
|
|
|
like e.g. cairo_push/pop_group() which will affect all the widgets
|
|
|
|
|
below you in the hierarchy. This makes it possible to have e.g.
|
|
|
|
|
partially transparent containers.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
</refsect2>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<refsect2 id="scrolling drawing model">
|
|
|
|
|
<title>Scrolling</title>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2013-11-10 08:25:48 +00:00
|
|
|
|
<para>
|
|
|
|
|
Traditionally, GTK+ has used self-copy operations to implement
|
|
|
|
|
scrolling with native windows. With transparent backgrounds, this
|
|
|
|
|
no longer works. Instead, we just mark the entire affected area for
|
|
|
|
|
repainting when these operations are used. This allows (partially)
|
|
|
|
|
transparent backgrounds, and it also more closely models modern
|
|
|
|
|
hardware where self-copy operations are problematic (they break the
|
|
|
|
|
rendering pipeline).
|
|
|
|
|
</para>
|
2008-12-26 06:41:23 +00:00
|
|
|
|
</refsect2>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2008-12-26 06:41:23 +00:00
|
|
|
|
</refsect1>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2008-12-26 06:41:23 +00:00
|
|
|
|
<refsect1 id="double-buffering">
|
2008-10-29 18:59:40 +00:00
|
|
|
|
<title>Double buffering</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
If each of the drawing calls made by each subwidget's
|
2011-03-28 13:03:38 +00:00
|
|
|
|
<literal>draw</literal> handler were sent directly to the
|
2008-10-29 18:59:40 +00:00
|
|
|
|
windowing system, flicker could result. This is because areas may get
|
|
|
|
|
redrawn repeatedly: the background, then decorative frames, then text
|
|
|
|
|
labels, etc. To avoid flicker, GTK+ employs a <firstterm>double
|
|
|
|
|
buffering</firstterm> system at the GDK level. Widgets normally don't
|
|
|
|
|
know that they are drawing to an off-screen buffer; they just issue their
|
|
|
|
|
normal drawing commands, and the buffer gets sent to the windowing system
|
|
|
|
|
when all drawing operations are done.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Two basic functions in GDK form the core of the double-buffering
|
|
|
|
|
mechanism: <link
|
|
|
|
|
linkend="gdk_window_begin_paint_region"><function>gdk_window_begin_paint_region()</function></link>
|
|
|
|
|
and <link
|
|
|
|
|
linkend="gdk_window_end_paint"><function>gdk_window_end_paint()</function></link>.
|
|
|
|
|
The first function tells a <classname>GdkWindow</classname> to
|
|
|
|
|
create a temporary off-screen buffer for drawing. All
|
|
|
|
|
subsequent drawing operations to this window get automatically
|
|
|
|
|
redirected to that buffer. The second function actually paints
|
|
|
|
|
the buffer onto the on-screen window, and frees the buffer.
|
|
|
|
|
</para>
|
|
|
|
|
|
2008-12-26 06:41:23 +00:00
|
|
|
|
<refsect2 id="automatic-double-buffering">
|
2008-10-29 18:59:40 +00:00
|
|
|
|
<title>Automatic double buffering</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
It would be inconvenient for all widgets to call
|
|
|
|
|
<function>gdk_window_begin_paint_region()</function> and
|
|
|
|
|
<function>gdk_window_end_paint()</function> at the beginning
|
2011-03-28 13:03:38 +00:00
|
|
|
|
and end of their draw handlers.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
To make this easier, GTK+ normally calls
|
|
|
|
|
<function>gdk_window_begin_paint_region()</function>
|
|
|
|
|
before emitting the #GtkWidget::draw signal, and
|
2008-10-29 18:59:40 +00:00
|
|
|
|
then it calls <function>gdk_window_end_paint()</function>
|
2013-11-10 08:25:48 +00:00
|
|
|
|
after the signal has been emitted. This is convenient for
|
2008-10-29 18:59:40 +00:00
|
|
|
|
most widgets, as they do not need to worry about creating
|
|
|
|
|
their own temporary drawing buffers or about calling those
|
|
|
|
|
functions.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
However, some widgets may prefer to disable this kind of
|
2013-11-10 08:25:48 +00:00
|
|
|
|
automatic double buffering and do things on their own.
|
|
|
|
|
To do this, call the
|
|
|
|
|
<function>gtk_widget_set_double_buffered()</function>
|
|
|
|
|
function in your widget's constructor. Double buffering
|
|
|
|
|
can only be turned off for widgets that have a native
|
|
|
|
|
window.
|
2008-10-29 18:59:40 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<example id="disabling-double-buffering">
|
|
|
|
|
<title>Disabling automatic double buffering</title>
|
|
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
|
static void
|
|
|
|
|
my_widget_init (MyWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
...
|
|
|
|
|
|
2010-03-01 17:14:05 +00:00
|
|
|
|
gtk_widget_set_double_buffered (widget, FALSE);
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
</programlisting>
|
|
|
|
|
</example>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
When is it convenient to disable double buffering? Generally,
|
|
|
|
|
this is the case only if your widget gets drawn in such a way
|
|
|
|
|
that the different drawing operations do not overlap each
|
|
|
|
|
other. For example, this may be the case for a simple image
|
|
|
|
|
viewer: it can just draw the image in a single operation.
|
|
|
|
|
This would <emphasis>not</emphasis> be the case with a word
|
|
|
|
|
processor, since it will need to draw and over-draw the page's
|
|
|
|
|
background, then the background for highlighted text, and then
|
|
|
|
|
the text itself.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
2011-03-28 13:03:38 +00:00
|
|
|
|
Even if you turn off double buffering on a widget, you
|
2008-10-29 18:59:40 +00:00
|
|
|
|
can still call
|
|
|
|
|
<function>gdk_window_begin_paint_region()</function> and
|
|
|
|
|
<function>gdk_window_end_paint()</function> by hand to use
|
|
|
|
|
temporary drawing buffers.
|
|
|
|
|
</para>
|
2008-12-26 06:41:23 +00:00
|
|
|
|
</refsect2>
|
|
|
|
|
</refsect1>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
2008-12-26 06:41:23 +00:00
|
|
|
|
</refentry>
|
2008-10-29 18:59:40 +00:00
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
Local variables:
|
|
|
|
|
mode: xml
|
2008-12-26 06:41:23 +00:00
|
|
|
|
sgml-parent-document: ("gtk-docs.sgml" "book" "part" "refentry")
|
2008-10-29 18:59:40 +00:00
|
|
|
|
End:
|
|
|
|
|
-->
|