Преглед на файлове

+ First complete version of article

michael преди 24 години
родител
ревизия
b75e34ff07
променени са 1 файла, в които са добавени 905 реда и са изтрити 58 реда
  1. 905 58
      docs/gtk5.tex

+ 905 - 58
docs/gtk5.tex

@@ -56,9 +56,10 @@ realized (i.e. when the window handle is created.)
 
 
 The widget has only 1 method: \var{gtk\_drawing\_area\_size}, which sets
 The widget has only 1 method: \var{gtk\_drawing\_area\_size}, which sets
 the size of the drawing area. It is defined as follows:
 the size of the drawing area. It is defined as follows:
-\begin{verbatim}
-procedure gtk_drawing_area_size(Area:PGtkDrawingArea; width:gint;height:gint) 
-\end{verbatim}
+\begin{lstlisting}{}
+procedure gtk_drawing_area_size(Area:PGtkDrawingArea;
+                                width,height:gint)
+\end{lstlisting}{}
 The arguments to this function are self-explaining.
 The arguments to this function are self-explaining.
 
 
 To use the drawing area widget, one should respond to the 'expose\_event'.
 To use the drawing area widget, one should respond to the 'expose\_event'.
@@ -81,7 +82,7 @@ used etc.
 The Graphics Context is an opaque record, and its members cannot be
 The Graphics Context is an opaque record, and its members cannot be
 accessed. The relevant parameters are set in a \var{TGdkGCValues} record,
 accessed. The relevant parameters are set in a \var{TGdkGCValues} record,
 which is defined as follows:
 which is defined as follows:
-\begin{verbatim}
+\begin{lstlisting}{}
 foreground : TGdkColor;
 foreground : TGdkColor;
 background : TGdkColor;
 background : TGdkColor;
 font : PGdkFont;
 font : PGdkFont;
@@ -100,7 +101,7 @@ line_width : gint;
 line_style : TGdkLineStyle;
 line_style : TGdkLineStyle;
 cap_style : TGdkCapStyle;
 cap_style : TGdkCapStyle;
 join_style : TGdkJoinStyle;
 join_style : TGdkJoinStyle;
-\end{verbatim}
+\end{lstlisting}{}
 The \var{ForeGround} and \var{Background} parameters determine the foreground
 The \var{ForeGround} and \var{Background} parameters determine the foreground
 and background colors. \var{Font} is the default font. The \var{Fill} field
 and background colors. \var{Font} is the default font. The \var{Fill} field
 describes how areas are filled. It can be one of the following:
 describes how areas are filled. It can be one of the following:
@@ -148,17 +149,17 @@ to the RGB-specified color, the GDK uses a colormap, and allocates a
 color that matches the closest to the specified color values. 
 color that matches the closest to the specified color values. 
 When allocating a new color, the colormap should be specified.
 When allocating a new color, the colormap should be specified.
 
 
-A colormap can be obtained from a \var{TGTKWidget} object using the
-\var{gtk\_widget\_get\_colormap} function; A color can then be allocated
-using the \var{gdk\_colormap\_alloc\_color} function:
-\begin{verbatim}
+A colormap can be obtained from a \var{TGTKWidget} descdendant using the GTK function
+\var{gtk\_widget\_get\_colormap}; A color can then be allocated
+using the following \var{gdk\_colormap\_alloc\_color} function:
+\begin{lstlisting}{}
 function gdk_colormap_alloc_color(colormap:PGdkColormap; 
 function gdk_colormap_alloc_color(colormap:PGdkColormap; 
                                   color:PGdkColor;
                                   color:PGdkColor;
                                   writeable:gboolean; 
                                   writeable:gboolean; 
                                   best_match:gboolean):gboolean;
                                   best_match:gboolean):gboolean;
-\end{verbatim}
-The \var{writeable} parameter specifies whether changes in the
-\var{color} using \var{gdk\_color\_change} are allowed.
+\end{lstlisting}{}
+The \var{writeable} parameter specifies whether changes to
+\var{color} using \var{gdk\_color\_change} are allowed. 
 \var{best\_match} specifies whether a best match should be attempted 
 \var{best\_match} specifies whether a best match should be attempted 
 on existing colors or an exact value is required.
 on existing colors or an exact value is required.
 The function returns \var{True} if the allocation succeeded, 
 The function returns \var{True} if the allocation succeeded, 
@@ -175,11 +176,11 @@ can be a pointer to a \var{TGDKWindow} or a \var{TGDkPixmap}, and a
 \var{PGdkGC}, a pointer to a graphics context. 
 \var{PGdkGC}, a pointer to a graphics context. 
 
 
 These parameters are omitted from the following declarations:
 These parameters are omitted from the following declarations:
-\begin{verbatim}
+\begin{lstlisting}{}
 procedure gdk_draw_point(x,y:gint);
 procedure gdk_draw_point(x,y:gint);
 procedure gdk_draw_line(x1,y1,x2,y2:gint);
 procedure gdk_draw_line(x1,y1,x2,y2:gint);
 procedure gdk_draw_rectangle(filled,x,y,width,height:gint);
 procedure gdk_draw_rectangle(filled,x,y,width,height:gint);
-\end{verbatim}
+\end{lstlisting}{}
 The above functions draw respectively a dot, a line and a rectangle.
 The above functions draw respectively a dot, a line and a rectangle.
 The meaning of the parameters for these functions is obvious.
 The meaning of the parameters for these functions is obvious.
 For the rectangle, care must be taken. If the parameter \var{Filled} is 
 For the rectangle, care must be taken. If the parameter \var{Filled} is 
@@ -187,12 +188,12 @@ False (-1) then the drawn rectangle has actually a width and height of
 \var{Width+1}, \var{Height+1}. If it is filled, then the width and 
 \var{Width+1}, \var{Height+1}. If it is filled, then the width and 
 height are as specified in the call to \var{gdk\_draw\_rectangle}.
 height are as specified in the call to \var{gdk\_draw\_rectangle}.
 
 
-The following functions can be used to draw a series of lines:
-\begin{verbatim}
+The following procedures can be used to draw a series of lines:
+\begin{lstlisting}{}
 procedure gdk_draw_polygon(filled:gint;points:PGdkPoint; npoints:gint);
 procedure gdk_draw_polygon(filled:gint;points:PGdkPoint; npoints:gint);
 procedure gdk_draw_lines(points:PGdkPoint; npoints:gint);
 procedure gdk_draw_lines(points:PGdkPoint; npoints:gint);
 procedure gdk_draw_segments(segs:PGdkSegment; nsegs:gint);
 procedure gdk_draw_segments(segs:PGdkSegment; nsegs:gint);
