752beee49dddf63a19fcb891ffe6b0945c1f9d05
[AXE.git] / doc / tutorial.xml
1 <?xml version="1.0"?>
2 <!DOCTYPE doc SYSTEM "/usr/local/xslt/doc.dtd">
3
4 <doc>
5
6 <book>
7
8 <title>AXE Tutorial</title>
9
10 <toc/>
11
12 <chapter>
13 <heading>Introduction</heading>
14 <para>
15 The <strong>Andromeda X-Windows Encapsulation (AXE)</strong> is a C++ class
16 library which encapsulates the X Windows library (<emph>Xlib</emph>).
17 Classical programming with Xlib is rather cumbersome to say the least.
18 The Xlib calls are rather complicated and often require many parameters
19 that can more easily be stored in objects.
20 Also, the classical event loop present in most X applications is something
21 you don't want to reinvent every time.
22 That sort of thing is better left to a framework which provides you
23 with more easy way to deal with events from the X server.
24 </para>
25
26 <para>
27 The intention of <strong>AXE</strong> is to make programming for X a lot
28 easier.
29 It was first developed to teach programming in C++ to students and let
30 them do some graphics without being confronted by the X library.
31 Over the past years it has grown into a framwork that not only encapsulates
32 the resources in the X server, like windows, colors and graphic context,
33 but provides some mechanisms that handle low-level communication with
34 the X server, user interface classes, multithreading and utility classes.
35 Although functionality of <strong>AXE</strong> overlaps with some other
36 user interface libraries such as <emph>gtk+</emph> or <emph>Qt</emph>,
37 the first goal of <strong>AXE</strong> is not to be a user interface
38 library.
39 Some of the design goals in <strong>AXE</strong> are not met yet, but
40 they include features such as dynamically loading of the user interface,
41 a strong set of graphical object functions, image processing, high-level
42 graphics objects and lots more.
43 </para>
44
45 <para>
46 To get you started with <strong>AXE</strong>, this tutorial takes you through
47 a sample application in which some the features of <strong>AXE</strong>
48 are touched upon.
49 The sample application is a doodle program, where the user can freely
50 draw pictures with the mouse.
51 The pictures are stored as simple polylines with a few attributes.
52 Writing the doodle program will show you how to build an <strong>AXE</strong>
53 application and create the most basic functions for an application.
54 In this tutorial, I assume you have sucessfully downloaded and installed
55 <strong>AXE</strong>.
56 </para>
57
58 </chapter>
59
60 <chapter>
61 <heading>A minimal AXE application</heading>
62
63 <para>
64 In this chapter we'll start writing the very minimum to get an AXE
65 application going.
66 All we do is make a top-level window, draw something in that window
67 and add a button to quit the application.
68 </para>
69
70 <section>
71 <heading>The start: class xapplication</heading>
72
73 <para>
74 Assuming you installed <strong>AXE</strong>, you can start creating the
75 doodle program.
76 The first thing you need in each and every <strong>AXE</strong> application
77 is to create an application class, derived from the class
78 <code>xapplication</code> and declare a static object of that class.
79 In the example below, our application class is called <code>doodle</code>
80 and the static object is <code>DoodleApp</code>:
81
82 <verbatim>
83
84 #include &lt;AXE/xappl.h&gt;
85
86 class doodle: public xapplication
87 {
88 };
89
90 doodle DoodleApp;
91
92 </verbatim>
93
94 Note that you need to include the header file <code>AXE/xappl.h</code>
95 which contains the definition of the <code>xapplication</code> class.
96 Also note that, other than in classical C or C++ programs, you do not
97 have a <code>main()</code> function.
98 This is taken care of by the <strong>AXE</strong> library.
99
100 Next, compile and link the application:
101
102 <verbatim>
103 g++ -c doodle1.cpp
104 g++ -o doodle1 doodle1.o -lAXE -L/usr/X11R6/lib -lX11 -lXpm
105 </verbatim>
106
107 Start the doodle program and you'll see that nothing happes.
108 All this program does is connect to the X server and wait for
109 events that will never come.
110 To do someting visible, we have to create a window and map in on
111 the screen.
112 The <code>main()</code> function in <strong>AXE</strong> calls virtual
113 functions in the static application object, which you can override
114 in your own application class to get some useful work done.
115 One of the first functions it calls after makeing the connection with
116 the X display is <code>SetupResources</code>.
117 We will now override this function and create a top-level window for
118 doodle (see <emph>demos/doodle1.cpp</emph>):
119
120 <verbatim>
121 #include &lt;AXE/xappl.h&gt;
122
123 class doodle: public xapplication
124 {
125    managed_window *main_frame;
126
127    virtual void SetupResources(void);
128 };
129
130 doodle DoodleApp;
131
132 void doodle::SetupResources()
133 {
134    main_frame = new managed_window("Doodling with AXE");
135    main_frame-&gt;Map();
136 }
137 </verbatim>
138
139 We added two items to our <code>doodle</code> class:
140 <enumerate>
141 <item>The <code>managed_window</code> pointer to our top-level window:
142       <code>main_frame</code>
143 </item>
144 <item>The overridden fuunction from the base class:
145       <code>SetupResources()</code>
146 </item>
147 </enumerate>
148
149 In the <code>SetupResources()</code> function, we create the actual
150 window as a <code>managed_window</code> object.
151 A <code>managed_window</code> is a window like any other window, except
152 that is a direct child of the server's root window and as such is
153 managed by the window manager.
154 The window manager will put all kinds of decorations on our top-level
155 window like a title bar, a close button, a menu button, a border for
156 resizing and that sort of stuff.
157 Your mileage may vary, depending on the window manager you use.
158 We pass the title of our application to the constructor of the
159 <code>managed_window</code>, so we'll know what window we're looking at:
160
161 <verbatim>
162    main_frame = new managed_window("Doodling with AXE");
163 </verbatim>
164
165 The window is created but is not visible yet.
166 To show the window on the screen, we have to <strong>Map</strong> the
167 window with the member function <code>Map()</code>.
168 When you start the program, it will show the empty window with our
169 'Doodling with AXE' title in the titlebar:
170
171 <para>
172 <picture src='tutor2.1.png' eps='tutor2.1.eps'/>
173 </para>
174
175 You can do most of the usual things a window manager lets you do with
176 the doodle window.
177 You can minimize and restore or resize and move the window, provided
178 your window manager implements those functions.
179 The one thing you can not do is close the window.
180 The only way to stop doodle1 is to press ctrl-C in the terminal you
181 started the program.
182 This is because we do not handle the proper events to let the
183 window manager close our application.
184 As a matter of fact we do not handle any events at all, but we'll
185 get to that in the next section.
186 </para>
187
188 </section>
189
190 <section>
191 <heading>Drawing in the window</heading>
192
193 <para>
194 For drawing graphics in X Windows, we need two things.
195 First of all the window to draw in, of course. Second, we need a
196 <emph>Graphics Context</emph>.
197 A graphics context is a resource in X Windows that defines how graphical
198 primitives are drawn. It holds all the properties such as backround and
199 foreground color, line size and dashing, the font for text strings and
200 much more.
201 The window part of drawing is easy.
202 We just created a window for doodle and all graphical drawing functions
203 are simply member functions of the <code>window</code> class.
204 The graphics context is encapsulated with the <code>gc</code> class.
205 For our first example we will create a <code>gc</code> object with a foreground
206 color of black.
207 This means that everything we draw in the window is black on a white background
208 (assuming the default background of the window is white).
209 To start drawing graphics, we add two lines to our <code>SetupResources()</code>
210 member funtion:
211
212 <verbatim>
213    gc    graphic("black");
214    main_frame-&gt;DrawRectangle(graphic, 50, 70, 200, 100);
215
216 </verbatim>
217
218 The parameters to <code>DrawRectangle()</code> are: the graphics context, the X and
219 Y coordinates of the top left corner and the size (width and height) of the rectangle.
220 So, this example draws a rectangle that has a top left corner 50 pixels to the right
221 of the left side of our window and 70 pixels down from the top side of our window.
222 The rectangle is 200 pixels wide and 100 pixels high.
223 </para>
224
225 <para>
226 Getting a picture in a window is not so hard in itself.
227 However, drawing once and immediately after creating the window is not enough
228 in any practical application.
229 Try some window operations on your fresh drawing after doodle puts the window
230 on the screen.
231 You can resize the window or move windows from other applications over the doodle
232 window and you'll see the rectangle disappear just as easily as you created it.
233 That is because the X server does not remember what you drew in the window.
234 At the moment you call the <code>DrawRectangle()</code> function, the X server
235 renders the pixels to make the area on the screen look like a rectangle and then
236 immediately forgets the request to draw the rectangle.
237 When the doodle window becomes visible again after having been obscured for a while
238 or when the contents of the window are supposed to change for any other reason,
239 all the X server can do is clear the area of the window.
240 It is left to the application to redraw the contents of the window.
241 </para>
242
243 <para>
244 Fortunately, the X server lets you know when somthing interesting happens to
245 your windows and when you are supposed to react.
246 It does this by sending <emph>events</emph> to the application that owns
247 the window where the event takes place.
248 The X server sends lots of events for all sorts of reasons.
249 Events are sent to your application for example when the user clicks a mouse button,
250 moves the mouse, hits a key on the keyboard or makes parts of your
251 window visible.
252 For each type of event, there is a virtual function in the <code>window</code> class.
253 If you want to handle any of those events from the X server, you have to
254 override an event handling function in a class you derive from the <code>window</code>
255 base class.
256 In our doodle application, we will make a new class and a new window.
257 The new window is created as a child window of our top level window and we will
258 draw pictures only in this child window.
259 Generally, it is not a good idea to do all kinds of drawing in the top level
260 window.
261 Any real application uses many windows for various kinds of user interaction
262 and the top level window is used only to organize all these sub windows and
263 interact with the window manager.
264 So, here we go with our own class derived from <code>window</code>, which we will
265 call a <code>doodle_view</code>:
266
267 <verbatim>
268
269 class doodle_view : public window
270 {
271 public:
272
273    doodle_view(window *parent) : window (*parent, 10, 30, 300, 220)
274    {
275       SelectInput(ExposureMask, 1);
276       Background(color("lightyellow"));
277    }
278
279    virtual int EV_Expose(XExposeEvent);
280 };
281
282 </verbatim>
283
284 We define two member functions for our <code>doodle_view</code> class: The contructor
285 function <code>doodle_view()</code> and the overridden event handler for
286 <emph>Expose</emph> events, <code>EV_Expose()</code>.
287 In the constructor, we pass the parent window to the contructor of the base class,
288 <code>window</code> and add the default geometry of our subwindow.
289 The geometry for a subwindow is very similar to drawing a rectangle.
290 The four numbers are the X and Y coordinate of the top left corner, the width
291 and the height of the subwindow, relative to the parent window.
292 Inside the contructor, we tell <strong>AXE</strong> that we want to handle
293 <emph>Expose</emph> events by calling <code>SelectInput()</code>.
294 The first parameter of <code>SelectInput()</code> is a bitmask of the events
295 we want to select.
296 The binary values and their names for the mask are the same as the ones defined
297 for the X library.
298 The second parameter is a boolean value which is '1' if you want to turn selection
299 of the events on and '0' of you want these events to be turned off.
300 We also add a little color to the subwindow, so it stands out more clearly
301 in the parent window.
302 The parent window specifies in which window we want to put our subwindow.
303 In doodle, we create the subwindow as a child of the top level window we created earlier.
304 A pointer to the subwindow is created inside the <code>doodle class</code>:
305
306 <verbatim>
307
308 class doodle: public xapplication
309 {
310    managed_window *main_frame;
311    doodle_view    *draw_frame;
312
313
314 </verbatim>
315
316 The actual creation of the subwindow is put in the <code>SetupResources()</code>
317 member funtion of the <code>doodle</code> class, right after the creation
318 of the top level window:
319
320 <verbatim>
321 void doodle::SetupResources()
322 {
323    main_frame = new managed_window("Doodling with AXE");
324    main_frame-&gt;Map();
325
326    draw_frame = new doodle_view(main_frame);
327    draw_frame-&gt;Map();
328 }
329 </verbatim>
330
331 Note that we have to <emph>Map</emph> the subwindow, just like the top level
332 window to make it visible.
333 </para>
334
335 <para>
336 Finally, we have to implement the event handler function of the <emph>Expose</emph>
337 event handler, <code>EV_Expose()</code>.
338 As you may have noticed, the <code>DrawRectangle()</code> is removed from the
339 <code>SetupResources()</code> function.
340 We now wait for an expose event from the X server to do the actual drawing.
341 Every time our window becomes 'exposed' the X server sends an <emph>Expose</emph>
342 event, to which we react by redrawing our rectangle in the window.
343 Here is the implementation of the <emph>Expose</emph> event handler:
344
345 <verbatim>
346
347 int doodle_view::EV_Expose(XExposeEvent ev)
348 {
349    gc    graphic("black");
350
351    DrawRectangle(graphic, 50, 70, 200, 100);
352
353    return 1;
354 }
355 </verbatim>
356
357 Here you see the <code>gc</code> object and the <code>DrawRectangle()</code>
358 again, nearly the same as we previously had in the <code>SetupResources()</code>
359 function of the <code>doodle</code> class.
360 There is one difference: The pointer to the window (<code>main_frame-&gt;</code>
361 in our previous example) is removed from the function call.
362 This is because we are now inside a member funtion of the <code>doodle_view</code>
363 class and our window is passed implicitly as the <strong>this</strong> pointer
364 of the object itself.
365 </para>
366
367 <para>
368 The complete source code of the second doodle example is in the file
369 <strong>demos/doodle2.cpp</strong> of the <strong>AXE</strong> distribution.
370 If you compile and run doodle2, it should look like this:
371
372 <para>
373 <picture src='tutor2.2.png' eps='tutor2.2.eps'/>
374 </para>
375
376 You can now move the window all over the screen, resize it, move other windows
377 over the doodle window and the rectangle we draw in the little yellow window
378 should stay intact.
379 </para>
380
381 </section>
382
383 <section>
384 <heading>Quitting the application</heading>
385
386 <para>
387 Up until now, we do not have a decent way to quit the doodle application.
388 You have to kill doodle by sending it a signal, like hitting ctrl-C on your
389 keyboard.
390 It's about time to remedy that situation.
391 There are many ways to close an application, like hitting a specific key
392 ('q' for quit might be a good one), clicking on the close button provided
393 by the window manager or providing a 'Quit' button or menu item in the
394 application itself.
395 We will explore all of these possibilities in later chapters.
396 For now, to keep things simple, we will use the keyboard to quit doodle.
397 </para>
398
399 <para>
400 When the user hits a key while the focus is on the doodle window, the X server
401 sends a <emph>KeyPress</emph> event to our application.
402 This <emph>KeyPress</emph> event is dispatched by <strong>AXE</strong> to the
403 window on which the key was pressed, just as <emph>Expose</emph> events are
404 dispatched to the appropriate window.
405 In <strong>AXE</strong>, you can use any event to quit your application program.
406 All you need to do is return the value 0 (zero) from the event handler function.
407 You may have noticed in the previous section that the <code>EV_Expose()</code>
408 handler function returned the value 1 (one).
409 This return value tells the <strong>AXE</strong> library not the quit the program
410 after the event is handled.
411 If you return 0 (zero) from an event handler function, <strong>AXE</strong> will
412 destroy all your windows, close the display connection with the X server
413 and quit the application.
414 </para>
415
416 <para>
417 So, to quit doodle on a key stroke, we select <emph>KeyPress</emph> events
418 next to <emph>Expose</emph> events in our subwindow and override the
419 <code>EV_KeyPress()</code> event handler function.
420 To select <emph>KeyPress</emph> events, we add another <code>SelectInput()</code>
421 in our <code>doodle_view</code> contructor:
422
423 <verbatim>
424    doodle_view(window *parent) : window (*parent, 10, 30, 300, 220)
425    {
426       SelectInput(ExposureMask, 1);
427       SelectInput(KeyPressMask, 1);
428       Background(color("lightyellow"));
429    }
430 </verbatim>
431
432 Next, also in the <code>doodle_view</code> class declaration, we add the
433 declaration of the member function to handle the KeyPress events:
434
435 <verbatim>
436    virtual int EV_KeyPress(XKeyEvent ev);
437 </verbatim>
438
439 The implementation of the event handler is very trivial.
440 Just return the value 0 (zero) and doodle will close down when any key
441 is pressed in the light yellow window:
442
443 <verbatim>
444 int doodle_view::EV_KeyPress(XKeyEvent ev)
445 {
446    return 0;
447 }
448 </verbatim>
449
450 Having any key at all, even the Ctrl or the CapsLock key, quit doodle is a bit
451 cruel, don;t you think.
452 So, let's restrain the quitting to just the lower case 'q' key.
453 When we get an event from the X server in one of our event handling functions,
454 all kinds of information about that event is passed in the <emph>ev</emph>
455 parameter.
456 Until now, we silently ignored the <emph>ev</emph> parameter but is this
457 case we need it to find out which key was actually pressed.
458 There is no special provision in <strong>AXE</strong> to do this.
459 There are Xlib functions that do the job just fine.
460 The one Xlib function we use here is <code>XLookupKeysym()</code>, which extracts
461 information from the <code>XKeyEvent</code> structure and returns
462 a standardized code (a <emph>KeySym</emph>) of the key that was actually pressed.
463 For most 'ordinary' keys, the <emph>KeySym</emph> value is the same as the ASCII
464 value.
465 We can use the 'q' key simply by checking the <emph>KeySym</emph> for the
466 value 'q':
467
468 <verbatim>
469 int doodle_view::EV_KeyPress(XKeyEvent ev)
470 {
471    KeySym   key;
472
473    key = XLookupKeysym(&amp;ev, ev.state &amp; 1);
474
475    if (key == 'q')
476    {
477       return 0;
478    }
479    else
480    {
481       return 1;
482    }
483 }
484 </verbatim>
485
486 With this extra check, you can hit any key you want on doodle, but
487 only the 'q' key makes doodle leave the desktop.
488 You can find the complete source of this example in <strong>demos/doodle3.cpp</strong>.
489 </para>
490
491 </section>
492
493 </chapter>
494
495 <!--
496  
497   Drawing
498     tracking mouse events
499     storing the strokes.
500
501   Menus, file IO
502     the file selector.
503     about box
504
505    Window manager
506      changing the title
507      resizing
508      close button
509      icon
510 -->
511 </book>
512
513 </doc>
514
515