| 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> |