-\end{verbatim}
+\end{lstlisting}{}
 The \var{gdk\_draw\_polygon} polygon takes a series of dots and connects 
 The \var{gdk\_draw\_polygon} polygon takes a series of dots and connects 
 them using lines, optionally filling them. The points are specified by a
 them using lines, optionally filling them. The points are specified by a
 pointer to an array of \var{TGDKPoint} records (there should be \var{npoint}
 pointer to an array of \var{TGDKPoint} records (there should be \var{npoint}
@@ -210,9 +211,10 @@ connected.
 
 
 The \var{gdk\_draw\_arc} can be used to draw a circle or a segment of
 The \var{gdk\_draw\_arc} can be used to draw a circle or a segment of
 the circle, or an ellipse.
 the circle, or an ellipse.
-\begin{verbatim}
-procedure gdk_draw_arc(filled,x,y,width,height,angle1,angle2 : gint);
-\end{verbatim}
+\begin{lstlisting}{}
+procedure gdk_draw_arc(filled,x,y,width,height,
+                       angle1,angle2 : gint);
+\end{lstlisting}{}
 The \var{x,y, width} and \var{height} parameters describe a bounding
 The \var{x,y, width} and \var{height} parameters describe a bounding
 rectangle for the circle. The angles describe the start and extending 
 rectangle for the circle. The angles describe the start and extending 
 angle of the segment to be drawn: The circle segment starts at angle
 angle of the segment to be drawn: The circle segment starts at angle
@@ -226,17 +228,17 @@ the circle centre, and filled, in effect drawing a pie-slice.
 
 
 Finally, for the \var{gdk\_draw\_string} function, the graphics context comes
 Finally, for the \var{gdk\_draw\_string} function, the graphics context comes
 before the graphics context:
 before the graphics context:
-\begin{verbatim}
-procedure gdk_draw_string(drawable:PGdkDrawable; font:PGdkFont; gc:PGdkGC;
-                          x:gint; y:gint; thestring:Pgchar);
-\end{verbatim}
+\begin{lstlisting}{}
+procedure gdk_draw_string(drawable:PGdkDrawable; font:PGdkFont; 
+                         gc:PGdkGC; x,y:gint; thestring:Pgchar);
+\end{lstlisting}{}
 The meaning of the parameters for this functions should be obvious.
 The meaning of the parameters for this functions should be obvious.
 
 
 The font for the \var{gdk\_draw\_string} can be obtained using the
 The font for the \var{gdk\_draw\_string} can be obtained using the
 \var{gdk\_font\_load} function:
 \var{gdk\_font\_load} function:
-\begin{verbatim}
-  function gdk_font_load(font_name:Pgchar):PGdkFont;
-\end{verbatim}
+\begin{lstlisting}{}
+function gdk_font_load(font_name:Pgchar):PGdkFont;
+\end{lstlisting}{}
 The font name should be specified as an X font path.
 The font name should be specified as an X font path.
 
 
 All this is demonstrated in the following program:
 All this is demonstrated in the following program:
@@ -293,6 +295,9 @@ Const
   capstyles : Array[1..5] of TgdkCapStyle = 
   capstyles : Array[1..5] of TgdkCapStyle = 
           (GDK_CAP_ROUND,GDK_CAP_NOT_LAST, GDK_CAP_BUTT,  
           (GDK_CAP_ROUND,GDK_CAP_NOT_LAST, GDK_CAP_BUTT,  
            GDK_CAP_PROJECTING, GDK_CAP_NOT_LAST);
            GDK_CAP_PROJECTING, GDK_CAP_NOT_LAST);
+
+  FontName : Pchar = 
+   '-*-helvetica-bold-r-normal--*-120-*-*-*-*-iso8859-1';
           
           
 Var
 Var
   SegTriangle : Array[1..3] of TgdkSegment;
   SegTriangle : Array[1..3] of TgdkSegment;
@@ -315,10 +320,12 @@ begin
   gdk_gc_set_foreground(gc,allocatecolor($ffff,0,0,Widget));
   gdk_gc_set_foreground(gc,allocatecolor($ffff,0,0,Widget));
   for I:=10 to 50 do
   for I:=10 to 50 do
     begin
     begin
-    gdk_gc_set_line_attributes(gc,6,LineStyles[i div 10],CapStyles[i div 10],GDK_JOIN_MITER);
+    gdk_gc_set_line_attributes(gc,6,LineStyles[i div 10],
+                               CapStyles[i div 10],GDK_JOIN_MITER);
     gdk_draw_line(win,gc,I*10,20,I*10,90)
     gdk_draw_line(win,gc,I*10,20,I*10,90)
     end;
     end;
-  gdk_gc_set_line_attributes(gc,1,GDK_LINE_SOLID,GDK_CAP_BUTT,GDK_JOIN_MITER);
+  gdk_gc_set_line_attributes(gc,1,GDK_LINE_SOLID,
+                             GDK_CAP_BUTT,GDK_JOIN_MITER);
   gdk_gc_set_foreground(gc,allocatecolor($ffff,0,$ffff,Widget));
   gdk_gc_set_foreground(gc,allocatecolor($ffff,0,$ffff,Widget));
   seg:=(360 div 20) * 64;
   seg:=(360 div 20) * 64;
   For I:=1 to 20 do
   For I:=1 to 20 do
@@ -342,10 +349,11 @@ begin
     SegTriangle[i].Y2:=400-Triangle[i+1].Y;
     SegTriangle[i].Y2:=400-Triangle[i+1].Y;
     end;
     end;
   gdk_draw_segments(win,gc,@segtriangle[1],3);
   gdk_draw_segments(win,gc,@segtriangle[1],3);
-  font:=gdk_font_load('-*-helvetica-bold-r-normal--*-120-*-*-*-*-iso8859-1');
+  font:=gdk_font_load(FontName);
   gdk_gc_set_foreground(gc,allocatecolor($ffff,$ffff,0,Widget));
   gdk_gc_set_foreground(gc,allocatecolor($ffff,$ffff,0,Widget));
   For I:=1 to 4 do
   For I:=1 to 4 do
-    gdk_draw_string(win,font,gc,I*100,300,Pchar(format('String %d',[i])));
+    gdk_draw_string(win,font,gc,I*100,300,
+                    Pchar(format('String %d',[i])));
   result:=0;
   result:=0;
 end;
 end;
 
 
@@ -377,6 +385,12 @@ primitives explained above.
 Note that the allocated colors are not freed again, so this program does
 Note that the allocated colors are not freed again, so this program does
 contain a memory leak.
 contain a memory leak.
 
 
+The result of the program is shown in figure \ref{fig:screenshot1}.
+\begin{figure}[ht]
+\caption{The graphics program in action.}\label{fig:screenshot1}
+\epsfig{file=gtk5ex/graphics.png,width=\textwidth}
+\end{figure}
+
 \section{Animation}
 \section{Animation}
 The GDK drawing functions can be used to draw directly on a window visible
 The GDK drawing functions can be used to draw directly on a window visible
 on the screen. This is OK for normal applications, but applications that
 on the screen. This is OK for normal applications, but applications that
@@ -428,7 +442,7 @@ more to separate the logic of the different objects.
 
 
 The \var{TGraphicalObject} class is a simple object which introduces some 
 The \var{TGraphicalObject} class is a simple object which introduces some 
 easy access properties to get the position and size of the object:
 easy access properties to get the position and size of the object:
-\begin{verbatim}
+\begin{lstlisting}{}
 TGraphicalObject  = Class(TObject)
 TGraphicalObject  = Class(TObject)
   FRect : TGdkRectangle;
   FRect : TGdkRectangle;
 Public 
 Public 
@@ -438,11 +452,11 @@ Public
   Property Width : Word  Read Frect.Width Write Frect.Width;
   Property Width : Word  Read Frect.Width Write Frect.Width;
   Property Height : Word  Read Frect.Height Write Frect.Height;
   Property Height : Word  Read Frect.Height Write Frect.Height;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 
 
 The \var{TBlock} object is a simple descendent of the var{TGraphicalObject}
 The \var{TBlock} object is a simple descendent of the var{TGraphicalObject}
 class:
 class:
-\begin{verbatim}
+\begin{lstlisting}{}
 TBlock = Class(TGraphicalObject)
 TBlock = Class(TGraphicalObject)
 Private
 Private
   FMaxHits : Integer;
   FMaxHits : Integer;
@@ -459,7 +473,7 @@ Public
   Constructor Create (ABlockList : TBlockList);
   Constructor Create (ABlockList : TBlockList);
   Property Color : PGDKColor Read FColor Write FColor;
   Property Color : PGDKColor Read FColor Write FColor;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 The \var{FMaxHits} field determines how many times the ball must hit the
 The \var{FMaxHits} field determines how many times the ball must hit the
 brick before it dissappears. With each hit, the field is decremented by 1.
 brick before it dissappears. With each hit, the field is decremented by 1.
 
 
@@ -473,7 +487,7 @@ drawn.
 
 
 The implementation of the \var{TBlock} methods are quite simple. The first
 The implementation of the \var{TBlock} methods are quite simple. The first
 methods don't need any explanation.
 methods don't need any explanation.
-\begin{verbatim}
+\begin{lstlisting}{}
 Constructor TBlock.Create (ABlockList : TBlockList);
 Constructor TBlock.Create (ABlockList : TBlockList);
 
 
 begin
 begin
@@ -493,9 +507,9 @@ Function TBlock.PixMap : PgdkPixMap;
 begin
 begin
   Result:=FBlockList.PixMap;
   Result:=FBlockList.PixMap;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 The first interesting method is the \var{CreateGC} method:
 The first interesting method is the \var{CreateGC} method:
-\begin{verbatim}
+\begin{lstlisting}{}
 Procedure TBlock.CreateGC;
 Procedure TBlock.CreateGC;
 
 
 begin
 begin
@@ -504,7 +518,7 @@ begin
   gdk_gc_set_fill(FGC,GDK_SOLID);
   gdk_gc_set_fill(FGC,GDK_SOLID);
   FNeedRedraw:=True;
   FNeedRedraw:=True;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 The method is called the first time the block must be drawn. It allocates a
 The method is called the first time the block must be drawn. It allocates a
 new graphics context using the \var{gdk\_gc\_new} function. This function
 new graphics context using the \var{gdk\_gc\_new} function. This function
 accepts a pointer to a \var{TGTKWidget} as a parameter and returns a new
 accepts a pointer to a \var{TGTKWidget} as a parameter and returns a new
@@ -514,7 +528,7 @@ to a valid color)
 
 
 The \var{Draw} procedure actually draws the block on the pixmap, using 
 The \var{Draw} procedure actually draws the block on the pixmap, using 
 the graphics context created in the previous method:
 the graphics context created in the previous method:
-\begin{verbatim}
+\begin{lstlisting}{}
 Procedure TBlock.Draw;
 Procedure TBlock.Draw;
 
 
 begin
 begin
@@ -526,14 +540,14 @@ begin
     FNeedRedraw:=False;
     FNeedRedraw:=False;
    end;
    end;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 The \var{FNeedRedraw} procedure is used for optimization.
 The \var{FNeedRedraw} procedure is used for optimization.
 
 
 Finally, the \var{Hit} method is called when the block is hit by the ball.
 Finally, the \var{Hit} method is called when the block is hit by the ball.
 It will decrease the \var{FMaxHits} field, and if it reaches zero, the 
 It will decrease the \var{FMaxHits} field, and if it reaches zero, the 
 place occupied by the block is redrawn in the background color. After that,
 place occupied by the block is redrawn in the background color. After that,
 it removes itself from the blocklist and frees itself.
 it removes itself from the blocklist and frees itself.
-\begin{verbatim}
+\begin{lstlisting}{}
 Function TBlock.Hit : Boolean;
 Function TBlock.Hit : Boolean;
 
 
 begin
 begin
@@ -546,11 +560,11 @@ begin
     Free;
     Free;
     end;
     end;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 
 
 The \var{TSprite} object is a little more involved. The declaration is 
 The \var{TSprite} object is a little more involved. The declaration is 
 as follows:
 as follows:
-\begin{verbatim}
+\begin{lstlisting}{}
 TSprite = Class(TGraphicalObject)
 TSprite = Class(TGraphicalObject)
   FPreviousTop,
   FPreviousTop,
   FPreviousLeft : Integer;
   FPreviousLeft : Integer;
@@ -569,7 +583,7 @@ Public
   Property PixMap : PgdkPixMap Read FPixMap;
   Property PixMap : PgdkPixMap Read FPixMap;
   Property BitMap : PGdkBitMap Read FBitMap; 
   Property BitMap : PGdkBitMap Read FBitMap; 
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 The important property is the \var{PixMap} property; this contains the
 The important property is the \var{PixMap} property; this contains the
 pixmap with the sprite's image. The \var{BitMap} property contains the
 pixmap with the sprite's image. The \var{BitMap} property contains the
 bitmap associated with the pixmap. The second important method is the
 bitmap associated with the pixmap. The second important method is the
@@ -583,7 +597,7 @@ All this drawing is done on the background pixmap, to avoid flickering
 when drawing: The result of the two drawing steps is shown at once.
 when drawing: The result of the two drawing steps is shown at once.
 
 
 The implementation of the \var{Draw} method is quite straightforward:
 The implementation of the \var{Draw} method is quite straightforward:
-\begin{verbatim}
+\begin{lstlisting}{}
 Procedure TSprite.Draw;    
 Procedure TSprite.Draw;    
 
 
 Var
 Var
@@ -598,7 +612,7 @@ begin
   gdk_draw_pixmap(FDrawPixMap,gc,FPixMap,0,0,Left,Top,Width,Height)
   gdk_draw_pixmap(FDrawPixMap,gc,FPixMap,0,0,Left,Top,Width,Height)
   gdk_gc_set_clip_mask(gc,Nil);  
   gdk_gc_set_clip_mask(gc,Nil);  
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 After the pixmap has been created (a method which must be implemented by
 After the pixmap has been created (a method which must be implemented by
 descendent objects), the graphics context of the drawing area is retrieved 
 descendent objects), the graphics context of the drawing area is retrieved 
 to do the drawing.
 to do the drawing.
@@ -612,11 +626,11 @@ bitmap will be drawn, other bits are left untouched.
 The pixmap is drawn using the \var{gdk\_draw\_pixmap} function. This
 The pixmap is drawn using the \var{gdk\_draw\_pixmap} function. This
 function copies a region from one \var{TGDKDrawable} to another.
 function copies a region from one \var{TGDKDrawable} to another.
 It is defined as follows:
 It is defined as follows:
-\begin{verbatim}
+\begin{lstlisting}{}
 procedure gdk_draw_pixmap(drawable:PGdkDrawable; gc:PGdkGC; 
 procedure gdk_draw_pixmap(drawable:PGdkDrawable; gc:PGdkGC; 
                           src:PGdkDrawable; 
                           src:PGdkDrawable; 
                           xsrc,ysrc,xdest,ydest,width,height:gint);
                           xsrc,ysrc,xdest,ydest,width,height:gint);
-\end{verbatim}
+\end{lstlisting}{}
 The function, as all GDK drawing functions, takes a \var{PGDKDrawable} 
 The function, as all GDK drawing functions, takes a \var{PGDKDrawable} 
 pointer and a graphics contexts as its first two arguments. The third
 pointer and a graphics contexts as its first two arguments. The third
 argument is the \var{TGDKDrawable} which should be copied. The
 argument is the \var{TGDKDrawable} which should be copied. The
@@ -634,7 +648,7 @@ time; The \var{CreateSpriteFromData} method accepts a pointer to an XPM
 pixmap, and uses the \var{gdk\_pixmap\_create\_from\_xpm\_d} function
 pixmap, and uses the \var{gdk\_pixmap\_create\_from\_xpm\_d} function
 (explained in the previous article) to create the actual pixmap and the 
 (explained in the previous article) to create the actual pixmap and the 
 corresponding bitmap.
 corresponding bitmap.
-\begin{verbatim}
+\begin{lstlisting}{}
 Procedure TSprite.CreateSpriteFromData(SpriteData : PPGChar);
 Procedure TSprite.CreateSpriteFromData(SpriteData : PPGChar);
 
 
 begin
 begin
@@ -643,13 +657,13 @@ begin
                                         Nil,
                                         Nil,
                                         SpriteData);
                                         SpriteData);
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 This method can be used by the descendent object's \var{CreatePixmap} 
 This method can be used by the descendent object's \var{CreatePixmap} 
 procedure.
 procedure.
 
 
 The \var{SavePosition} and \var{GetChangeRect} methods are very
 The \var{SavePosition} and \var{GetChangeRect} methods are very
 straightforward:
 straightforward:
