418 lines
20 KiB
HTML
418 lines
20 KiB
HTML
<!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.29 (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
|
||
<span class="structname">GdkEvent</span>
|
||
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="keyword">static</span><span class="normal"> </span><span class="type">void</span>
|
||
<span class="function">my_widget_init</span><span class="normal"> </span><span class="symbol">(</span><span class="usertype">MyWidget</span><span class="normal"> </span><span class="symbol">*</span><span class="normal">widget</span><span class="symbol">)</span>
|
||
<span class="cbracket">{</span>
|
||
<span class="normal"> </span><span class="symbol">...</span>
|
||
|
||
<span class="normal"> </span><span class="function"><a href="GtkWidget.html#gtk-widget-set-double-buffered">gtk_widget_set_double_buffered</a></span><span class="normal"> </span><span class="symbol">(</span><span class="normal">widget</span><span class="symbol">,</span><span class="normal"> FALSE</span><span class="symbol">);</span>
|
||
|
||
<span class="normal"> </span><span class="symbol">...</span>
|
||
<span class="cbracket">}</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.29</div>
|
||
</body>
|
||
</html> |