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 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>The GTK+ Drawing Model: GTK+ 3 Reference Manual</title>
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="index.html" title="GTK+ 3 Reference Manual">
<link rel="up" href="gtk.html" title="Part I. GTK+ Overview">
<link rel="prev" href="gtk-question-index.html" title="Common Questions">
<link rel="next" href="chap-input-handling.html" title="The GTK+ Input and Event Handling Model">
<meta name="generator" content="GTK-Doc V1.25.1 (XML mode)">
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="5"><tr valign="middle">
<td width="100%" align="left" class="shortcuts"></td>
<td><a accesskey="h" href="index.html"><img src="home.png" width="16" height="16" border="0" alt="Home"></a></td>
<td><a accesskey="u" href="gtk.html"><img src="up.png" width="16" height="16" border="0" alt="Up"></a></td>
<td><a accesskey="p" href="gtk-question-index.html"><img src="left.png" width="16" height="16" border="0" alt="Prev"></a></td>
<td><a accesskey="n" href="chap-input-handling.html"><img src="right.png" width="16" height="16" border="0" alt="Next"></a></td>
</tr></table>
<div class="refentry">
<a name="chap-drawing-model"></a><div class="titlepage"></div>
<div class="refnamediv"><table width="100%"><tr>
<td valign="top">
<h2><span class="refentrytitle">The GTK+ Drawing Model</span></h2>
<p>The GTK+ Drawing Model —
The GTK+ drawing model in detail
</p>
</td>
<td class="gallery_image" valign="top" align="right"></td>
</tr></table></div>
<div class="refsect1">
<a name="drawing-overview"></a><h2>Overview of the drawing model</h2>
<p>
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.
</p>
<div class="refsect2">
<a name="drawing%20model%20windows"></a><h3>Windows and events</h3>
<p>
Programs that run in a windowing system generally create
rectangular regions in the screen called
<em class="firstterm">windows</em>. 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 <em class="firstterm">exposure event</em> to the
program for that window.
</p>
<p>
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.
</p>
<p>
In practice, most windows in modern GTK+ application are client-side
constructs. Only few windows (in particular toplevel windows) are
<span class="emphasis"><em>native</em></span>, 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 <span class="type">Window</span>; on Win32,
it corresponds to a <span class="type">HANDLE</span>.
</p>
<p>
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 <a class="link" href="GtkEntry.html" title="GtkEntry"><code class="classname">GtkEntry</code></a>
widget, the entry asks GTK+ to queue a redraw operation for
itself.
</p>
<p>
The windowing system generates events for native windows. The GDK
interface to the windowing system translates such native events into
<a href="http://developer.gnome.org/gdk3/gdk4-Event-Structures.html#GdkEvent"><span class="structname">GdkEvent</span></a>
structures and sends them on to the GTK layer. In turn, the GTK layer
finds the widget that corresponds to a particular
<code class="classname">GdkWindow</code> and emits the corresponding event
signals on that widget.
</p>
<p>
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.
</p>
</div>
<hr>
<div class="refsect2">
<a name="frameclock"></a><h3>The frame clock</h3>
<p>
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:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem"><p>Events</p></li>
<li class="listitem"><p>Update</p></li>
<li class="listitem"><p>Layout</p></li>
<li class="listitem"><p>Paint</p></li>
</ul></div>
<p>
The phases happens in this order and we will always run each
phase through before going back to the start.
</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
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).
</p>
<p>
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:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem"><p>
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.
</p></li>
<li class="listitem"><p>
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.
</p></li>
<li class="listitem"><p>
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.
</p></li>
</ul></div>
<p>
There are also a lot of implicit triggers of these from the
CSS layer (which does animations, resizes and repaints as needed).
</p>
</div>
<hr>
<div class="refsect2">
<a name="hierarchical-drawing"></a><h3>Hierarchical drawing</h3>
<p>
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.
</p>
<p>
When generating the event, GDK also sets up double buffering to
avoid the flickering that would result from each widget drawing
itself in turn. <a class="xref" href="chap-drawing-model.html#double-buffering" title="Double buffering">the section called “Double buffering”</a> describes
the double buffering mechanism in detail.
</p>
<p>
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.
</p>
<p>
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.)
</p>
<p>
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.
</p>
</div>
<hr>
<div class="refsect2">
<a name="scrolling%20drawing%20model"></a><h3>Scrolling</h3>
<p>
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).
</p>
<p>
Since the above causes some overhead, we introduce a caching mechanism.
Containers that scroll a lot (GtkViewport, GtkTextView, GtkTreeView,
etc) allocate an offscreen image during scrolling and render their
children to it (which is possible since drawing is fully hierarchical).
The offscreen image is a bit larger than the visible area, so most of
the time when scrolling it just needs to draw the offscreen in a
different position. This matches contemporary graphics hardware much
better, as well as allowing efficient transparent backgrounds.
In order for this to work such containers need to detect when child
widgets are redrawn so that it can update the offscreen. This can be
done with the new gdk_window_set_invalidate_handler() function.
</p>
</div>
</div>
<div class="refsect1">
<a name="double-buffering"></a><h2>Double buffering</h2>
<p>
If each of the drawing calls made by each subwidget's
<code class="literal">draw</code> handler were sent directly to the
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 <em class="firstterm">double
buffering</em> 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.
</p>
<p>
Two basic functions in GDK form the core of the double-buffering
mechanism: <code class="function">gdk_window_begin_paint_region()</code>
and <code class="function">gdk_window_end_paint()</code>.
The first function tells a <code class="classname">GdkWindow</code> 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.
</p>
<div class="refsect2">
<a name="automatic-double-buffering"></a><h3>Automatic double buffering</h3>
<p>
It would be inconvenient for all widgets to call
<code class="function">gdk_window_begin_paint_region()</code> and
<code class="function">gdk_window_end_paint()</code> at the beginning
and end of their draw handlers.
</p>
<p>
To make this easier, GTK+ normally calls
<code class="function">gdk_window_begin_paint_region()</code>
before emitting the #GtkWidget::draw signal, and
then it calls <code class="function">gdk_window_end_paint()</code>
after the signal has been emitted. This is convenient for
most widgets, as they do not need to worry about creating
their own temporary drawing buffers or about calling those
functions.
</p>
<p>
However, some widgets may prefer to disable this kind of
automatic double buffering and do things on their own.
To do this, call the
<code class="function">gtk_widget_set_double_buffered()</code>
function in your widget's constructor. Double buffering
can only be turned off for widgets that have a native
window.
</p>
<div class="example">
<a name="disabling-double-buffering"></a><p class="title"><b>Example 5. Disabling automatic double buffering</b></p>
<div class="example-contents">
<table class="listing_frame" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td class="listing_lines" align="right"><pre>1
2
3
4
5
6
7
8
9</pre></td>
<td class="listing_code"><pre class="programlisting"><span class="gtkdoc kwb">static void</span>
<span class="function">my_widget_init</span> <span class="gtkdoc opt">(</span>MyWidget <span class="gtkdoc opt">*</span>widget<span class="gtkdoc opt">)</span>
<span class="gtkdoc opt">{</span>
<span class="gtkdoc opt">...</span>
<span class="function"><a href="GtkWidget.html#gtk-widget-set-double-buffered">gtk_widget_set_double_buffered</a></span> <span class="gtkdoc opt">(</span>widget<span class="gtkdoc opt">,</span> FALSE<span class="gtkdoc opt">);</span>
<span class="gtkdoc opt">...</span>
<span class="gtkdoc opt">}</span></pre></td>
</tr>
</tbody>
</table>
</div>
</div>
<br class="example-break"><p>
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 <span class="emphasis"><em>not</em></span> 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.
</p>
<p>
Even if you turn off double buffering on a widget, you
can still call
<code class="function">gdk_window_begin_paint_region()</code> and
<code class="function">gdk_window_end_paint()</code> by hand to use
temporary drawing buffers.
</p>
</div>
</div>
<div class="refsect1">
<a name="app-paintable-widgets"></a><h2>App-paintable widgets</h2>
<p>
Generally, applications use the pre-defined widgets in GTK+ and
they do not draw extra things on top of them (the exception
being <code class="classname">GtkDrawingArea</code>). However,
applications may sometimes find it convenient to draw directly
on certain widgets like toplevel windows or event boxes. When
this is the case, GTK+ needs to be told not to overwrite your
drawing afterwards, when the window gets to drawing its default
contents.
</p>
<p>
<code class="classname">GtkWindow</code> and
<code class="classname">GtkEventBox</code> are the two widgets that allow
turning off drawing of default contents by calling
<code class="function">gtk_widget_set_app_paintable()</code>. If you call
this function, they will not draw their contents and let you do
it instead.
</p>
<p>
Since the #GtkWidget::draw signal runs user-connected handlers
<span class="emphasis"><em>before</em></span> the widget's default handler, what
usually happens is this:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem"><p>
Your own draw handler gets run. It paints something
on the window or the event box.
</p></li>
<li class="listitem"><p>
The widget's default draw handler gets run. If
<code class="function">gtk_widget_set_app_paintable()</code> has not
been called to turn off widget drawing (this
is the default), <span class="emphasis"><em>your drawing will be
overwritten</em></span>. An app paintable widget will not
draw its default contents however and preserve your drawing
instead.
</p></li>
<li class="listitem"><p>
The draw handler for the parent class gets run.
Since both <code class="classname">GtkWindow</code> and
<code class="classname">GtkEventBox</code> are descendants of
<code class="classname">GtkContainer</code>, their no-window
children will be asked to draw themselves recursively, as
described in <a class="xref" href="chap-drawing-model.html#hierarchical-drawing" title="Hierarchical drawing">the section called “Hierarchical drawing”</a>.
</p></li>
</ol></div>
<p><b>Summary of app-paintable widgets. </b>
Call <code class="function">gtk_widget_set_app_paintable()</code> if you
intend to draw your own content directly on a
<code class="classname">GtkWindow</code> and
<code class="classname">GtkEventBox</code>. You seldom need to draw
on top of other widgets, and
<code class="classname">GtkDrawingArea</code> ignores this flag, as it
<span class="emphasis"><em>is</em></span> intended to be drawn on.
</p>
</div>
</div>
<div class="footer">
<hr>Generated by GTK-Doc V1.25.1</div>
</body>
</html>
|