-\begin{verbatim}
+\begin{lstlisting}{}
 Function TSprite.GetChangeRect (Var Rect : TGDkRectAngle) : Boolean;
 Function TSprite.GetChangeRect (Var Rect : TGDkRectAngle) : Boolean;
 
 
 begin
 begin
@@ -670,13 +684,13 @@ begin
   FPreviousLeft:=Left;
   FPreviousLeft:=Left;
   FPreviousTop:=Top;
   FPreviousTop:=Top;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 Note that the \var{GetChangeRect} procedure returns false if the position
 Note that the \var{GetChangeRect} procedure returns false if the position
 of the sprite didn't change. This is used for optimization purposes.
 of the sprite didn't change. This is used for optimization purposes.
 
 
 The pad is the simplest of the two \var{TSprite} descendents. It only adds a
 The pad is the simplest of the two \var{TSprite} descendents. It only adds a
 horizontal movement to the sprite:
 horizontal movement to the sprite:
-\begin{verbatim}
+\begin{lstlisting}{}
 TPad = Class (TSprite)
 TPad = Class (TSprite)
 Private
 Private
   FSlope,
   FSlope,
@@ -694,15 +708,848 @@ Public
   Property Speed : Integer Read FSpeed Write FSpeed;
   Property Speed : Integer Read FSpeed Write FSpeed;
   Property Slope : Integer Read FSlope Write FSlope;
   Property Slope : Integer Read FSlope Write FSlope;
 end;
 end;
