7cb02901 |
1 | <?xml version="1.0" encoding="UTF-8" ?> |
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" |
3 | "/usr/share/sgml/docbook/dtd/4.3/xdocbook.dtd"> |
4 | <!--<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" >--> |
5 | |
6 | <book> |
7 | |
8 | <bookinfo> |
9 | <title>Linux Trace Toolkit Viewer Developer Guide</title> |
10 | <authorgroup> |
11 | <author> |
12 | <firstname>Mathieu</firstname> |
13 | <surname>Desnoyers</surname> |
14 | </author> |
15 | </authorgroup> |
16 | |
17 | <date>01/12/2004</date> |
18 | <releaseinfo>1.00.00</releaseinfo> |
19 | |
20 | <abstract> |
21 | <para> |
22 | This document describes the basic steps necessary to develop within the |
23 | <application>Linux Trace Toolkit Viewer</application> project. |
24 | |
25 | </para> |
26 | </abstract> |
27 | |
28 | <keywordset> |
29 | <keyword>Linux Trace Toolkit Viewer</keyword> |
30 | <keyword>text</keyword> |
31 | <keyword>module</keyword> |
32 | <keyword>context</keyword> |
33 | </keywordset> |
34 | |
35 | </bookinfo> |
36 | <chapter> |
37 | <title>Linux Trace Toolkit Viewer Text Module Tutorial</title> |
38 | |
39 | <sect1> |
40 | <title>Introduction</title> |
41 | <para> |
42 | This chapter explains all the steps that are necessary to create a text module |
43 | in LTTV. |
44 | </para> |
45 | </sect1> |
46 | |
47 | <sect1> |
48 | <title>A typical module</title> |
49 | <para> |
50 | A typical module must have a init() and destroy() function. Please refer to |
51 | lttv/modules/text/textDump.c for the detail of these functions. |
52 | </para> |
53 | <para> |
54 | The init() function is called when the library is loaded and destroy() |
55 | inversely. It adds options to the command line by calling "lttv_option_add" from |
56 | option.h |
57 | </para> |
58 | <para> |
59 | The module communicates with the main lttv program through the use of global |
60 | attributes. Use lttv/attribute.h, lttv/iattribute.h and lttv/lttv.h, and then |
61 | LTTV_IATTRIBUTE(lttv_global_attributes()) to get the pointer to these |
62 | global attributes. |
63 | </para> |
64 | <para> |
65 | You can then add your hooks (functions that follows the prototype of a hook, as |
66 | defined in lttv/hook.h) in the different hook lists defined in lttv/lttv.h. Note |
67 | that hooks have an assigned priority. This is necessary to inform the trace |
68 | reader that a specific hook needs to be called, for example, before or after the |
69 | state update done for an event by the state module. For that specific example, a |
70 | hook could use the LTTV_PRIO_STATE-5 to get called before the state update and a |
71 | second hook could use the LTTV_PRIO_STATE+5 to get called after the state |
72 | update. This is especially important for graphical module, which is the subject |
73 | of a the chapter named "Linux Trace Toolkit Viewer Graphical Module Tutorial". |
74 | </para> |
75 | <para> |
76 | You should also take a look at lttv/state.c, where by_id hooks are used. When |
77 | you only need some specific events, you should use this interface. It makes the |
78 | event filtering sooner in the dispatch chain : you hook doesn't have to be |
79 | called for each event, only the ones selected. That improves the performances a |
80 | lot! |
81 | </para> |
82 | <para> |
83 | Note that you should use the lttv_trace_find_hook method from |
84 | lttv/tracecontext.h to connect the hook to the right facility/event type. See |
85 | state.c for an example. A problem that may arise is that the LttvTraceHook |
86 | structure must be passed as hook_data when registering the hook. In fact, it is |
87 | not necessary for it to be directly passed as the hook_data parameter. As long |
88 | as the hook function can access the LttvTraceHook fields necessary to parse the |
89 | LttEvent, there is no problem. In a complex viewer where you need a pointer to |
90 | your own data structure, just keep a pointer to the LttvTraceHook structure |
91 | inside your own data structure, and give to pointer to your data structure in |
92 | parameter as the hook_data. |
93 | </para> |
94 | <para> |
95 | Then, you should use the macro LTTV_MODULE, defined in lttv/module.h. It allows |
96 | you to specify the module name, a short and a long description, the init and |
97 | destroy functions and the module dependencies. That permits to the module |
98 | backend to load the right dependencies when needed. |
99 | </para> |
100 | <para> |
101 | A typical text module will depend on batchAnalysis for the batch computation of a |
102 | trace, and simply register before and after trace hooks, as weel as the most |
103 | important one : a event hook. |
104 | </para> |
105 | </sect1> |
106 | |
107 | <sect1> |
108 | <title>The hooks</title> |
109 | <para> |
110 | The before and after trace hooks only exists to be able to generate a report at |
111 | the end of a trace computation. The effective computation is done by the event |
112 | hooks. |
113 | </para> |
114 | <para> |
115 | These hooks does particular computation on data arriving as argument, a |
116 | call_data. The type of the call_data, when a hook is called during the trace |
117 | read, is a traceset context. It contains all the necessary information about the |
118 | read in progress. This is the base class from which inherits trace set |
119 | state, and trace set/trace/tracefile state is the base classe of trace |
120 | set/trace/tracefile statistics. All these types can be casted to another without |
121 | problem (a TracesetState, for example, can be casted to a TracesetContext, but |
122 | it's not true for the casting between a TraceContext and a TracesetContext, see |
123 | the chapter "How to use the trace reading context" for details). They offer the |
124 | input data and they give a container (the attributes of the trace set/trace/tracefile |
125 | statistics) to write the output of this hook. |
126 | </para> |
127 | <para> |
128 | The idea behind writing in the attributes container is to provide an extensible |
129 | way of storing any type of information. For example, a specific module that adds |
130 | statistics to a trace can store them there, and the statistic printout will |
131 | automatically include the results produced by the specific module. |
132 | </para> |
133 | <para> |
134 | Output data does not necessarily need to be stored in such a global container |
135 | though. If we think of data of which we need to keed track during the execution, |
136 | an event counter for example, we should create our own data structure that |
137 | contains this counter, and pass the address of the allocated structure as the |
138 | hook_data parameter of the hook list creation function. That way, the hook will |
139 | be called with its hook_data as first parameter, which it can read and write. We |
140 | can think of this structure as the data related to the function that persists |
141 | between each call to the hook. You must make sure that you cast the hook_data to |
142 | the type of the structure before you use it in the hook function. |
143 | </para> |
144 | <para> |
145 | The detail about how to access the different fields of the reading context (the |
146 | hook's call_data) will be discussed in the chapter "How to use the trace |
147 | reading context". |
148 | </para> |
149 | </sect1> |
150 | |
151 | |
152 | </chapter> |
153 | |
154 | |
155 | <chapter> |
156 | <title>How to use the Linux Trace Toolkit Viewer's Reading Context</title> |
157 | |
158 | <sect1> |
159 | <title>Introduction</title> |
160 | <para> |
161 | This chapter describes how to use the Linux Trace Toolkit reading context, a |
162 | data structure that is given as call data parameter of the modules'callbacks. |
163 | </para> |
164 | <para> |
165 | Linux Trace Toolkit Viewer provides a backend that reads the traces. In combines |
166 | them in tracesets. A trace is an abstaction over many tracefiles, one per CPU. |
167 | LTTV reads the whole trace together, providing the events to modules by calling |
168 | their pre-registered hook lists in a chronological order. |
169 | </para> |
170 | </sect1> |
171 | |
172 | <sect1> |
173 | <title>Why an event driven trace reader ?</title> |
174 | <para> |
175 | The complexity of synchronizing the tracesets is then hidden to the viewer. Some |
176 | future plans involve to be able to put many traces together in a trace set. |
177 | Before this becomes possible, the time of each trace must be synchronized in |
178 | some way. Some work is actually done to create a module that uses the network |
179 | traffic shared by different computers to synchronize the time of different |
180 | traces. |
181 | </para> |
182 | <para> |
183 | In order to make each module integrate well with each other, we made the trace |
184 | reader a simple hook caller. For each event it reads, it just calls the hook |
185 | lists for this event. For each event, it calls the by_id specific hooks |
186 | registered for this event and also the "main" hooks, registered for all events. |
187 | Note that the two hook lists are merged when called so the priority of the |
188 | hooks of each list is respected. For example, a hook of higher priority (20) in |
189 | the main list will be called before a hook of lower priority (40) from the |
190 | by_id specific list. |
191 | </para> |
192 | </sect1> |
193 | |
194 | <sect1> |
195 | <title>Using the reading context</title> |
196 | <para> |
197 | If you have read the tutorials about writing a text and a graphic module, you |
198 | should be fairly ready to use the information provided to your hook by the |
199 | reading API. |
200 | </para> |
201 | <para> |
202 | The data structures of the reading context are based on the gobject, a |
203 | object-oriented library from the glib. Some evolved types that are found in the |
204 | context also comes from the "glib" (GArray, GHashTable and so on). For detailed |
205 | information about "gobjects" and the "glib", see the <ulink |
206 | url="http://www.gtk.org">www.gtk.org</ulink> website. They provide a complete |
207 | API reference about the data types they provide. |
208 | </para> |
209 | <para> |
210 | The reading context is object oriented. It is described by the lttv/tracecontext.h |
211 | header. Is can be illustrated with this UML class diagram : |
212 | </para> |
213 | <para> |
214 | <screenshot> |
215 | <mediaobject> |
216 | <imageobject> |
217 | <imagedata srccredit="Mathieu Desnoyers, 2004" fileref="lttv-context.png" |
218 | format="PNG" align="center"/> |
219 | </imageobject> |
220 | <imageobject> |
221 | <imagedata srccredit="Mathieu Desnoyers, 2004" |
222 | fileref="lttv-context.eps" |
223 | format="EPS" align="center"/> |
224 | </imageobject> |
225 | <!--<imagedata srccredit="Mathieu Desnoyers, 2004" fileref="lttv-numbered-6.svg" |
226 | format="SVG" align="center" scalefit="1"/> |
227 | </imageobject>--> |
228 | <caption><para>Linux Trace Toolkit Viewer Reading Context Class Diagram</para></caption> |
229 | </mediaobject> |
230 | </screenshot> |
231 | </para> |
232 | <para> |
233 | Though, for performance's sake, navigating through it is not as encapsulated as |
234 | it could. Consider the class attributes to be all public (no get/set functions). |
235 | Sometimes, iteration upon a specific element can be uneasy. For example, you may |
236 | have to get the number of tracefiles in a trace from the "vt" field of the trace |
237 | context to be able to iterate over all the tracefiles contained by the trace. |
238 | </para> |
239 | <para> |
240 | To facilitate the common operations on the reading context, LTTV now provides a |
241 | header that consists of simple macros : lttv/contextmacros.h. It gives an object |
242 | look-and-feel to the context classes. Simple "GET" macros can be used to easily |
243 | access the different fields are iterate over the elements (and get the total |
244 | number of elements too). |
245 | </para> |
246 | </sect1> |
247 | </chapter> |
248 | |
249 | <chapter> |
250 | <title>Linux Trace Toolkit Viewer Graphical Module Tutorial</title> |
251 | <sect1> |
252 | <title>Introduction</title> |
253 | <para> |
254 | As a matter of fact, most of the things said for the text modules still hold for |
255 | the graphical modules. However, the fact that every module must instanciate |
256 | objects (called viewers) more than once changes a little bit the scenario. It is |
257 | then impossible to use static structures : everything must be instanciated at |
258 | run-time, except the structures related to the module itself. |
259 | </para> |
260 | </sect1> |
261 | <sect1> |
262 | <title>The static part of a module</title> |
263 | <para> |
264 | A module must have a static part to be able to get loaded just like a text |
265 | module. Now, let's see the differences. The graphical module depends on the |
266 | "lttvwindow" module. See module.c from the control flow viewer for an example. |
267 | </para> |
268 | <para> |
269 | The init() and destroy() functions must register functions that can be called by |
270 | user interaction to instanciate the viewers. That's the goal of |
271 | lttvwindow_register_constructor() and lttvwindow_unregister_constructor() : |
272 | they register a function with a menu entry and an icon. The main window will |
273 | shown them in its interface and call the function when the button or menu item |
274 | is selected. This hook function must receive a pointer to a "Tab" object in |
275 | parameter. |
276 | </para> |
277 | <para> |
278 | Also note the presence of the destroy_walk() method. It is called when the |
279 | module is unloaded : it must destroy all the instances of the viewers from the |
280 | module. |
281 | </para> |
282 | </sect1> |
283 | <sect1> |
284 | <title>The dynamic part of a module : the viewer</title> |
285 | <para> |
286 | The dynamic part starts with the constructor of the viewer. It is called by the |
287 | main window when the corresponding button or menu item is selected. See |
288 | h_guicontrolflow() from control flow viewer eventhooks.c for an example. It does |
289 | basic connexion to the tab's events available : time window change notification, |
290 | current time notification, redraw notification, continue notification. All these |
291 | function should be implemented in your viewer if you want the data you shown to |
292 | be synchronised with the main window and the other viewers. It also calls the |
293 | background computation, which will be discussed in the next section. |
294 | </para> |
295 | <para> |
296 | This is also at this point that the viewer does create it's own memory footprint |
297 | : its inner structure. This structure will have to be passed as hook_data to |
298 | each function registered by the viewer : this is what makes the functions |
299 | "belong" to this instance of the viewer. |
300 | </para> |
301 | </sect1> |
302 | <sect1> |
303 | <title>How to request background computation</title> |
304 | <para> |
305 | You will also notice the presence of a request_background_data() called in the |
306 | constructor. This function, in eventhooks.c, does verify for the presence of the |
307 | state information that could be precomputed by the main window background |
308 | computation. If it has not been precomputed, we ask for a computation and show |
309 | partial data. We also register a hook that will be called (notified) by the main |
310 | window when the requested data will become ready, so the viewer can update |
311 | itself with the new data. If no partial information would have made sense in a |
312 | particular viewer, one could choose to shown a "waiting for computation" message |
313 | while waiting for the notification. See lttvwindow/lttvwindowtraces.h for the API |
314 | of the background requests. |
315 | </para> |
316 | </sect1> |
317 | |
318 | <sect1> |
319 | <title>How to handle events and use the graphical trace reading service</title> |
320 | <para> |
321 | The events that are delivered by the main window are defined in |
322 | lttvwindow/lttvwindow.h. Let's describe them and their use in details. Remember |
323 | that you can refer to the control flow viewer module as an example. |
324 | </para> |
325 | |
326 | <sect2> |
327 | <title>Module Related API</title> |
328 | <para> |
329 | A viewer plugin is, before anything, a plugin. As a dynamically loadable |
330 | module, it thus has an init and a destroy function called whenever it is |
331 | loaded/initialized and unloaded/destroyed. A graphical module depends on |
332 | lttvwindow for construction of its viewer instances. In order to achieve |
333 | this, it must register its constructor function to the main window along |
334 | with button description or text menu entry description. A module keeps |
335 | a list of every viewer that currently sits in memory so it can destroy |
336 | them before the module gets unloaded/destroyed. |
337 | </para> |
338 | <para> |
339 | The contructor registration to the main windows adds button and menu |
340 | entry to each main window, thus allowing instanciation of viewers. |
341 | </para> |
342 | </sect2> |
343 | <sect2> |
344 | <title>Main Window</title> |
345 | <para> |
346 | The main window is a container that offers menus, buttons and a |
347 | notebook. Some of those menus and buttons are part of the core of the |
348 | main window, others are dynamically added and removed when modules are |
349 | loaded/unloaded. |
350 | </para> |
351 | <para> |
352 | The notebook contains as much tabs as wanted. Each tab is linked with |
353 | a set of traces (traceset). Each trace contains many tracefiles (one |
354 | per cpu). A trace corresponds to a kernel being traced. A traceset |
355 | corresponds to many traces read together. The time span of a traceset |
356 | goes from the earliest start of all the traces to the latest end of all |
357 | the traces. |
358 | </para> |
359 | <para> |
360 | Inside each tab are added the viewers. When they interact with the main |
361 | window through the lttvwindow API, they affect the other viewers located |
362 | in the same tab as they are. |
363 | </para> |
364 | <para> |
365 | The insertion of many viewers in a tab permits a quick look at all the |
366 | information wanted in a glance. The main window does merge the read |
367 | requests from all the viewers in the same tab in a way that every viewer |
368 | will get exactly the events it asked for, while the event reading loop |
369 | and state update are shared. It improves performance of events delivery |
370 | to the viewers. |
371 | </para> |
372 | </sect2> |
373 | |
374 | <sect2> |
375 | <title>Viewer Instance Related API</title> |
376 | <para> |
377 | The lifetime of a viewer is as follows. The viewer constructor function |
378 | is called each time an instance view is created (one subwindow of this |
379 | viewer type is created by the user either by clicking on the menu item |
380 | or the button corresponding to the viewer). Thereafter, the viewer gets |
381 | hooks called for different purposes by the window containing it. These |
382 | hooks are detailed below. It also has to deal with GTK Events. Finally, |
383 | it can be destructed by having its top level widget unreferenced by the |
384 | main window or by any GTK Event causing a "destroy-event" signal on the |
385 | its top widget. Another possible way for it do be destroyed is if the |
386 | module gets unloaded. The module unload function will have to emit a |
387 | "destroy" signal on each top level widget of all instances of its viewers. |
388 | </para> |
389 | </sect2> |
390 | <sect2> |
391 | <title>Notices from Main Window</title> |
392 | <variablelist> |
393 | <varlistentry> |
394 | <term>time_window</term> |
395 | <listitem> |
396 | <simpara>This is the time interval visible on the viewer's tab. Every |
397 | viewer that cares about being synchronised by respect to the |
398 | time with other viewers should register to this notification. |
399 | They should redraw all or part of their display when this |
400 | occurs.</simpara> |
401 | </listitem> |
402 | </varlistentry> |
403 | <varlistentry> |
404 | <term>traceset</term> |
405 | <listitem> |
406 | <simpara>This notification is called whenever a trace is added/removed |
407 | from the traceset. As it affects all the data displayed by the |
408 | viewer, it sould redraw itself totally.</simpara> |
409 | </listitem> |
410 | </varlistentry> |
411 | |
412 | <varlistentry> |
413 | <term>filter</term> |
414 | <listitem> |
415 | <simpara>This feature has not been implemented yet.</simpara> |
416 | </listitem> |
417 | </varlistentry> |
418 | |
419 | <varlistentry> |
420 | <term>current_time</term> |
421 | <listitem> |
422 | <simpara>Being able to zoom nearer a specific time or highlight a specific |
423 | time on every viewer in synchronicity implies that the viewer |
424 | has to shown a visual sign over the drawing or select an event |
425 | when it receives this notice. It should also inform the main |
426 | window with the appropriate report API function when a user |
427 | selects a specific time as being the current time.</simpara> |
428 | </listitem> |
429 | </varlistentry> |
430 | |
431 | <varlistentry> |
432 | <term>dividor</term> |
433 | <listitem> |
434 | <simpara>This notice links the positions of the horizontal dividors |
435 | between the graphic display zone of every viewer and their Y axis, |
436 | typically showing processes, cpus, ...</simpara> |
437 | </listitem> |
438 | </varlistentry> |
439 | </variablelist> |
440 | </sect2> |
441 | <sect2> |
442 | <title>Reporting Changes to the Main Window</title> |
443 | <para> |
444 | In most cases, the enclosing window knows about updates such as described |
445 | in the Notification section higher. There are a few cases, however, where |
446 | updates are caused by actions known by a view instance. For example, |
447 | clicking in a view may update the current time; all viewers within |
448 | the same window must be told about the new current time to change the |
449 | currently highlighted time point. A viewer reports such events by calling |
450 | lttvwindow_report_current_time on its lttvwindow. The lttvwindow will |
451 | consequently call current_time_notify for each of its contained viewers. |
452 | </para> |
453 | <para> |
454 | Available report methods are : |
455 | <itemizedlist> |
456 | <listitem> |
457 | <simpara> |
458 | lttvwindow_report_time_window : reports the new time window. |
459 | </simpara> |
460 | </listitem> |
461 | <listitem> |
462 | <simpara> |
463 | lttvwindow_report_current_time : reports the new current time. |
464 | </simpara> |
465 | </listitem> |
466 | <listitem> |
467 | <simpara> |
468 | lttvwindow_report_dividor : reports the new horizontal dividor's position. |
469 | </simpara> |
470 | </listitem> |
471 | </itemizedlist> |
472 | </para> |
473 | </sect2> |
474 | |
475 | <sect2> |
476 | <title>Requesting Events to Main Window</title> |
477 | <para> |
478 | Events can be requested by passing a EventsRequest structure to the main |
479 | window. They will be delivered later when the next g_idle functions |
480 | will be called. Event delivery is done by calling the event hook for |
481 | this event ID, or the main event hooks. A pointer to the EventsRequest |
482 | structure is passed as hook_data to the event hooks of the viewers. |
483 | </para> |
484 | <para> |
485 | EventsRequest consists in |
486 | <itemizedlist> |
487 | <listitem> |
488 | <simpara> |
489 | a pointer to the viewer specific data structure |
490 | </simpara> |
491 | </listitem> |
492 | <listitem> |
493 | <simpara> |
494 | a start timestamp or position |
495 | </simpara> |
496 | </listitem> |
497 | <listitem> |
498 | <simpara> |
499 | a stop_flag, ending the read process when set to TRUE |
500 | </simpara> |
501 | </listitem> |
502 | <listitem> |
503 | <simpara> |
504 | a end timestamp and/or position and/or number of events to read |
505 | </simpara> |
506 | </listitem> |
507 | <listitem> |
508 | <simpara> |
509 | hook lists to call for traceset/trace/tracefile begin and end, and for each |
510 | event (event hooks and event_by_id hooks). |
511 | </simpara> |
512 | </listitem> |
513 | </itemizedlist> |
514 | </para> |
515 | <para> |
516 | The main window will deliver events for every EventRequests it has |
517 | pending through an algorithm that guarantee that all events requested, |
518 | and only them, will be delivered to the viewer between the call of the |
519 | tracefile_begin hooks and the call of the tracefile_end hooks. |
520 | </para> |
521 | <para> |
522 | If a viewer wants to stop the event request at a certain point inside the |
523 | event hooks, it has to set the stop_flag to TRUE and return TRUE from the |
524 | hook function. Then return value will stop the process traceset. Then, |
525 | the main window will look for the stop_flag and remove the EventRequests |
526 | from its lists, calling the process_traceset_end for this request (it |
527 | removes hooks from the context and calls the after hooks). |
528 | </para> |
529 | <para> |
530 | It no stop_flag is risen, the end timestamp, end position or number |
531 | of events to read has to be reached to determine the end of the |
532 | request. Otherwise, the end of traceset does determine it. |
533 | </para> |
534 | </sect2> |
535 | <sect2> |
536 | <title>GTK Events</title> |
537 | <sect3> |
538 | <title>Events and Signals</title> |
539 | <para> |
540 | GTK is quite different from the other graphical toolkits around |
541 | there. The main difference resides in that there are many X Windows |
542 | inside one GtkWindow, instead of just one. That means that X events are |
543 | delivered by the glib main loop directly to the widget corresponding to |
544 | the GdkWindow affected by the X event. |
545 | </para> |
546 | <para> |
547 | Event delivery to a widget emits a signal on that widget. Then, if a |
548 | handler is connected to this widget's signal, it will be executed. There |
549 | are default handlers for signals, connected at class instantiation |
550 | time. There is also the possibility to connect other handlers to these |
551 | signals, which is what should be done in most cases when a viewer needs |
552 | to interact with X in any way. |
553 | </para> |
554 | |
555 | <para> |
556 | Signal emission and propagation is described there : |
557 | |
558 | <itemizedlist> |
559 | <listitem> |
560 | <simpara> |
561 | http://www.gtk.org/tutorial/sec-signalemissionandpropagation.html |
562 | </simpara> |
563 | </listitem> |
564 | </itemizedlist> |
565 | </para> |
566 | |
567 | <para> |
568 | For further information on the GTK main loop (now a wrapper over glib main loop) |
569 | see : |
570 | |
571 | <itemizedlist> |
572 | <listitem> |
573 | <simpara> |
574 | http://developer.gnome.org/doc/API/2.0/gtk/gtk-General.html |
575 | </simpara> |
576 | </listitem> |
577 | <listitem> |
578 | <simpara> |
579 | http://developer.gnome.org/doc/API/2.0/glib/glib-The-Main-Event-Loop.html |
580 | </simpara> |
581 | </listitem> |
582 | </itemizedlist> |
583 | </para> |
584 | |
585 | |
586 | <para> |
587 | For documentation on event handling in GTK/GDK, see : |
588 | |
589 | <itemizedlist> |
590 | <listitem> |
591 | <simpara> |
592 | http://developer.gnome.org/doc/API/2.0/gdk/gdk-Events.html |
593 | </simpara> |
594 | </listitem> |
595 | <listitem> |
596 | <simpara> |
597 | http://developer.gnome.org/doc/API/2.0/gdk/gdk-Event-Structures.html |
598 | </simpara> |
599 | </listitem> |
600 | </itemizedlist> |
601 | </para> |
602 | |
603 | |
604 | <para> |
605 | Signals can be connected to handlers, emitted, propagated, blocked, |
606 | stopped. See : |
607 | |
608 | <itemizedlist> |
609 | <listitem> |
610 | <simpara> |
611 | http://developer.gnome.org/doc/API/2.0/gobject/gobject-Signals.html |
612 | </simpara> |
613 | </listitem> |
614 | </itemizedlist> |
615 | </para> |
616 | |
617 | </sect3> |
618 | |
619 | |
620 | <sect3> |
621 | <title>The "expose_event"</title> |
622 | <para> |
623 | Provides the exposed region in the GdkEventExpose structure. |
624 | </para> |
625 | <para> |
626 | There are two ways of dealing with exposures. The first one is to directly |
627 | draw on the screen and the second one is to draw in a pixmap buffer, |
628 | and then to update the screen when necessary. |
629 | </para> |
630 | <para> |
631 | In the first case, the expose event will be responsible for registering |
632 | hooks to process_traceset and require time intervals to the main |
633 | window. So, in this scenario, if a part of the screen is damaged, the |
634 | trace has to be read to redraw the screen. |
635 | </para> |
636 | <para> |
637 | In the second case, with a pixmap buffer, the expose handler is only |
638 | responsible of showing the pixmap buffer on the screen. If the pixmap |
639 | buffer has never been filled with a drawing, the expose handler may ask |
640 | for it to be filled. |
641 | </para> |
642 | <para> |
643 | The interest of using events request to the main window instead of reading |
644 | the events directly from the trace comes from the fact that the main |
645 | window does merge requests from the different viewers in the same tab so |
646 | that the read loop and the state update is shared. As viewers will, in |
647 | the common scenario, request the same events, only one pass through the |
648 | trace that will call the right hooks for the right intervals will be done. |
649 | </para> |
650 | <para> |
651 | When the traceset read is over for a events request, the traceset_end |
652 | hook is called. It has the responsibility of finishing the drawing if |
653 | some parts still need to be drawn and to show it on the screen (if the |
654 | viewer uses a pixmap buffer). |
655 | </para> |
656 | <para> |
657 | It can add dotted lines and such visual effects to enhance the user's |
658 | experience. |
659 | </para> |
660 | </sect3> |
661 | </sect2> |
662 | </sect1> |
663 | |
664 | </chapter> |
665 | |
666 | |
667 | |
668 | </book> |