]> Pileus Git - ~andy/gtk/blob - docs/reference/gtk/drawing-model.xml
7c0d20ea6a9536c0e26d2e24a540ca291abd50f3
[~andy/gtk] / docs / reference / gtk / drawing-model.xml
1 <?xml version="1.0"?>
2 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
3                "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
4 ]>
5 <refentry id="chap-drawing-model">
6 <refmeta>
7 <refentrytitle>The GTK+ Drawing Model</refentrytitle>
8 <manvolnum>3</manvolnum>
9 <refmiscinfo>GTK Library</refmiscinfo>
10 </refmeta>
11
12 <refnamediv>
13 <refname>The GTK+ Drawing Model</refname>
14 <refpurpose>
15     The GTK+ drawing model in detail
16 </refpurpose>
17 </refnamediv>
18
19
20   <refsect1 id="drawing-overview">
21     <title>Overview of the drawing model</title>
22
23     <para>
24       This chapter describes the GTK+ drawing model in detail.  If you
25       are interested in the procedure which GTK+ follows to draw its
26       widgets and windows, you should read this chapter; this will be
27       useful to know if you decide to implement your own widgets.  This
28       chapter will also clarify the reasons behind the ways certain
29       things are done in GTK+; for example, why you cannot change the
30       background color of all widgets with the same method.
31     </para>
32
33     <para>
34       Programs that run in a windowing system generally create
35       rectangular regions in the screen called
36       <firstterm>windows</firstterm>.  Traditional windowing systems
37       do not automatically save the graphical content of windows, and
38       instead ask client programs to repaint those windows whenever it
39       is needed.  For example, if a window that is stacked below other
40       windows gets raised to the top, then a client program has to
41       repaint the area that was previously obscured.  When the
42       windowing system asks a client program to redraw part of a
43       window, it sends an <firstterm>exposure event</firstterm> to the
44       program for that window.
45     </para>
46
47     <para>
48       Here, "windows" means "rectangular regions with automatic
49       clipping", instead of "toplevel application windows".  Most
50       windowing systems support nested windows, where the contents of
51       child windows get clipped by the boundaries of their parents.
52       Although GTK+ and GDK in particular may run on a windowing
53       system with no such notion of nested windows, GDK presents the
54       illusion of being under such a system.  A toplevel window may
55       contain many subwindows and sub-subwindows, for example, one for
56       the menu bar, one for the document area, one for each scrollbar,
57       and one for the status bar.  In addition, controls that receive
58       user input, such as clickable buttons, are likely to have their
59       own subwindows as well.
60     </para>
61
62     <para>
63       Generally, the drawing cycle begins when GTK+ receives an
64       exposure event from the underlying windowing system:  if the
65       user drags a window over another one, the windowing system will
66       tell the underlying window that it needs to repaint itself.  The
67       drawing cycle can also be initiated when a widget itself decides
68       that it needs to update its display.  For example, when the user
69       types a character in a <link
70       linkend="GtkEntry"><classname>GtkEntry</classname></link>
71       widget, the entry asks GTK+ to queue a redraw operation for
72       itself.
73     </para>
74
75     <para>
76       The following sections describe how GTK+ decides which widgets
77       need to be repainted, and how widgets work internally in terms
78       of the resources they use from the windowing system.
79     </para>
80
81     <refsect2 id="window-no-window-widgets">
82       <title>Window and no-window widgets</title>
83
84       <para>
85         A <link linkend="GdkWindow"><classname>GdkWindow</classname></link>
86         represents a window from the underlying windowing system on which GTK+
87         is running.  For example, on X11 it corresponds to a
88         <type>Window</type>; on Win32, it corresponds to a <type>HANDLE</type>.
89         The windowing system generates events for these windows.  The GDK
90         interface to the windowing system translates such native events into
91         <link linkend="GdkEvent"><structname>GdkEvent</structname></link>
92         structures and sends them on to the GTK layer.  In turn, the GTK layer
93         finds the widget that corresponds to a particular
94         <classname>GdkWindow</classname> and emits the corresponding event
95         signals on that widget.
96       </para>
97
98       <para>
99         When the program needs to redraw a region of a
100         <classname>GdkWindow</classname>, GDK generates an event of
101         type <link
102         linkend="GDK_EVENT_EXPOSE"><constant>GDK_EVENT_EXPOSE</constant></link>
103         for that window.  The GTK+ widget layer in turn finds the
104         widget that corresponds to that window, and emits the <link
105         linkend="GtkWidget-expose-event">expose-event signal</link>
106         for that widget.
107       </para>
108
109       <para>
110         In principle, each widget could have a
111         <classname>GdkWindow</classname> of its own.  With such a
112         scheme, the drawing cycle would be trivial:  when GDK notifies
113         the GTK layer about an exposure event for a
114         <classname>GdkWindow</classname>, the GTK layer would simply
115         emit the <link linkend="GtkWidget-expose-event">expose-event
116         signal</link> for that widget.  The widget's expose event
117         handler would subsequently repaint the widget.  No further
118         work would be necessary; the windowing system would generate
119         exposure events for each window that needs it, and then each
120         corresponding widget would draw itself in turn.
121       </para>
122
123       <para>
124         However, in practice it is convenient to have widgets which do
125         not have a <classname>GdkWindow</classname> of their own, but
126         rather share the one from their parent widget.  Such widgets
127         have the <constant>GTK_NO_WINDOW</constant> <link
128         linkend="GtkWidgetFlags">widget flag</link> turned on; this
129         can be tested easily with the <link
130         linkend="GTK-WIDGET-NO-WINDOW-CAPS"><function>GTK_WIDGET_NO_WINDOW()</function></link>
131         macro.  As such, these are called <firstterm>no-window
132         widgets</firstterm>.
133       </para>
134
135       <para>
136         No-window widgets are useful for various reasons:
137       </para>
138
139       <itemizedlist>
140         <listitem>
141           <para>
142             Some widgets may want the parent's background to show through, even
143             when they draw on parts of it.  For example, consider a theme that
144             uses textured backgrounds, such as gradients or repeating
145             patterns.  If each widget had its own window, and in turn its own
146             gradient background, labels would look bad because there would be a
147             visible break with respect to their surroundings.  <xref
148               linkend="figure-windowed-label"/> shows this undesirable effect.
149           </para>
150
151           <figure id="figure-windowed-label">
152             <title>Windowed label vs. no-window label</title>
153
154             <graphic fileref="figure-windowed-label.png" format="png"/>
155           </figure>
156         </listitem>
157
158         <listitem>
159           <para>
160             Reducing the number of windows creates less traffic between GTK+ and
161             the underlying windowing system, especially when getting events.
162           </para>
163         </listitem>
164       </itemizedlist>
165
166       <para>
167         On the other hand, widgets that would benefit from having a "hard"
168         clipping region may find it more convenient to create their own
169         windows.  Also, widgets which want to receive events resulting from
170         user interaction may find it convenient to use windows of their own as
171         well.  Widgets may have more than one window if they want to
172         define different regions for capturing events.
173       </para>
174     </refsect2>
175
176     <refsect2 id="hierarchical-drawing">
177       <title>Hierarchical drawing</title>
178
179       <para>
180         When the GTK layer receives an exposure event from GDK, it
181         finds the widget that corresponds to the window which received
182         the event.  By definition, this corresponds to a widget that
183         has the <constant>GTK_NO_WINDOW</constant> flag turned
184         <emphasis>off</emphasis> (otherwise, the widget wouldn't own
185         the window!).  First this widget paints its background, and
186         then, if it is a container widget, it tells each of its
187         <constant>GTK_NO_WINDOW</constant> children to paint
188         themselves.  This process is applied recursively for all the
189         <constant>GTK_NO_WINDOW</constant> descendants of the original
190         widget.
191       </para>
192
193       <para>
194         Note that this process does not get propagated to widgets
195         which have windows of their own, that is, to widgets which
196         have the <constant>GTK_NO_WINDOW</constant> flag turned off.
197         If such widgets require redrawing, then the windowing system
198         will already have sent exposure events to their corresponding
199         windows.  As such, there is no need to
200         <firstterm>propagate</firstterm> the exposure to them on the
201         GTK+ side.
202       </para>
203
204       <para>
205         <xref
206         linkend="figure-hierarchical-drawing"/> shows how a simple toplevel window would
207         paint itself when it contains only <constant>GTK_NO_WINDOW</constant> descendants:
208
209         <orderedlist>
210           <listitem>
211             <para>
212               The outermost, thick rectangle is a toplevel <link
213                 linkend="GtkWindow"><classname>GtkWindow</classname></link>,
214               which is not a <constant>GTK_NO_WINDOW</constant> widget &mdash;
215               as such, it does receive its exposure event as it comes from GDK.
216               First the <classname>GtkWindow</classname> would paint its own
217               background.  Then, it would ask its only child to paint itself,
218               numbered 2.
219             </para>
220           </listitem>
221           <listitem>
222             <para>
223               The dotted rectangle represents a <link
224                 linkend="GtkVBox"><classname>GtkVBox</classname></link>, which
225               has been made the sole child of the
226               <classname>GtkWindow</classname>.  Boxes are just layout
227               containers that do not paint anything by themselves, so this
228               <classname>GtkVBox</classname> would draw nothing, but rather ask
229               its children to draw themselves.  The children are numbered 3 and
230               6.
231             </para>
232           </listitem>
233           <listitem>
234             <para>
235               The thin rectangle is a <link
236                 linkend="GtkFrame"><classname>GtkFrame</classname></link>,
237               which has two children:  a label for the frame, numbered 4, and
238               another label inside, numbered 5.  First the frame would draw its
239               own beveled box, then ask the frame label and its internal child to
240               draw themselves.
241             </para>
242           </listitem>
243           <listitem>
244             <para>
245               The frame label has no children, so it just draws its text:  "Frame&nbsp;Label".
246             </para>
247           </listitem>
248           <listitem>
249             <para>
250               The internal label has no children, so it just draws its text:  "This
251               is some text inside the frame!".
252             </para>
253           </listitem>
254           <listitem>
255             <para>
256               The dotted rectangle represents a <link
257                 linkend="GtkHBox"><classname>GtkHBox</classname></link>.  Again,
258               this does not draw anything by itself, but rather asks its children
259               to draw themselves.  The children are numbered 7 and 9.
260             </para>
261           </listitem>
262           <listitem>
263             <para>
264               The thin rectangle is a <link
265                 linkend="GtkButton"><classname>GtkButton</classname></link> with
266               a single child, numbered 8.  First the button would draw its
267               beveled box, and then it would ask its child to draw itself.
268             </para>
269           </listitem>
270           <listitem>
271             <para>
272               This is a text label which has no children, so it just draws its
273               own text:  "Cancel".
274             </para>
275           </listitem>
276           <listitem>
277             <para>
278               Similar to number 7, this is a button with a single child, numbered
279               10.  First the button would draw its beveled box, and then it would
280               ask its child to draw itself.
281             </para>
282           </listitem>
283           <listitem>
284             <para>
285               Similar to number 8, this is a text label which has no children,
286               so it just draws its own text:  "OK".
287             </para>
288           </listitem>
289         </orderedlist>
290       </para>
291
292       <figure id="figure-hierarchical-drawing">
293         <title>Hierarchical drawing order</title>
294
295         <graphic fileref="figure-hierarchical-drawing.png" format="png"/>
296       </figure>
297
298       <para>
299         To avoid the flickering that would result from each widget drawing
300         itself in turn, GTK+ uses a double-buffering mechanism.  The following
301         sections describe this mechanism in detail.
302       </para>
303     </refsect2>
304
305     <refsect2 id="notes-on-drawing-no-window-widgets">
306       <title>Notes on drawing no-window widgets</title>
307
308       <para>
309         Remember that the coordinates in a <link
310         linkend="GdkEventExpose">GdkEventExpose</link> are relative to
311         the <classname>GdkWindow</classname> that received the event,
312         <emphasis>not</emphasis> to the widget whose expose-event
313         handler is being called.  If your widget owns the window, then
314         these coordinates are probably what you expect.  However, if
315         you have a <constant>GTK_NO_WINDOW</constant> widget that
316         shares its parent's window, then the event's coordinates will
317         be offset by your widget's allocation:  remember that the
318         allocation is always relative to the parent
319         <emphasis>window</emphasis> of the widget, not to the parent
320         <emphasis>widget</emphasis> itself.
321       </para>
322
323       <para>
324         For example, if you have a no-window widget whose allocation
325         is {&nbsp;x=5,&nbsp;y=6,
326         <replaceable>width</replaceable>,&nbsp;<replaceable>height</replaceable>&nbsp;},
327         then your drawing origin should be at (5,&nbsp;6), not at
328         (0,&nbsp;0).
329       </para>
330     </refsect2>
331
332     <refsect2 id="include-inferiors">
333       <title>Drawing over child windows</title>
334
335       <para>
336         When you draw on a <classname>GdkWindow</classname>, your
337         drawing gets clipped by any child windows that it may
338         intersect.  Sometimes you need to draw over your child windows
339         as well; for example, when drawing a drag-handle to resize
340         something.  In this case, turn on the <link
341         linkend="GDK-INCLUDE-INFERIORS:CAPS">GDK_INCLUDE_INFERIORS</link>
342         subwindow mode for the <link
343         linkend="gdk-Graphics-Contexts">GdkGC</link> which you use for
344         drawing.
345       </para>
346     </refsect2>
347   </refsect1>
348
349   <refsect1 id="double-buffering">
350     <title>Double buffering</title>
351
352     <para>
353       When the GTK layer receives an exposure event from GDK, it first finds
354       the <literal>!<constant>GTK_NO_WINDOW</constant></literal> widget that
355       corresponds to the event's window.  Then, it emits the <link
356         linkend="GtkWidget-expose-event">expose-event signal</link> for that
357       widget.  As described above, that widget will first draw its background,
358       and then ask each of its <constant>GTK_NO_WINDOW</constant> children to
359       draw themselves.
360     </para>
361
362     <para>
363       If each of the drawing calls made by each subwidget's
364       <literal>expose-event</literal> handler were sent directly to the
365       windowing system, flicker could result.  This is because areas may get
366       redrawn repeatedly:  the background, then decorative frames, then text
367       labels, etc.  To avoid flicker, GTK+ employs a <firstterm>double
368         buffering</firstterm> system at the GDK level.  Widgets normally don't
369       know that they are drawing to an off-screen buffer; they just issue their
370       normal drawing commands, and the buffer gets sent to the windowing system
371       when all drawing operations are done.
372     </para>
373
374     <!-- FIXME: figure with a timeline of non-double-buffered and
375          double-buffered paints:
376
377          onscreen:
378          [garbage]
379          [background]
380          [button-frame]
381          [icon]
382          [label]
383
384
385          onscreen:             offscreen:
386          [garbage]
387                                [background]
388                                [button-frame]
389                                [icon]
390                                [label]
391          [final result]
392     -->
393
394     <para>
395       Two basic functions in GDK form the core of the double-buffering
396       mechanism:  <link
397       linkend="gdk_window_begin_paint_region"><function>gdk_window_begin_paint_region()</function></link>
398       and <link
399       linkend="gdk_window_end_paint"><function>gdk_window_end_paint()</function></link>.
400       The first function tells a <classname>GdkWindow</classname> to
401       create a temporary off-screen buffer for drawing.  All
402       subsequent drawing operations to this window get automatically
403       redirected to that buffer.  The second function actually paints
404       the buffer onto the on-screen window, and frees the buffer.
405     </para>
406
407     <refsect2 id="automatic-double-buffering">
408       <title>Automatic double buffering</title>
409
410       <para>
411         It would be inconvenient for all widgets to call
412         <function>gdk_window_begin_paint_region()</function> and
413         <function>gdk_window_end_paint()</function> at the beginning
414         and end of their expose-event handlers.
415       </para>
416
417       <para>
418         To make this easier, most GTK+ widgets have the
419         <constant>GTK_DOUBLE_BUFFERED</constant> <link
420         linkend="GtkWidgetFlags">widget flag</link> turned on by
421         default.  When GTK+ encounters such a widget, it automatically
422         calls <function>gdk_window_begin_paint_region()</function>
423         before emitting the expose-event signal for the widget, and
424         then it calls <function>gdk_window_end_paint()</function>
425         after the signal has been emitted.  This is convenient for
426         most widgets, as they do not need to worry about creating
427         their own temporary drawing buffers or about calling those
428         functions.
429       </para>
430
431       <para>
432         However, some widgets may prefer to disable this kind of
433         automatic double buffering and do things on their own.  To do
434         this, turn off the <constant>GTK_DOUBLE_BUFFERED</constant>
435         flag in your widget's constructor.
436       </para>
437
438       <example id="disabling-double-buffering">
439         <title>Disabling automatic double buffering</title>
440
441         <programlisting>
442 static void
443 my_widget_init (MyWidget *widget)
444 {
445   ...
446
447   GTK_WIDGET_UNSET_FLAGS (widget, GTK_DOUBLE_BUFFERED);
448
449   ...
450 }
451         </programlisting>
452       </example>
453
454       <para>
455         When is it convenient to disable double buffering?  Generally,
456         this is the case only if your widget gets drawn in such a way
457         that the different drawing operations do not overlap each
458         other.  For example, this may be the case for a simple image
459         viewer:  it can just draw the image in a single operation.
460         This would <emphasis>not</emphasis> be the case with a word
461         processor, since it will need to draw and over-draw the page's
462         background, then the background for highlighted text, and then
463         the text itself.
464       </para>
465
466       <para>
467         Even if you turn off the
468         <constant>GTK_DOUBLE_BUFFERED</constant> flag on a widget, you
469         can still call
470         <function>gdk_window_begin_paint_region()</function> and
471         <function>gdk_window_end_paint()</function> by hand to use
472         temporary drawing buffers.
473       </para>
474     </refsect2>
475   </refsect1>
476
477   <refsect1 id="app-paintable-widgets">
478     <title>App-paintable widgets</title>
479
480     <para>
481       Generally, applications use the pre-defined widgets in GTK+ and
482       they do not draw extra things on top of them (the exception
483       being <classname>GtkDrawingArea</classname>).  However,
484       applications may sometimes find it convenient to draw directly
485       on certain widgets like toplevel windows or event boxes.  When
486       this is the case, GTK+ needs to be told not to overwrite your
487       drawing afterwards, when the window gets to drawing its default
488       contents.
489     </para>
490
491     <para>
492       <classname>GtkWindow</classname> and
493       <classname>GtkEventBox</classname> are the only two widgets
494       which will draw their default contents unless you turn on the
495       <constant>GTK_APP_PAINTABLE</constant> <link
496       linkend="GtkWidgetFlags">widget flag</link>.  If you turn on
497       this flag, then they will not draw their contents and let you do
498       it instead.
499     </para>
500
501     <para>
502       The expose-event handler for <classname>GtkWindow</classname> is
503       implemented effectively like this:
504     </para>
505
506     <programlisting>
507 static gint
508 gtk_window_expose (GtkWidget      *widget,
509                    GdkEventExpose *event)
510 {
511   if (!GTK_WIDGET_APP_PAINTABLE (widget))
512     gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
513                         GTK_SHADOW_NONE, event->area, widget, "base", 0, 0, -1, -1);
514
515   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event)
516     return GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event (widget, event);
517
518   return FALSE;
519 }
520     </programlisting>
521
522     <para>
523       The expose-event handler for <classname>GtkEventBox</classname>
524       is implemented in a similar fashion.
525     </para>
526
527     <para>
528       Since the <link linkend="GtkWidget-expose-event">expose-event
529         signal</link> runs user-connected handlers
530       <emphasis>before</emphasis> the widget's default handler, what
531       happens is this:
532     </para>
533
534     <orderedlist>
535       <listitem>
536         <para>
537           Your own expose-event handler gets run.  It paints something
538           on the window or the event box.
539         </para>
540       </listitem>
541
542       <listitem>
543         <para>
544           The widget's default expose-event handler gets run.  If
545           <constant>GTK_APP_PAINTABLE</constant> is turned off (this
546           is the default), <emphasis>your drawing will be
547           overwritten</emphasis>.  If that flag is turned on, the
548           widget will not draw its default contents and preserve your
549           drawing instead.
550         </para>
551       </listitem>
552
553       <listitem>
554         <para>
555           The expose-event handler for the parent class gets run.
556           Since both <classname>GtkWindow</classname> and
557           <classname>GtkEventBox</classname> are descendants of
558           <classname>GtkContainer</classname>, their no-window
559           children will be asked to draw themselves recursively, as
560           described in <xref linkend="hierarchical-drawing"/>.
561         </para>
562       </listitem>
563     </orderedlist>
564
565     <formalpara>
566       <title>Summary of app-paintable widgets</title>
567
568       <para>
569         Turn on the <constant>GTK_APP_PAINTABLE</constant> flag if you
570         intend to draw your own content directly on a
571         <classname>GtkWindow</classname> and
572         <classname>GtkEventBox</classname>.  You seldom need to draw
573         on top of other widgets, and
574         <classname>GtkDrawingArea</classname> ignores this flag, as it
575         <emphasis>is</emphasis> intended to be drawn on.
576       </para>
577     </formalpara>
578   </refsect1>
579 </refentry>
580
581 <!--
582 Local variables:
583 mode: xml
584 sgml-parent-document: ("gtk-docs.sgml" "book" "part" "refentry")
585 End:
586 -->