-\end{verbatim}
+\end{lstlisting}{}
 The procedures \var{GoLeft}, \var{GoRight} and \var{Stop} can be used to
 The procedures \var{GoLeft}, \var{GoRight} and \var{Stop} can be used to
 control the movement of the pad. The method \var{Step} will be called at
 control the movement of the pad. The method \var{Step} will be called at
 regular intervals to actually move the pad. The \var{InitialPosition} 
 regular intervals to actually move the pad. The \var{InitialPosition} 
 sets the pad at its initial position on the screen. The \var{Speed} and 
 sets the pad at its initial position on the screen. The \var{Speed} and 
 \var{Slope} properties can be used to set the speed and slope of the pad.
 \var{Slope} properties can be used to set the speed and slope of the pad.
+The \var{Speed} is a number of pixels the pad will move per time unit.
+The 'Slope' is a positive number. 
 
 
 The implementation is quite straightforward:
 The implementation is quite straightforward:
-\begin{verbatim}
-\end{verbatim}
+\begin{lstlisting}{}
+Constructor TPad.Create(DrawingArea: PGtkWidget);
+
+begin
+  Inherited Create(DrawingArea);
+  FSpeed:=6;
+  FSlope:=50;
+end;
+
+Procedure TPad.InitialPosition;
+
+begin
+  Left:=(FDrawingArea^.Allocation.Width-Width) div 2;
+  Top:=FDrawingArea^.Allocation.Height-(2*Height);
+  FCurrentSpeed:=0;
+end;
+\end{lstlisting}{}
+The \var{InitialPosition} is used to reset the pad to its initial position
+when the game starts, after a ball is lost or when a new level starts.
+
+The various moving procedures do nothing except manipulate the current speed.
+The handling here is quite simple, more complex handling (accelleration and
+so on) coul be handled.
+\begin{lstlisting}{}
+Procedure TPad.GoLeft;
+
+begin
+  FCurrentSpeed:=-FSpeed;
+end;
+
+Procedure TPad.GoRight;
+
+begin
+  FCurrentSpeed:=FSpeed;
+end;
+
+Procedure TPad.Stop;
+
+begin
+  FCurrentSpeed:=0;
+end;
+\end{lstlisting}{}
+The pixmap for the pad is defined in a global constant \var{PadBitmap}. It is 
+an array of \var{PCHar} which make up a XPM pixmap. The height and width of 
+the bitmap are defined in global constants \var{PadHeight} and \var{PadWidth}
+\begin{lstlisting}{}
+Procedure TPad.CreatePixMap; 
+
+begin
+  CreateSpriteFromData(@PadBitmap[1]);
+  Width:=PadWidth;
+  Height:=PadHeight;
+  InitialPosition;
+end;
+\end{lstlisting}{}
+The \var{Step} method does the actual moving of the pad. It is called at regular intervals
+by a timer. It saves the current position, and calculates the new position. A check is 
+done for the boundaries of the game.
+\begin{lstlisting}{}
+Procedure TPad.Step;
+
+begin
+  SavePosition;
+  Left:=Left+FCurrentSpeed;
+  if Left<=0 then
+    begin
+    FCurrentSpeed:=-FCurrentSpeed;
+    Left:=0;
+    end
+  else if Left+Width>=FDrawingArea^.allocation.width then
+    begin
+    FCurrentSpeed:=-FCurrentSpeed;
+    Left:=FDrawingArea^.allocation.width-Width;
+    end;
+end;
+\end{lstlisting}{}
+
+The implementation of the \var{Tball} class is similar to the one of the \var{TPad},
+only it introduces also a vertical speed. The speed of the ball is determined by 3 
+numbers:
+\begin{enumerate}
+\item A horizontal speed.
+\item A vertical speed. 
+\item A speed factor. (a number between 0 and 100)
+\end{enumerate} 
+The sum of the absolute values of the vertical and horizontal speeds is always 100. 
+To change the speed direction, the horizontal speed can be set to a value between 0
+and 90. This means that the ball can never fly horizontally. The actual speed is 
+determined by multiplying the horizontal speed and vertical speed with a speed 
+factor. The 2 values that are obtained like that are the actual horizontal and 
+vertical speed of the ball.
+
+All this is implemented in the following class:
+\begin{lstlisting}{}
+TBall = Class (TSprite)
+Private
+  FBreakOut : TBreakOut;
+  FCurrentSpeedX,
+  FCurrentSpeedY : Integer;
+  FSpeedfactor : Integer;
+Protected
+  Procedure CreatePixMap; override;
+  Procedure SetSpeed(Value : Integer);
+Public  
+  Constructor Create(BreakOut : TBreakOut);
+  Procedure Step;
+  Procedure IncSpeed (Value: Integer);
+  Procedure FlipSpeed (FlipX,FlipY : Boolean);
+  Property CurrentSpeedX : Integer Read FCurrentSpeedX Write SetSpeed;
+  Property CurrentSpeedY : Integer Read FCurrentSpeedY;
+  Property SpeedFactor : Integer Read FSpeedFactor Write FSpeedFactor;
+end;
+\end{lstlisting}{}
+The \var{FlipSpeed} method is used to change the ball's direction when it hits a brick
+or one of the borders of the game. The \var{IncSpeed} method increases the speed of the
+ball.
+
+As usual, the implementation of these methods is quite straightforward;
+\begin{lstlisting}{}
+Constructor TBall.Create(BreakOut : TBreakOut);
+
+begin
+  Inherited Create(BreakOut.FDrawingArea);
+  FBreakOut:=breakout;
+  FCurrentSpeedY:=-100;
+  FCurrentSpeedX:=0;
+  FSpeedFactor:=10;
+end;
+\end{lstlisting}
+The CreatePixmap uses the global constant \var{BallPixmap} to 
+create the pixmap. The with and height are stored in the \var{BallWidth}
+and \var{BallHeight} constants.
+\begin{lstlisting}{}
+Procedure TBall.CreatePixMap; 
+
+begin
+  CreateSpriteFromData(@BallBitmap[1]);
+  Width:=BallWidth;
+  Height:=BallHeight;
+end;
+\end{lstlisting}
+The SetSpeed value is the write handler for the \var{CurrentSpeedX} property.
+It makes sure that the value stays within certain bounds, and that the sum
+of the horizontal and vertical speeds remains 100.
+\begin{lstlisting}{}
+Procedure TBall.SetSpeed(Value : Integer);
+
+begin
+  If Value<-FMaxXspeed then 
+    Value:=-FMaxXSpeed
+  else if Value>FMaxXspeed then
+    Value:=FMaxXspeed;
+  FCurrentSpeedX:=Value;
+  If FCurrentSpeedY>0 then
+    FCurrentSpeedY:=100-Abs(FCurrentSpeedX)
+  else
+    FCurrentSpeedY:=-100+Abs(FCurrentSpeedX);
+end;
+\end{lstlisting}
+The \var{IncSpeed} procedure increases or decreases the speed of the ball, 
+making sure it doesn't get smaller as 10.
+\begin{lstlisting}{}
+Procedure TBall.IncSpeed (Value: Integer);
+
+begin
+  FSpeedFactor:=FSpeedFactor+Value;
+  If FSpeedFactor<10 then
+    FSpeedFactor:=10;
+end;
+
+Procedure TBall.FlipSpeed (FlipX,FlipY : Boolean);
+
+begin
+  If FlipX then 
+    FCurrentSpeedX:=-FCurrentSpeedX;
+  If FlipY then 
+    FCurrentSpeedY:=-FCurrentSpeedY;
+end;
+\end{lstlisting}
+The last method of \var{TBall} is the \var{Step} method,
+which moves the ball on the screen. It adjusts the speed when the ball hits the
+border of the game area, and calls the \var{TBreakOut.LostBall} method
+when the ball hits the bottom of the game area.
+\begin{lstlisting}{}
+Procedure TBall.Step;
+
+begin
+  SavePosition;
+  Left :=Left + Round((FCurrentSpeedX*FSpeedFactor/100));
+  Top  :=Top  + Round((FCurrentSpeedY*FSpeedFactor/100));
+  if Left<=1 then
+    begin
+    FlipSpeed(True,False);
+    Left:=1;
+    end
+  else if Left+Width>=FDrawingArea^.allocation.width then
+    begin
+    FlipSpeed(True,False);
+    Left:=FDrawingArea^.allocation.width-Width-1;
+    end;
+  if Top<=1 then
+    begin
+    FlipSpeed(False,True);
+    Top:=1;
+    end
+  else if Top+Height>=FDrawingArea^.allocation.Height then
+    FBreakOut.LostBall
+end;
+\end{lstlisting}
+
+\section{Game logic}
+The previous objects were concerned with the grapical representation of the
+game. The logic of the game is concentrated in 2 other objects: \var{TBlockList},
+ which manages the blocks in the game, and \var{TBreakOut}, which implements the
+game logic.
+
+The \var{TBlockList} class is a simple descendent of \var{TList}:
+\begin{lstlisting}{}
+TBlockList = Class (TList)
+  FTotalRows,FTotalColums,FStartRow,FBlockRows,FSpacing : Byte;
+  FBreakOut : TBreakOut;
+  FColor : PGDKColor;
+  Function DRawingArea : PGTKWidget;
+  FPixMap : PGDKPixmap;
+Public 
+  Constructor Create(BreakOut : TBreakOut);
+  Destructor Destroy; override;
+  Procedure CheckCollision (Ball: TBall);
+  Procedure DrawBlocks;
+  Procedure DrawBlocks(Const Area : TGdkRectangle);
+  Procedure CreateBlocks;
+  Procedure FreeBlocks;
+  Property TotalRows : Byte Read FTotalRows Write FTotalRows;
+  Property TotalColumns : Byte Read FTotalColums Write FTotalColums;
+  Property StartRow : Byte Read FStartRow Write FStartRow;
+  Property BlockRows : Byte Read FBlockRows Write FBlockRows;
+  Property BlockSpacing : Byte Read FSpacing Write FSpacing; 
+  Property PixMap : PGDKPixMap Read FPixMap Write FPixMap;
+end;
+\end{lstlisting}
+It introduces some properties which control the look of the game:
+\var{TotalRows}, \var{TotalColumns} is the total number of columns 
+and rows in which blocks can be placed. \var{StartRow} and \var{BlockRows}
+determines how many blocks are actually placed. \var{BlockSpacing} determines
+the amount of space between the blocks. The \var{CheckCollision} determines
+whether a ball has hit one of the blocks. The \var{DrawBlocks} draws only the blocks
+that intersect with the rectangle defined in the \var{Area} parameter.
+The other methods are self explaining.
+
+The implementation of the \var{TBlockList} class is -as usual- quite simple:
+\begin{lstlisting}{}
+Constructor TBlockList.Create(BreakOut : TBreakOut);
 
 
-\end{document}
+begin
+  FBreakOut:=BreakOut;
+end;
+
+Function TBlockList.DrawingArea : PGtkWidget;
+
+begin
+  Result:=FBreakOut.FDrawingArea;
+end;
+
+Destructor TBlockList.Destroy; 
+
+begin
+  If FColor<>Nil then
+    FreeMem(FColor);
+  FreeBlocks;
+end;
+
+Procedure TBlockList.DrawBlocks;
+
+Var
+  I : Longint; 
+
+begin
+  If Count=0 then
+    CreateBlocks;
+  For I:=0 to Count-1 do
+    TBlock(Items[i]).draw;
+end;
+
+Procedure TBlockList.DrawBlocks (Const Area : TGdkRectangle);
+
+Var
+  i : longint;
+  inters : TgdkRectangle;
+
+begin
+  For I:=0 to Count-1 do
+    With TBlock(Items[i]) do
+      FNeedRedraw:=gdk_rectangle_intersect(@area,@Frect,@inters)<>0;
+  DrawBlocks;    
+end;
+\end{lstlisting}
+The \var{gdk\_rectangle\_interset} returns 0 if 2 rectangles do not intersect,
+and returns a nonzero constant if they do. If they do, the last parameter
+is filled with the position and size of the intersecting rectangle.
+
+\begin{lstlisting}{}
+Procedure TBlockList.FreeBlocks;
+
+Var
+  I : longint;
+
+begin
+  For I:=Count-1 downto 0 do
+    begin
+    TBlock(Items[i]).Free;
+    Delete(i);
+    end;
+end;
+\end{lstlisting}
+The \var{CreateBlocks} method creates the blocks and draws them on the screen.
+It is called when the blocklist is drawn and there are no blocks.
+
+The algoritthm to color and place the blocks is quite simple, but a more 
+complex algorithm that implements patterns of blocks depending on the 
+level, and different colors for blocks could be implemented.
+\begin{lstlisting}{}
+Procedure TBlockList.CreateBlocks;
+
+Var
+  TotalHeight,TotalWidth,
+  Cellheight,CellWidth,
+  I,J : Integer;
+  Block : TBlock;
+  Min : Byte;
+  
+begin
+  FColor:=AllocateColor(0,0,$ffff,DrawingArea);
+  Min:=FSpacing div 2;
+  If Min<1 then 
+    Min:=1;
+  TotalWidth:=Drawingarea^.Allocation.Width;
+  TotalHeight:=DrawingArea^.Allocation.Height;
+  Cellheight:=TotalHeight Div TotalRows;
+  CellWidth:=TotalWidth div TotalColumns;
+  For I:=StartRow to StartRow+BlockRows-1 do
+    For J:=0 to TotalColumns-1 do
+    begin
+    Block:=TBlock.Create(Self);
+    With Block do
+      begin
+      Top:=TotalHeight-(CellHeight*I)+Min;
+      Left:=(CellWidth*J)+min;
+      Width:=CellWidth-2*min;
+      Height:=CellHeight-2*min;
+      Color:=Self.FColor;
+      FNeedRedraw:=True;
+      end;
+    add(Block);
+    end;
+end;
+\end{lstlisting}
+The checkcollision function checks all blocks to see whether it collides with the ball.
+If so, it flips the speed of the ball and calls the balls \var{Hit} function. This will
+remove the ball from the list if it is destroyed.
+
+Note that the flipping of the speed of the ball checks where the ball came from, i.e.
+looks at the previous position of the ball.
+\begin{lstlisting}{}
+Procedure TBlockList.CheckCollision (Ball: TBall);
+
+var
+  brect,ints : tgdkrectangle;
+  B : TBlock;
+  i : integer;
+  flipx,flipy : Boolean;
+    
+begin
+  For I:=Count-1 downto 0 do
+    begin
+    B:=TBlock(Items[i]);
+    BRect:=B.FRect;    
+    if gdk_rectangle_intersect(@Ball.Frect,@BRect,@ints)<>0 then
+      begin
+      FlipY:=((Ball.FpreviousTop>=(B.Top+B.Height)) and 
+              (Ball.CurrentSpeedY<0)) or
+             ((Ball.FpreviousTop+Ball.Height<=B.Top) and 
+              (Ball.CurrentSpeedY>0));
+      FlipX:=Not FlipY;
+      If FlipX then
+        FlipX:=((Ball.FPreviousLeft>=(B.Left+B.Width)) and 
+                (Ball.CurrentSpeedX<0)) or
+               (((Ball.FPreviousLeft+Ball.Width)<=B.Left) and 
+                (Ball.CurrentSpeedX>0));
+      Ball.FlipSpeed(FlipX,Flipy);
+      if B.Hit and not (Count=0) then 
+        gtk_widget_draw(DrawingArea,@BRect);
+      Break;
+      end;
+    end;
+end;
+\end{lstlisting}
+
+Finally, the \var{TBreakOut} class encapsulates the rest of the game logic. Its declaration 
+is as follows:
+\begin{lstlisting}{}
+TBreakOut = Class(TObject)
+Private
+  FLevel : Integer;
+  FBalls : Integer;
+  FBGGC : PGDKGC;
+  FBackGroundColor : PGDKColor;
+  FPad : TPad;
+  FBall : TBall;
+  FBlockList : TBlockList;
+  FDrawingArea : PGTKWidget;
+  FPixMap : PGDKPixMap;
+  Procedure DrawBackGround (Area : TGdkrectAngle);
+  Procedure DrawBoard(Exposed : PGdkEventExpose);
+  Procedure CreateGC;
+  Procedure CreatePixMap;
+  Procedure CopyPixMap(Area : TGdkRectangle);
+  Procedure CheckCollision;
+  Procedure FreeBall;
+  Procedure NextLevel;
+  Procedure NextBall;
+  Procedure GameOver;
+  Procedure LostBall;
+  Procedure Redrawgame;
+Public   
+  Constructor Create (DrawingArea : PGtkWidget);
+  Procedure Draw(Exposed : PGDKEventExpose);
+  Procedure Step;
+  Property BlockList : TBlockList Read FBlockList;
+  Property Pad : TPad Read FPad;
+  Property Level : Integer Read Flevel;
+  Property Balls : Integer Read FBalls Write FBalls;
+end;
+\end{lstlisting}
+The purpose of most of the methods of \var{TBreakOut} is self-evident. The \var{Draw}
+method will be called when the drawing area on which the game is drawn is exposed.
+The \var{Step} method will be called by a timer routine, and this will move all pieces
+in the game, creating the illusion of movement. These are the only 2 public routines
+of the component.
+
+The constructor simply initializes the Ball and blocklist components. It does not
+create a ball, this will be created when the ball enters the game.
+\begin{lstlisting}{}
+Constructor TBreakOut.Create (DrawingArea : PGtkWidget);
+
+begin
+  FDrawingArea:=DrawingArea;
+  FBlockList:=TBlockList.Create (Self);
+  FPad:=TPad.Create(FDrawingArea);
+  FBalls:=5;
+end;
+\end{lstlisting}
+
+The following routines are mainly concerned with the drawing of the various parts of the game.
+\begin{lstlisting}{}
+Procedure TBreakOut.DrawBoard(Exposed : PGdkEventExpose);
+
+begin
+  If FBGGC=Nil then
+    CreateGC;  
+  DrawBackGround(Exposed^.Area);
+end;
+
+Procedure TBreakOut.CreateGC;
+
+begin
+  FBGGC:=gdk_gc_new(FDrawingArea^.Window);
+  FBackGroundColor:=AllocateColor(0,0,0,FDrawingArea);
+  gdk_gc_set_foreground(FBGGC,FBackGroundColor);
+  gdk_gc_set_fill(FBGGC,GDK_SOLID);
+end;
+\end{lstlisting}
+The graphics context is needed for the drawing of the background of the game; 
+it sets the drawing color to black and the fill style to solid. The graphics
+context is then used in the \var{DrawBackground} method to draw the background
+on the pixmap with the game image:
+\begin{lstlisting}{}
+Procedure TBreakOut.DrawBackGround (Area : TGdkrectAngle);
+
+begin
+  With Area do
+    gdk_draw_rectangle(PGDKDrawable(FPixMap),FBGGC,-1,x,y,Width+1,Height+1);
+end;
+\end{lstlisting}
+The pixmap that contains the game image is created the first time the breakout 
+game is drawn. It is created using the \var{gdk\_pixmap\_new} function, which 
+needs a \var{PGDKwindow} as the first parameter; from this window certain 
+device properties are copied.
+
+After the pixmap is created, it is assigned to the pad and blocklist objects.
+\begin{lstlisting}{}
+Procedure TBreakOut.CreatePixMap;
+
+begin
+  If FPixMap<>Nil then
+    GDK_pixmap_unref(FPixMap);
+  With FDrawingArea^ do
+    FPixMap:=gdk_pixmap_new(Window,Allocation.Width,Allocation.Height,-1);
+  FBlockList.PixMap:=FPixMap;
+  FPad.FDrawPixMap:=FPixMap;
+  If Assigned(FBall) then
+    FBall.FDrawPixMap:=FPixMap;
+end;
+\end{lstlisting}
+The following routine does the actual drawing of the screen: 
+It copies the pixmap with the game image to the actual window. 
+Not the whole pixmap is drawn (this would be very inefficient), 
+but just the part indicated by the \var\var{Area} parameter.
+\begin{lstlisting}{}
+Procedure TBreakOut.CopyPixMap(Area : TGdkRectangle);
+
+begin
+  gdk_draw_pixmap(FDrawingArea^.Window,
+                  gtk_widget_get_style(FDrawingArea)^.fg_gc[GTK_WIDGET_STATE(FDrawingArea)],
+                  FPixMap,
+                  area.x,area.y,
+                  area.x,area.y,
+                  area.width,area.height); 
+end;
+\end{lstlisting}
+The \var{CopyPixmap} method is called as much as needed 
+by the \var{Draw} method. This method tries to determine
+the minimum amount of drawing needed to restore the game image on the screen.
+
+It will draw the board, the exposed blocks, the previous position of
+the ball and pad on the pixmap. After that the changed portions of
+the pixmap are copied to the screen.
+\begin{lstlisting}{}
+Procedure TBreakOut.Draw(Exposed : PGDKEventExpose);
+
+Var
+  Rect : TGdkRectangle;
+
+begin
+  if FPixMap=Nil then 
+    CreatePixMap;
+  if Exposed<>Nil then
+    begin
+    DrawBoard(Exposed);
+    FBlockList.DrawBlocks(exposed^.area)
+    end
+  else
+    begin
+    If Assigned(FBall) then 
+      if FBall.GetChangeRect(Rect) then
+        begin
+        DrawBackground(Rect);
+        FBLockList.drawBlocks(Rect);
+        end;  
+    if FPad.GetChangeRect(Rect) then
+      DrawBackground(Rect)
+    end;
+  FPad.Draw;
+  if Assigned(FBall) Then
+    FBall.draw;
+  If Exposed<>Nil then
+    CopyPixMap(Exposed^.Area);
+  If assigned(FBall) then
+    if FBall.GetChangeRect(Rect) then
+      CopyPixMap(Rect);
+  if FPad.GetChangeRect(Rect) then
+    CopyPixMap(Rect);
+  IF Assigned(FBall) then
+    CopyPixMap(FBall.FRect);
+  CopyPixMap(FPad.FRect);
+end;
+\end{lstlisting}
+The \var{RedrawGame} forces a redraw of the whole game, by forcing an expose event on the 
+drawing area:
+\begin{lstlisting}{}
+Procedure TBreakout.Redrawgame;
+
+Var
+  Rect : TgdkRectangle;
+
+begin
+  Rect.X:=FDrawingArea^.allocation.x;
+  Rect.Y:=FDrawingArea^.allocation.y;
+  Rect.Width:=FDrawingArea^.allocation.Width;
+  Rect.Height:=FDrawingArea^.allocation.Height;
+  gtk_Widget_draw(FDrawingArea,@rect)
+end;
+\end{lstlisting}
+The \var{Step} procedure is the central part of the game logic: it moves
+the various components on the screen, and checks for collisions between 
+the ball and the pad or the blocks. If a 'game over' or 'end of level' 
+condition is detected, the appropriate methods are called to handle 
+these situations.
+\begin{lstlisting}{}
+Procedure TBreakOut.Step;
+
+begin
+  FPad.Step;
+  If Assigned(FBall) then
+    FBall.Step;
+  CheckCollision;
+  If FBlockList.Count=0 then
+    NextLevel;
+  if Not Assigned(FBall) and (FBalls=0) then
+    GameOver;
+end;
+\end{lstlisting}
+The \var{CheckCollision} method checks for collisions of the ball with the pad
+or with a block. The blocklist handles the collisions with a block, the collision
+between the ball and the pad is handled here, in much the same was as it was handled
+by the blocklist for the blocks. The only difference is that the speed of the ball 
+is altered, depending on the speed of the pad:
+\begin{enumerate}
+\item If the pad was moving at the moment of impact, then the speedfactor of
+the ball is increased or decreased, depending on whether the ball and pad
+ were moving in the same direction, or in opposite directions.
+\item The angle of the ball is altered using the \var{Slope} of the pad. The horizontal
+component of the speed is increased (or decreased) with a factor that depends on
+the place where the ball hits the pad. If the pad is hit in the middle, no change takes
+place. If it is not hit in the middle, the alteration is proportional to the distance
+between the middle of the pad and the point of impact.
+\end{enumerate}
+\begin{lstlisting}{}
+Procedure TBreakOut.CheckCollision;
+
+Var
+  Inters :TGdkrectangle;
+
+begin
+  If Assigned(FBall) then
+   begin
+   if gdk_rectangle_intersect(@FBall.FRect,@FPad.Frect,@inters)<>0 then
+     If (FBall.FPreviousTop<FPad.Top) and (FBall.FCurrentSpeedY>0) then
+       begin
+       FBall.FlipSpeed(False,True);
+       If (FPad.CurrentSpeed<>0) then
+         if (FBall.FCurrentSpeedX*FPad.CurrentSpeed)>0 then
+           FBall.IncSpeed(HitAccelleration)
+         else
+           FBall.IncSpeed(-HitAccelleration);
+       FBall.CurrentSpeedX:=FBall.CurrentSpeedX+
+                           (Round(((FBall.Left+(FBall.Width div 2)) - 
+                                  (FPad.left+Fpad.Width div 2)) 
+                                   * (FPad.Slope / 100)));
+       end; 
+   FBlockList.CheckCollision(FBall);  
+   end;
+end;
+\end{lstlisting}
+The following methods control the logic of the game. They are kept as simple
+as possible, but they can be altered to make the game more interesting or 
+visually attractive.
+\begin{lstlisting}{}
+Procedure TBreakOut.FreeBall;
+
+begin
+  FBall.Free;
+  FBall:=Nil;
+end;
+
+Procedure TbreakOut.NextBall;
+
+begin
+  If FBall=Nil then
+    begin
+    FBall:=TBall.Create(Self);
+    FBall.Top:=FPad.Top-1;
+    FBall.Left:=FPad.Left + (FPad.Width div 2);
+    FBall.CurrentSpeedX:=FPad.CurrentSpeed*5;
+    FBall.FPreviousTop:=FBall.Top;
+    FBall.FPreviousLeft:=FBall.Left;
+    FBall.FDrawPixMap:=Self.FPixMap;
+    FBall.Draw;
+    end;
+end;
+
+Procedure TBreakOut.NextLevel;
+
+Var
+  Area : TGdkRectangle;
+
+begin
+  If Assigned(FBall) then
+    FreeBall;
+  FPad.FSpeed:=FPad.Speed+LevelAccelleration;
+  FPad.InitialPosition;
+  RedrawGame;
+end;
+
+Procedure TBreakout.LostBall;
+
+begin
+  Dec(FBalls);
+  If FBalls=0 then 
+    GameOver;
+  FreeBall;
+  Fpad.InitialPosition;
+  RedrawGame;
+end;
+
+Procedure TBreakout.GameOver;
+
+begin
+end;
+\end{lstlisting}
+
+All the code for these three objects is collected in the unit \file{blocks}.
+
+The main program uses the \var{TBreakOut} object to draw the game on a screen:
+A simple, non-sizable window is created, and a \var{TGTKDrawingArea} widget is
+dropped on it. A signal handler for the expose event of the widget is installed 
+(the \var{Exposed} function), as well as a timeout which will step the game 
+every 50 milliseconds (the \var{Step} function). After that, event handlers 
+are installed for the keyboard, to the user can move the pad 
+(the \var{KeyPress} function). The 'delete' event is also handled, to destroy the
+window (the \var{Close} function).
+
+The only logic in these functions consists of communicating the events to the 
+\var{TBreakout} object, and to set the movement of the Pad based on the key 
+that was hit. The program listing is presented without further comment.
+\begin{lstlisting}{}
+program breakout;
+
+{$mode objfpc}
+
+uses glib,gdk,gtk,blocks;
+
+Type 
+  TBreakOutWindow = Class(TObject)
+  Public
+    window, 
+    area : PGtkWidget;
+    BreakOut : TBreakOut;
+  end;
+
+Var
+  GameWindow : TBreakOutWindow;
+  
+Function Close( widget : PGtkWidget ;
+                event : PGdkEvent;
+                data : gpointer) : boolean; cdecl;
+Begin
+  gtk_main_quit();
+  Close := false;
+End;
+
+function Exposed(Widget: PGtkWidget;
+                 event : PGdkEventExpose; 
+                 Data : gpointer) : Integer; cdecl;
+
+begin
+  TBreakOutWindow(Data).BreakOut.Draw(Event);
+  result:=0;
+end;
+
+function KeyPress (Widget: PGtkWidget;
+                   event : PGdkEventKey; 
+                   Data : gpointer) : Integer; cdecl;
+
+begin
+  with TBreakOutWindow(Data).BreakOut do
+    Case event^.keyval of
+      gdk_left  : Pad.Goleft;
+      gdk_right : Pad.GoRight;
+      gdk_down  : Pad.Stop;
+      Ord(' ')  : NextBall;
+    end;    
+  Result:=0; 
+end;
+
+function Step (data : Gpointer): integer;cdecl;
+
+Var
+ Rect : TGdkRectangle;
+
+begin
+  With TBreakOutWindow(Data) do
+    begin
+    With Breakout do
+      begin
+      Step;
+      Draw(Nil);
+      end; 
+    end;
+  Result:=integer(True);
+end;
+
+Begin
+  gtk_init( @argc, @argv );
+  GameWindow:=TBreakOutWindow.Create;
+  With GameWindow do
+    begin
+    window := gtk_window_new( GTK_WINDOW_TOPLEVEL );
+    gtk_window_set_policy(PgtkWindow(Window),0,0,1);
+    gtk_signal_connect(PGTK_OBJECT (window),'delete_event',
+                       GTK_SIGNAL_FUNC(@Close),Nil);
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+    area := gtk_drawing_area_new();
+    gtk_container_add( GTK_CONTAINER(window), Area);
+    BreakOut:=TBreakOut.Create(area);
+    With BreakOut.BlockList do
+      begin
+      TotalRows:=20;
+      TotalColumns:=10;
+      StartRow:=15;
+      BlockRows:=5;
+      BlockSpacing:=2;
+      end;
+    gtk_signal_connect (GTK_OBJECT (area),'expose_event',
+                        GTK_SIGNAL_FUNC(@Exposed),GameWindow);
+    gtk_drawing_area_size (PGTKDRAWINGAREA(area),600,400);
+    gtk_widget_set_events(window,GDK_KEY_RELEASE_MASK);
+    gtk_signal_connect(PGTKObject(Window),'key_press_event',
+                       GTK_SIGNAL_FUNC(@KeyPress),GameWindow);
+    gtk_timeout_add(50,@Step,GameWindow);
+    gtk_widget_show_all(window); 
+    gtk_main();
+    end;
+End.
+  
+end.
+\end{lstlisting}
+The result of the program can be seen in figure \ref{fig:breakout}.
+\begin{figure}[ht]
+\caption{The breakout program in action.}\label{fig:breakout}
+\epsfig{file=gtk5ex/breakout.png,width=\textwidth}
+\end{figure}
+The program can be enhanced in many ways:
+\begin{enumerate}
+\item More different colors for the blocks.
+\item Different patterns of blocks when going to new levels.
+\item Add some messages at the end of a level, or at game over.
+\item Add a pause mode.
+\item Add a menu to start/stop the game, and with some preferences
+(game size, player level)
+\item add a score based on the time it takes to finish a level.
+\end{enumerate}
+And many more things can probably be done. The program as it is now is playable, and 
+fulfills it purpose: to demonstrate that simple game programming using the drawing 
+facilities offered by GTK/GDK toolkit is possible and can be quite easy.
+\end{document}