fix seek so that adding and removing a trace from a traceset will work
[lttv.git] / ltt / branches / poly / lttv / modules / gui / controlflow / eventhooks.c
CommitLineData
ce0214a6 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19
f0d936c0 20/*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
23
f0d936c0 24
b9a010a2 25/* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
27 *
e92eabaf 28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
b9a010a2 31 *
e92eabaf 32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
b9a010a2 34 *
e92eabaf 35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
b9a010a2 37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
e92eabaf 40 * corresponding to it is over, which happens to be at the next before_schedchange
b9a010a2 41 * hook.
42 *
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
45 * line/background.
46 */
47
4e4d11b3 48#ifdef HAVE_CONFIG_H
49#include <config.h>
50#endif
b9a010a2 51
cf6cb7e0 52//#define PANGO_ENABLE_BACKEND
558aa013 53#include <gtk/gtk.h>
54#include <gdk/gdk.h>
5f16133f 55#include <glib.h>
80a52ff8 56#include <assert.h>
50439712 57#include <string.h>
319e9d81 58#include <stdio.h>
5f16133f 59
cf6cb7e0 60//#include <pango/pango.h>
61
80a52ff8 62#include <ltt/event.h>
4ba42155 63#include <ltt/time.h>
50439712 64#include <ltt/type.h>
2c82c4dc 65#include <ltt/trace.h>
80a52ff8 66
2a2fa4f0 67#include <lttv/lttv.h>
558aa013 68#include <lttv/hook.h>
80a52ff8 69#include <lttv/state.h>
2d262115 70#include <lttvwindow/lttvwindow.h>
6395d57c 71#include <lttvwindow/lttvwindowtraces.h>
0de51231 72#include <lttvwindow/support.h>
80a52ff8 73
f0d936c0 74
a117e3f7 75#include "eventhooks.h"
76#include "cfv.h"
77#include "processlist.h"
78#include "drawing.h"
5f16133f 79
80a52ff8 80
1a31868c 81#define MAX_PATH_LEN 256
82
0de51231 83extern GSList *g_legend_list;
84
b9a010a2 85
6395d57c 86/* Action to do when background computation completed.
87 *
e800cf84 88 * Wait for all the awaited computations to be over.
6395d57c 89 */
90
91gint background_ready(void *hook_data, void *call_data)
92{
93 ControlFlowData *control_flow_data = (ControlFlowData *)hook_data;
94 LttvTrace *trace = (LttvTrace*)call_data;
95
e800cf84 96 control_flow_data->background_info_waiting--;
97
98 if(control_flow_data->background_info_waiting == 0) {
4a24fa1f 99 g_message("control flow viewer : background computation data ready.");
6395d57c 100
e800cf84 101 drawing_clear(control_flow_data->drawing);
102 processlist_clear(control_flow_data->process_list);
07390ec1 103 gtk_widget_set_size_request(
104 control_flow_data->drawing->drawing_area,
105 -1, processlist_get_height(control_flow_data->process_list));
e800cf84 106 redraw_notify(control_flow_data, NULL);
b9a010a2 107 }
6395d57c 108
109 return 0;
110}
111
112
113/* Request background computation. Verify if it is in progress or ready first.
e800cf84 114 * Only for each trace in the tab's traceset.
6395d57c 115 */
116void request_background_data(ControlFlowData *control_flow_data)
117{
e800cf84 118 LttvTracesetContext * tsc =
119 lttvwindow_get_traceset_context(control_flow_data->tab);
120 gint num_traces = lttv_traceset_number(tsc->ts);
6395d57c 121 gint i;
122 LttvTrace *trace;
123
124 LttvHooks *background_ready_hook =
125 lttv_hooks_new();
126 lttv_hooks_add(background_ready_hook, background_ready, control_flow_data,
127 LTTV_PRIO_DEFAULT);
e800cf84 128 control_flow_data->background_info_waiting = 0;
6395d57c 129
130 for(i=0;i<num_traces;i++) {
e800cf84 131 trace = lttv_traceset_get(tsc->ts, i);
6395d57c 132
133 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE) {
134
135 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
136 trace) == FALSE) {
137 /* We first remove requests that could have been done for the same
138 * information. Happens when two viewers ask for it before servicing
139 * starts.
140 */
141 lttvwindowtraces_background_request_remove(trace, "state");
142 lttvwindowtraces_background_request_queue(trace,
143 "state");
144 lttvwindowtraces_background_notify_queue(control_flow_data,
145 trace,
146 ltt_time_infinite,
147 NULL,
148 background_ready_hook);
e800cf84 149 control_flow_data->background_info_waiting++;
6395d57c 150 } else { /* in progress */
151
152 lttvwindowtraces_background_notify_current(control_flow_data,
153 trace,
154 ltt_time_infinite,
155 NULL,
156 background_ready_hook);
e800cf84 157 control_flow_data->background_info_waiting++;
6395d57c 158 }
4368b993 159 } else {
160 /* Data ready. Be its nature, this viewer doesn't need to have
161 * its data ready hook called htere, because a background
162 * request is always linked with a redraw.
163 */
6395d57c 164 }
4368b993 165
6395d57c 166 }
167
168 lttv_hooks_destroy(background_ready_hook);
169}
170
171
172
173
f0d936c0 174/**
175 * Event Viewer's constructor hook
176 *
177 * This constructor is given as a parameter to the menuitem and toolbar button
178 * registration. It creates the list.
ca0f8a8e 179 * @param tab A pointer to the parent tab.
f0d936c0 180 * @return The widget created.
181 */
182GtkWidget *
d47b33d2 183h_guicontrolflow(Tab *tab)
f0d936c0 184{
d47b33d2 185 g_info("h_guicontrolflow, %p", tab);
68997a22 186 ControlFlowData *control_flow_data = guicontrolflow() ;
a56a1ba4 187
ca0f8a8e 188 control_flow_data->tab = tab;
a56a1ba4 189
a56a1ba4 190 // Unreg done in the GuiControlFlow_Destructor
6395d57c 191 lttvwindow_register_traceset_notify(tab,
192 traceset_notify,
193 control_flow_data);
194
ca0f8a8e 195 lttvwindow_register_time_window_notify(tab,
224446ce 196 update_time_window_hook,
197 control_flow_data);
ca0f8a8e 198 lttvwindow_register_current_time_notify(tab,
224446ce 199 update_current_time_hook,
200 control_flow_data);
ca0f8a8e 201 lttvwindow_register_redraw_notify(tab,
202 redraw_notify,
203 control_flow_data);
204 lttvwindow_register_continue_notify(tab,
205 continue_notify,
206 control_flow_data);
667ca2a0 207 request_background_data(control_flow_data);
6395d57c 208
ca0f8a8e 209
68997a22 210 return guicontrolflow_get_widget(control_flow_data) ;
a56a1ba4 211
f0d936c0 212}
213
0de51231 214void legend_destructor(GtkWindow *legend)
215{
216 g_legend_list = g_slist_remove(g_legend_list, legend);
217}
218
219/* Create a popup legend */
220GtkWidget *
221h_legend(Tab *tab)
222{
223 g_info("h_legend, %p", tab);
224
225 GtkWindow *legend = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
226
227 g_legend_list = g_slist_append(
228 g_legend_list,
229 legend);
230
231 g_object_set_data_full(
232 G_OBJECT(legend),
233 "legend",
234 legend,
235 (GDestroyNotify)legend_destructor);
236
237 gtk_window_set_title(legend, "Control Flow View Legend");
238
239 GtkWidget *pixmap = create_pixmap(GTK_WIDGET(legend), "lttv-color-list.png");
240
241 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
242 // GDK_PIXMAP(pixmap), NULL));
243
244 gtk_container_add(GTK_CONTAINER(legend), GTK_WIDGET(pixmap));
245
246 gtk_widget_show(GTK_WIDGET(pixmap));
247 gtk_widget_show(GTK_WIDGET(legend));
248
249
250 return NULL; /* This is a popup window */
251}
252
253
3cff8cc1 254int event_selected_hook(void *hook_data, void *call_data)
f0d936c0 255{
68997a22 256 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
14963be0 257 guint *event_number = (guint*) call_data;
f0d936c0 258
2a2fa4f0 259 g_debug("DEBUG : event selected by main window : %u", *event_number);
a56a1ba4 260
2eef04b5 261 return 0;
f0d936c0 262}
263
9a1ec01b 264/* Function that selects the color of status&exemode line */
6550d711 265static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
9a1ec01b 266{
267 PropertiesLine prop_line;
268 prop_line.line_width = 2;
269 prop_line.style = GDK_LINE_SOLID;
270 prop_line.y = MIDDLE;
271 //GdkColormap *colormap = gdk_colormap_get_system();
272
9a1ec01b 273 if(process->state->s == LTTV_STATE_RUN) {
274 if(process->state->t == LTTV_STATE_USER_MODE)
275 prop_line.color = drawing_colors[COL_RUN_USER_MODE];
276 else if(process->state->t == LTTV_STATE_SYSCALL)
277 prop_line.color = drawing_colors[COL_RUN_SYSCALL];
278 else if(process->state->t == LTTV_STATE_TRAP)
279 prop_line.color = drawing_colors[COL_RUN_TRAP];
280 else if(process->state->t == LTTV_STATE_IRQ)
281 prop_line.color = drawing_colors[COL_RUN_IRQ];
282 else if(process->state->t == LTTV_STATE_MODE_UNKNOWN)
283 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
284 else
285 g_assert(FALSE); /* RUNNING MODE UNKNOWN */
286 } else if(process->state->s == LTTV_STATE_WAIT) {
287 /* We don't show if we wait while in user mode, trap, irq or syscall */
288 prop_line.color = drawing_colors[COL_WAIT];
289 } else if(process->state->s == LTTV_STATE_WAIT_CPU) {
290 /* We don't show if we wait for CPU while in user mode, trap, irq
291 * or syscall */
292 prop_line.color = drawing_colors[COL_WAIT_CPU];
293 } else if(process->state->s == LTTV_STATE_ZOMBIE) {
294 prop_line.color = drawing_colors[COL_ZOMBIE];
295 } else if(process->state->s == LTTV_STATE_WAIT_FORK) {
296 prop_line.color = drawing_colors[COL_WAIT_FORK];
297 } else if(process->state->s == LTTV_STATE_EXIT) {
298 prop_line.color = drawing_colors[COL_EXIT];
299 } else if(process->state->s == LTTV_STATE_UNNAMED) {
300 prop_line.color = drawing_colors[COL_UNNAMED];
301 } else
302 g_assert(FALSE); /* UNKNOWN STATE */
303
304 return prop_line;
305
306}
307
c8bba5fa 308
e92eabaf 309/* before_schedchange_hook
b9a010a2 310 *
f0d936c0 311 * This function basically draw lines and icons. Two types of lines are drawn :
312 * one small (3 pixels?) representing the state of the process and the second
313 * type is thicker (10 pixels?) representing on which CPU a process is running
314 * (and this only in running state).
315 *
316 * Extremums of the lines :
317 * x_min : time of the last event context for this process kept in memory.
318 * x_max : time of the current event.
319 * y : middle of the process in the process list. The process is found in the
320 * list, therefore is it's position in pixels.
321 *
322 * The choice of lines'color is defined by the context of the last event for this
323 * process.
324 */
b9a010a2 325
326
e92eabaf 327int before_schedchange_hook(void *hook_data, void *call_data)
f0d936c0 328{
2c82c4dc 329 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
330 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
b9a010a2 331 ControlFlowData *control_flow_data = events_request->viewer_data;
332
333 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
334
335 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
348c6ba8 336 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
b9a010a2 337
338 LttEvent *e;
2c82c4dc 339 e = ltt_tracefile_get_event(tfc->tf);
b9a010a2 340
341 LttTime evtime = ltt_event_time(e);
fd22065b 342
10a1069a 343 /* we are in a schedchange, before the state update. We must draw the
344 * items corresponding to the state before it changes : now is the right
345 * time to do it.
346 */
b9a010a2 347
10a1069a 348 guint pid_out;
349 guint pid_in;
350 {
2c82c4dc 351 pid_out = ltt_event_get_long_unsigned(e, thf->f1);
352 pid_in = ltt_event_get_long_unsigned(e, thf->f2);
10a1069a 353 }
354
355 {
356 /* For the pid_out */
357 /* First, check if the current process is in the state computation
358 * process list. If it is there, that means we must add it right now and
359 * draw items from the beginning of the read for it. If it is not
360 * present, it's a new process and it was not present : it will
361 * be added after the state update. */
348c6ba8 362 guint cpu = ltt_tracefile_num(tfc->tf);
363 LttvProcessState *process = ts->running_process[cpu];
40debf7b 364 /* unknown state, bad current pid */
348c6ba8 365 if(process->pid != pid_out)
800aa029 366 process = lttv_state_find_process(ts,
367 ltt_tracefile_num(tfc->tf), pid_out);
b9a010a2 368
10a1069a 369 if(process != NULL) {
370 /* Well, the process_out existed : we must get it in the process hash
371 * or add it, and draw its items.
372 */
373 /* Add process to process list (if not present) */
1c736ed5 374 guint pl_height = 0;
10a1069a 375 HashedProcessData *hashed_process_data = NULL;
5c230fc4 376 ProcessList *process_list = control_flow_data->process_list;
10a1069a 377 LttTime birth = process->creation_time;
b9a010a2 378
ac4e21cf 379 hashed_process_data = processlist_get_process_data(process_list,
10a1069a 380 pid_out,
348c6ba8 381 process->cpu,
10a1069a 382 &birth,
ac4e21cf 383 tfc->t_context->index);
384 if(hashed_process_data == NULL)
10a1069a 385 {
386 g_assert(pid_out == 0 || pid_out != process->ppid);
387 /* Process not present */
4e86ae2e 388 ProcessInfo *process_info;
1c736ed5 389 Drawing_t *drawing = control_flow_data->drawing;
10a1069a 390 processlist_add(process_list,
1c736ed5 391 drawing,
10a1069a 392 pid_out,
348c6ba8 393 process->cpu,
10a1069a 394 process->ppid,
395 &birth,
396 tfc->t_context->index,
f4b88a7d 397 process->name,
10a1069a 398 &pl_height,
4e86ae2e 399 &process_info,
10a1069a 400 &hashed_process_data);
1c736ed5 401 gtk_widget_set_size_request(drawing->drawing_area,
402 -1,
403 pl_height);
404 gtk_widget_queue_draw(drawing->drawing_area);
405
10a1069a 406 }
ac4e21cf 407
10a1069a 408 /* Now, the process is in the state hash and our own process hash.
409 * We definitely can draw the items related to the ending state.
410 */
e800cf84 411
b2743953 412 if(ltt_time_compare(hashed_process_data->next_good_time,
413 evtime) > 0)
10a1069a 414 {
b2743953 415 if(hashed_process_data->x.middle_marked == FALSE) {
ac4e21cf 416
fd22065b 417 TimeWindow time_window =
418 lttvwindow_get_time_window(control_flow_data->tab);
419#ifdef EXTRA_CHECK
420 if(ltt_time_compare(evtime, time_window.start_time) == -1
421 || ltt_time_compare(evtime, time_window.end_time) == 1)
422 return;
423#endif //EXTRA_CHECK
d6fef890 424 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 425 guint width = drawing->width;
b2743953 426 guint x;
427 convert_time_to_pixels(
428 time_window,
429 evtime,
430 width,
431 &x);
432
433 /* Draw collision indicator */
434 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 435 gdk_draw_point(hashed_process_data->pixmap,
b2743953 436 drawing->gc,
437 x,
1c736ed5 438 (hashed_process_data->height/2)-3);
b2743953 439 hashed_process_data->x.middle_marked = TRUE;
440 }
441 } else {
ac4e21cf 442 TimeWindow time_window =
443 lttvwindow_get_time_window(control_flow_data->tab);
fd22065b 444#ifdef EXTRA_CHECK
ac4e21cf 445 if(ltt_time_compare(evtime, time_window.start_time) == -1
446 || ltt_time_compare(evtime, time_window.end_time) == 1)
447 return;
fd22065b 448#endif //EXTRA_CHECK
d6fef890 449 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 450 guint width = drawing->width;
10a1069a 451 guint x;
10a1069a 452 convert_time_to_pixels(
a18124ff 453 time_window,
4b7dc462 454 evtime,
455 width,
456 &x);
10a1069a 457
10a1069a 458
4b7dc462 459 /* Jump over draw if we are at the same x position */
e72908ed 460 if(x == hashed_process_data->x.middle &&
461 hashed_process_data->x.middle_used)
e800cf84 462 {
e72908ed 463 if(hashed_process_data->x.middle_marked == FALSE) {
464 /* Draw collision indicator */
465 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 466 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 467 drawing->gc,
468 x,
1c736ed5 469 (hashed_process_data->height/2)-3);
de4ea1ad 470 hashed_process_data->x.middle_marked = TRUE;
e72908ed 471 }
4b7dc462 472 /* jump */
473 } else {
474 DrawContext draw_context;
10a1069a 475
4b7dc462 476 /* Now create the drawing context that will be used to draw
477 * items related to the last state. */
1c736ed5 478 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 479 draw_context.gc = drawing->gc;
480 draw_context.pango_layout = drawing->pango_layout;
481 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
482 draw_context.drawinfo.end.x = x;
483
1c736ed5 484 draw_context.drawinfo.y.over = 1;
485 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
486 draw_context.drawinfo.y.under = hashed_process_data->height;
4b7dc462 487
488 draw_context.drawinfo.start.offset.over = 0;
489 draw_context.drawinfo.start.offset.middle = 0;
490 draw_context.drawinfo.start.offset.under = 0;
491 draw_context.drawinfo.end.offset.over = 0;
492 draw_context.drawinfo.end.offset.middle = 0;
493 draw_context.drawinfo.end.offset.under = 0;
494
495 {
496 /* Draw the line */
9a1ec01b 497 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 498 draw_line((void*)&prop_line, (void*)&draw_context);
499
500 }
501 /* become the last x position */
502 hashed_process_data->x.middle = x;
e72908ed 503 hashed_process_data->x.middle_used = TRUE;
504 hashed_process_data->x.middle_marked = FALSE;
b2743953 505
506 /* Calculate the next good time */
507 convert_pixels_to_time(width, x+1, time_window,
508 &hashed_process_data->next_good_time);
e800cf84 509 }
510 }
511 }
10a1069a 512 }
e800cf84 513
10a1069a 514 {
515 /* For the pid_in */
516 /* First, check if the current process is in the state computation
517 * process list. If it is there, that means we must add it right now and
518 * draw items from the beginning of the read for it. If it is not
519 * present, it's a new process and it was not present : it will
520 * be added after the state update. */
521 LttvProcessState *process;
800aa029 522 process = lttv_state_find_process(ts,
523 ltt_tracefile_num(tfc->tf), pid_in);
10a1069a 524
525 if(process != NULL) {
800aa029 526 /* Well, the process existed : we must get it in the process hash
10a1069a 527 * or add it, and draw its items.
528 */
529 /* Add process to process list (if not present) */
1c736ed5 530 guint pl_height = 0;
10a1069a 531 HashedProcessData *hashed_process_data = NULL;
5c230fc4 532 ProcessList *process_list = control_flow_data->process_list;
10a1069a 533 LttTime birth = process->creation_time;
e800cf84 534
ac4e21cf 535 hashed_process_data = processlist_get_process_data(process_list,
10a1069a 536 pid_in,
348c6ba8 537 process->cpu,
10a1069a 538 &birth,
ac4e21cf 539 tfc->t_context->index);
540 if(hashed_process_data == NULL)
10a1069a 541 {
542 g_assert(pid_in == 0 || pid_in != process->ppid);
543 /* Process not present */
4e86ae2e 544 ProcessInfo *process_info;
1c736ed5 545 Drawing_t *drawing = control_flow_data->drawing;
10a1069a 546 processlist_add(process_list,
1c736ed5 547 drawing,
10a1069a 548 pid_in,
348c6ba8 549 process->cpu,
10a1069a 550 process->ppid,
551 &birth,
552 tfc->t_context->index,
f4b88a7d 553 process->name,
10a1069a 554 &pl_height,
4e86ae2e 555 &process_info,
10a1069a 556 &hashed_process_data);
1c736ed5 557 gtk_widget_set_size_request(drawing->drawing_area,
558 -1,
559 pl_height);
560 gtk_widget_queue_draw(drawing->drawing_area);
561
10a1069a 562 }
40debf7b 563 //We could set the current process and hash here, but will be done
564 //by after schedchange hook
10a1069a 565
566 /* Now, the process is in the state hash and our own process hash.
567 * We definitely can draw the items related to the ending state.
568 */
b9a010a2 569
b2743953 570 if(ltt_time_compare(hashed_process_data->next_good_time,
571 evtime) > 0)
10a1069a 572 {
b2743953 573 if(hashed_process_data->x.middle_marked == FALSE) {
ac4e21cf 574
fd22065b 575 TimeWindow time_window =
576 lttvwindow_get_time_window(control_flow_data->tab);
577#ifdef EXTRA_CHECK
578 if(ltt_time_compare(evtime, time_window.start_time) == -1
579 || ltt_time_compare(evtime, time_window.end_time) == 1)
580 return;
581#endif //EXTRA_CHECK
d6fef890 582 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 583 guint width = drawing->width;
b2743953 584 guint x;
585 convert_time_to_pixels(
586 time_window,
587 evtime,
588 width,
589 &x);
590
591 /* Draw collision indicator */
592 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 593 gdk_draw_point(hashed_process_data->pixmap,
b2743953 594 drawing->gc,
595 x,
1c736ed5 596 (hashed_process_data->height/2)-3);
b2743953 597 hashed_process_data->x.middle_marked = TRUE;
598 }
599 } else {
fd22065b 600 TimeWindow time_window =
601 lttvwindow_get_time_window(control_flow_data->tab);
602#ifdef EXTRA_CHECK
603 if(ltt_time_compare(evtime, time_window.start_time) == -1
604 || ltt_time_compare(evtime, time_window.end_time) == 1)
605 return;
606#endif //EXTRA_CHECK
d6fef890 607 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 608 guint width = drawing->width;
10a1069a 609 guint x;
10a1069a 610
611 convert_time_to_pixels(
a18124ff 612 time_window,
4b7dc462 613 evtime,
614 width,
615 &x);
10a1069a 616
10a1069a 617
4b7dc462 618 /* Jump over draw if we are at the same x position */
e72908ed 619 if(x == hashed_process_data->x.middle &&
620 hashed_process_data->x.middle_used)
4b7dc462 621 {
e72908ed 622 if(hashed_process_data->x.middle_marked == FALSE) {
623 /* Draw collision indicator */
624 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 625 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 626 drawing->gc,
627 x,
1c736ed5 628 (hashed_process_data->height/2)-3);
de4ea1ad 629 hashed_process_data->x.middle_marked = TRUE;
e72908ed 630 }
4b7dc462 631 /* jump */
632 } else {
633 DrawContext draw_context;
10a1069a 634
4b7dc462 635 /* Now create the drawing context that will be used to draw
636 * items related to the last state. */
1c736ed5 637 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 638 draw_context.gc = drawing->gc;
639 draw_context.pango_layout = drawing->pango_layout;
640 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
641 draw_context.drawinfo.end.x = x;
10a1069a 642
1c736ed5 643 draw_context.drawinfo.y.over = 1;
644 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
645 draw_context.drawinfo.y.under = hashed_process_data->height;
10a1069a 646
4b7dc462 647 draw_context.drawinfo.start.offset.over = 0;
648 draw_context.drawinfo.start.offset.middle = 0;
649 draw_context.drawinfo.start.offset.under = 0;
650 draw_context.drawinfo.end.offset.over = 0;
651 draw_context.drawinfo.end.offset.middle = 0;
652 draw_context.drawinfo.end.offset.under = 0;
653
654 {
655 /* Draw the line */
9a1ec01b 656 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 657 draw_line((void*)&prop_line, (void*)&draw_context);
658 }
659
660
661 /* become the last x position */
662 hashed_process_data->x.middle = x;
e72908ed 663 hashed_process_data->x.middle_used = TRUE;
664 hashed_process_data->x.middle_marked = FALSE;
b2743953 665
666 /* Calculate the next good time */
667 convert_pixels_to_time(width, x+1, time_window,
668 &hashed_process_data->next_good_time);
4b7dc462 669 }
c8bba5fa 670 }
b9a010a2 671 }
672 }
b9a010a2 673 return 0;
674
675
b9a010a2 676
a56a1ba4 677
51705146 678 /* Text dump */
80a52ff8 679#ifdef DONTSHOW
a56a1ba4 680 GString *string = g_string_new("");;
681 gboolean field_names = TRUE, state = TRUE;
80a52ff8 682
e9a9c513 683 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
684 g_string_append_printf(string,"\n");
685
686 if(state) {
687 g_string_append_printf(string, " %s",
688 g_quark_to_string(tfs->process->state->s));
689 }
690
691 g_info("%s",string->str);
692
a56a1ba4 693 g_string_free(string, TRUE);
694
695 /* End of text dump */
80a52ff8 696#endif //DONTSHOW
50439712 697
f0d936c0 698}
699
e92eabaf 700/* after_schedchange_hook
b9a010a2 701 *
702 * The draw after hook is called by the reading API to have a
703 * particular event drawn on the screen.
704 * @param hook_data ControlFlowData structure of the viewer.
705 * @param call_data Event context.
706 *
707 * This function adds items to be drawn in a queue for each process.
708 *
709 */
e92eabaf 710int after_schedchange_hook(void *hook_data, void *call_data)
f0d936c0 711{
2c82c4dc 712 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
713 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
ca0f8a8e 714 ControlFlowData *control_flow_data = events_request->viewer_data;
50439712 715
a56a1ba4 716 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
50439712 717
718 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
719
348c6ba8 720 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
721
b9a010a2 722 LttEvent *e;
2c82c4dc 723 e = ltt_tracefile_get_event(tfc->tf);
b9a010a2 724
725 LttTime evtime = ltt_event_time(e);
b9a010a2 726
10a1069a 727 /* Add process to process list (if not present) */
2eef04b5 728 LttvProcessState *process_in;
10a1069a 729 LttTime birth;
1c736ed5 730 guint pl_height = 0;
10a1069a 731 HashedProcessData *hashed_process_data_in = NULL;
b9a010a2 732
5c230fc4 733 ProcessList *process_list = control_flow_data->process_list;
10a1069a 734
735 guint pid_in;
736 {
737 guint pid_out;
2c82c4dc 738 pid_out = ltt_event_get_long_unsigned(e, thf->f1);
739 pid_in = ltt_event_get_long_unsigned(e, thf->f2);
10a1069a 740 }
b9a010a2 741
742
10a1069a 743 /* Find process pid_in in the list... */
348c6ba8 744 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
745 //process_in = tfs->process;
746 guint cpu = ltt_tracefile_num(tfc->tf);
747 process_in = ts->running_process[cpu];
10a1069a 748 /* It should exist, because we are after the state update. */
96947fcf 749#ifdef EXTRA_CHECK
10a1069a 750 g_assert(process_in != NULL);
96947fcf 751#endif //EXTRA_CHECK
10a1069a 752 birth = process_in->creation_time;
b9a010a2 753
ac4e21cf 754 hashed_process_data_in = processlist_get_process_data(process_list,
10a1069a 755 pid_in,
348c6ba8 756 process_in->cpu,
10a1069a 757 &birth,
ac4e21cf 758 tfc->t_context->index);
759 if(hashed_process_data_in == NULL)
10a1069a 760 {
761 g_assert(pid_in == 0 || pid_in != process_in->ppid);
4e86ae2e 762 ProcessInfo *process_info;
1c736ed5 763 Drawing_t *drawing = control_flow_data->drawing;
10a1069a 764 /* Process not present */
765 processlist_add(process_list,
1c736ed5 766 drawing,
10a1069a 767 pid_in,
348c6ba8 768 process_in->cpu,
10a1069a 769 process_in->ppid,
770 &birth,
771 tfc->t_context->index,
f4b88a7d 772 process_in->name,
10a1069a 773 &pl_height,
4e86ae2e 774 &process_info,
10a1069a 775 &hashed_process_data_in);
1c736ed5 776 gtk_widget_set_size_request(drawing->drawing_area,
777 -1,
778 pl_height);
779 gtk_widget_queue_draw(drawing->drawing_area);
b9a010a2 780 }
40debf7b 781 /* Set the current process */
348c6ba8 782 process_list->current_hash_data[process_in->cpu] =
40debf7b 783 hashed_process_data_in;
10a1069a 784
b2743953 785 if(ltt_time_compare(hashed_process_data_in->next_good_time,
786 evtime) <= 0)
787 {
fd22065b 788 TimeWindow time_window =
789 lttvwindow_get_time_window(control_flow_data->tab);
790
791#ifdef EXTRA_CHECK
792 if(ltt_time_compare(evtime, time_window.start_time) == -1
793 || ltt_time_compare(evtime, time_window.end_time) == 1)
794 return;
795#endif //EXTRA_CHECK
d6fef890 796 Drawing_t *drawing = control_flow_data->drawing;
797 guint width = drawing->width;
b2743953 798 guint new_x;
799
800 convert_time_to_pixels(
801 time_window,
802 evtime,
803 width,
804 &new_x);
e72908ed 805
b2743953 806 if(hashed_process_data_in->x.middle != new_x) {
807 hashed_process_data_in->x.middle = new_x;
808 hashed_process_data_in->x.middle_used = FALSE;
809 hashed_process_data_in->x.middle_marked = FALSE;
810 }
811 }
b9a010a2 812 return 0;
4a24fa1f 813}
b9a010a2 814
815
816
e72908ed 817
4a24fa1f 818/* before_execmode_hook
819 *
820 * This function basically draw lines and icons. Two types of lines are drawn :
821 * one small (3 pixels?) representing the state of the process and the second
822 * type is thicker (10 pixels?) representing on which CPU a process is running
823 * (and this only in running state).
824 *
825 * Extremums of the lines :
826 * x_min : time of the last event context for this process kept in memory.
827 * x_max : time of the current event.
828 * y : middle of the process in the process list. The process is found in the
829 * list, therefore is it's position in pixels.
830 *
831 * The choice of lines'color is defined by the context of the last event for this
832 * process.
833 */
834
e72908ed 835
4a24fa1f 836int before_execmode_hook(void *hook_data, void *call_data)
837{
838 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
839 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
b9a010a2 840 ControlFlowData *control_flow_data = events_request->viewer_data;
841
842 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
843
844 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
b9a010a2 845
4a24fa1f 846 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
847
50439712 848 LttEvent *e;
4a24fa1f 849 e = ltt_tracefile_get_event(tfc->tf);
50439712 850
9444deae 851 LttTime evtime = ltt_event_time(e);
9444deae 852
4a24fa1f 853 /* we are in a execmode, before the state update. We must draw the
854 * items corresponding to the state before it changes : now is the right
855 * time to do it.
856 */
857 /* For the pid */
858 //LttvProcessState *process = tfs->process;
859 guint cpu = ltt_tracefile_num(tfc->tf);
860 LttvProcessState *process = ts->running_process[cpu];
861 g_assert(process != NULL);
23093869 862
10a1069a 863 guint pid = process->pid;
23093869 864
10a1069a 865 /* Well, the process_out existed : we must get it in the process hash
866 * or add it, and draw its items.
867 */
868 /* Add process to process list (if not present) */
1c736ed5 869 guint pl_height = 0;
10a1069a 870 HashedProcessData *hashed_process_data = NULL;
5c230fc4 871 ProcessList *process_list = control_flow_data->process_list;
10a1069a 872 LttTime birth = process->creation_time;
40debf7b 873
348c6ba8 874 if(likely(process_list->current_hash_data[cpu] != NULL)) {
875 hashed_process_data = process_list->current_hash_data[cpu];
40debf7b 876 } else {
ac4e21cf 877 hashed_process_data = processlist_get_process_data(process_list,
40debf7b 878 pid,
348c6ba8 879 process->cpu,
40debf7b 880 &birth,
ac4e21cf 881 tfc->t_context->index);
1d1df11d 882 if(unlikely(hashed_process_data == NULL))
40debf7b 883 {
884 g_assert(pid == 0 || pid != process->ppid);
885 ProcessInfo *process_info;
886 /* Process not present */
1c736ed5 887 Drawing_t *drawing = control_flow_data->drawing;
40debf7b 888 processlist_add(process_list,
1c736ed5 889 drawing,
40debf7b 890 pid,
348c6ba8 891 process->cpu,
40debf7b 892 process->ppid,
893 &birth,
894 tfc->t_context->index,
f4b88a7d 895 process->name,
40debf7b 896 &pl_height,
897 &process_info,
898 &hashed_process_data);
1c736ed5 899 gtk_widget_set_size_request(drawing->drawing_area,
900 -1,
901 pl_height);
902 gtk_widget_queue_draw(drawing->drawing_area);
40debf7b 903 }
904 /* Set the current process */
348c6ba8 905 process_list->current_hash_data[process->cpu] =
40debf7b 906 hashed_process_data;
10a1069a 907 }
23093869 908
10a1069a 909 /* Now, the process is in the state hash and our own process hash.
910 * We definitely can draw the items related to the ending state.
911 */
b2743953 912
1d1df11d 913 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
914 evtime) > 0))
10a1069a 915 {
1d1df11d 916 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
fd22065b 917 TimeWindow time_window =
918 lttvwindow_get_time_window(control_flow_data->tab);
919
920#ifdef EXTRA_CHECK
921 if(ltt_time_compare(evtime, time_window.start_time) == -1
922 || ltt_time_compare(evtime, time_window.end_time) == 1)
923 return;
924#endif //EXTRA_CHECK
d6fef890 925 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 926 guint width = drawing->width;
b2743953 927 guint x;
928 convert_time_to_pixels(
929 time_window,
930 evtime,
931 width,
932 &x);
933
934 /* Draw collision indicator */
935 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 936 gdk_draw_point(hashed_process_data->pixmap,
b2743953 937 drawing->gc,
938 x,
1c736ed5 939 (hashed_process_data->height/2)-3);
b2743953 940 hashed_process_data->x.middle_marked = TRUE;
941 }
942 } else {
fd22065b 943 TimeWindow time_window =
944 lttvwindow_get_time_window(control_flow_data->tab);
945
946#ifdef EXTRA_CHECK
947 if(ltt_time_compare(evtime, time_window.start_time) == -1
948 || ltt_time_compare(evtime, time_window.end_time) == 1)
949 return;
950#endif //EXTRA_CHECK
d6fef890 951 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 952 guint width = drawing->width;
10a1069a 953 guint x;
dbd243b1 954
10a1069a 955 convert_time_to_pixels(
a18124ff 956 time_window,
10a1069a 957 evtime,
958 width,
959 &x);
dbd243b1 960
23093869 961
4b7dc462 962 /* Jump over draw if we are at the same x position */
1d1df11d 963 if(unlikely(x == hashed_process_data->x.middle &&
964 hashed_process_data->x.middle_used))
10a1069a 965 {
1d1df11d 966 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
e72908ed 967 /* Draw collision indicator */
968 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 969 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 970 drawing->gc,
971 x,
1c736ed5 972 (hashed_process_data->height/2)-3);
de4ea1ad 973 hashed_process_data->x.middle_marked = TRUE;
e72908ed 974 }
4b7dc462 975 /* jump */
976 } else {
977
978 DrawContext draw_context;
979 /* Now create the drawing context that will be used to draw
980 * items related to the last state. */
1c736ed5 981 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 982 draw_context.gc = drawing->gc;
983 draw_context.pango_layout = drawing->pango_layout;
9a1ec01b 984 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
4b7dc462 985 draw_context.drawinfo.end.x = x;
986
1c736ed5 987 draw_context.drawinfo.y.over = 1;
988 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
989 draw_context.drawinfo.y.under = hashed_process_data->height;
4b7dc462 990
991 draw_context.drawinfo.start.offset.over = 0;
992 draw_context.drawinfo.start.offset.middle = 0;
993 draw_context.drawinfo.start.offset.under = 0;
994 draw_context.drawinfo.end.offset.over = 0;
995 draw_context.drawinfo.end.offset.middle = 0;
996 draw_context.drawinfo.end.offset.under = 0;
997
998 {
999 /* Draw the line */
9a1ec01b 1000 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 1001 draw_line((void*)&prop_line, (void*)&draw_context);
23093869 1002
4b7dc462 1003 }
1004 /* become the last x position */
9a1ec01b 1005 hashed_process_data->x.middle = x;
e72908ed 1006 hashed_process_data->x.middle_used = TRUE;
1007 hashed_process_data->x.middle_marked = FALSE;
b2743953 1008
1009 /* Calculate the next good time */
1010 convert_pixels_to_time(width, x+1, time_window,
1011 &hashed_process_data->next_good_time);
23093869 1012 }
1013 }
1014
1015 return 0;
1016}
1017
4a24fa1f 1018/* before_process_exit_hook
23093869 1019 *
4a24fa1f 1020 * Draw lines for process event.
1021 *
23093869 1022 * @param hook_data ControlFlowData structure of the viewer.
1023 * @param call_data Event context.
1024 *
1025 * This function adds items to be drawn in a queue for each process.
1026 *
1027 */
8869ac08 1028
1029
4a24fa1f 1030int before_process_exit_hook(void *hook_data, void *call_data)
1031{
2c82c4dc 1032 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1033 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
4a24fa1f 1034
23093869 1035 ControlFlowData *control_flow_data = events_request->viewer_data;
1036
1037 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1038
1039 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
23093869 1040
4a24fa1f 1041 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1042
23093869 1043 LttEvent *e;
2c82c4dc 1044 e = ltt_tracefile_get_event(tfc->tf);
23093869 1045
1046 LttTime evtime = ltt_event_time(e);
23093869 1047
10a1069a 1048 /* Add process to process list (if not present) */
4a24fa1f 1049 //LttvProcessState *process = tfs->process;
1050 guint cpu = ltt_tracefile_num(tfc->tf);
1051 LttvProcessState *process = ts->running_process[cpu];
1052 guint pid = process->pid;
10a1069a 1053 LttTime birth;
1c736ed5 1054 guint pl_height = 0;
10a1069a 1055 HashedProcessData *hashed_process_data = NULL;
23093869 1056
5c230fc4 1057 ProcessList *process_list = control_flow_data->process_list;
4a24fa1f 1058
10a1069a 1059 g_assert(process != NULL);
23093869 1060
10a1069a 1061 birth = process->creation_time;
23093869 1062
4a24fa1f 1063 if(likely(process_list->current_hash_data[cpu] != NULL)) {
1064 hashed_process_data = process_list->current_hash_data[cpu];
40debf7b 1065 } else {
ac4e21cf 1066 hashed_process_data = processlist_get_process_data(process_list,
4a24fa1f 1067 pid,
1068 process->cpu,
1069 &birth,
1070 tfc->t_context->index);
1d1df11d 1071 if(unlikely(hashed_process_data == NULL))
40debf7b 1072 {
1073 g_assert(pid == 0 || pid != process->ppid);
1074 /* Process not present */
1c736ed5 1075 Drawing_t *drawing = control_flow_data->drawing;
40debf7b 1076 ProcessInfo *process_info;
1077 processlist_add(process_list,
1c736ed5 1078 drawing,
40debf7b 1079 pid,
4a24fa1f 1080 process->cpu,
40debf7b 1081 process->ppid,
1082 &birth,
1083 tfc->t_context->index,
4a24fa1f 1084 process->name,
40debf7b 1085 &pl_height,
1086 &process_info,
1087 &hashed_process_data);
4a24fa1f 1088 gtk_widget_set_size_request(drawing->drawing_area,
1089 -1,
1090 pl_height);
1091 gtk_widget_queue_draw(drawing->drawing_area);
40debf7b 1092 }
23093869 1093 }
40debf7b 1094
4a24fa1f 1095 /* Now, the process is in the state hash and our own process hash.
1096 * We definitely can draw the items related to the ending state.
1097 */
1098
1099 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1100 evtime) > 0))
b2743953 1101 {
4a24fa1f 1102 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1103 TimeWindow time_window =
1104 lttvwindow_get_time_window(control_flow_data->tab);
1105
1106#ifdef EXTRA_CHECK
1107 if(ltt_time_compare(evtime, time_window.start_time) == -1
1108 || ltt_time_compare(evtime, time_window.end_time) == 1)
1109 return;
1110#endif //EXTRA_CHECK
1111 Drawing_t *drawing = control_flow_data->drawing;
1112 guint width = drawing->width;
1113 guint x;
1114 convert_time_to_pixels(
1115 time_window,
1116 evtime,
1117 width,
1118 &x);
1119
1120 /* Draw collision indicator */
1121 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1122 gdk_draw_point(hashed_process_data->pixmap,
1123 drawing->gc,
1124 x,
1125 (hashed_process_data->height/2)-3);
1126 hashed_process_data->x.middle_marked = TRUE;
1127 }
1128 } else {
fd22065b 1129 TimeWindow time_window =
1130 lttvwindow_get_time_window(control_flow_data->tab);
1131
1132#ifdef EXTRA_CHECK
1133 if(ltt_time_compare(evtime, time_window.start_time) == -1
1134 || ltt_time_compare(evtime, time_window.end_time) == 1)
1135 return;
1136#endif //EXTRA_CHECK
d6fef890 1137 Drawing_t *drawing = control_flow_data->drawing;
1138 guint width = drawing->width;
4a24fa1f 1139 guint x;
1140
2c82c4dc 1141 convert_time_to_pixels(
1142 time_window,
1143 evtime,
1144 width,
1145 &x);
1146
b2743953 1147
2c82c4dc 1148 /* Jump over draw if we are at the same x position */
1149 if(unlikely(x == hashed_process_data->x.middle &&
1150 hashed_process_data->x.middle_used))
1151 {
1152 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
b2743953 1153 /* Draw collision indicator */
1154 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 1155 gdk_draw_point(hashed_process_data->pixmap,
b2743953 1156 drawing->gc,
1157 x,
1c736ed5 1158 (hashed_process_data->height/2)-3);
b2743953 1159 hashed_process_data->x.middle_marked = TRUE;
1160 }
2c82c4dc 1161 /* jump */
b2743953 1162 } else {
2c82c4dc 1163 DrawContext draw_context;
fd22065b 1164
2c82c4dc 1165 /* Now create the drawing context that will be used to draw
1166 * items related to the last state. */
1167 draw_context.drawable = hashed_process_data->pixmap;
1168 draw_context.gc = drawing->gc;
1169 draw_context.pango_layout = drawing->pango_layout;
1170 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1171 draw_context.drawinfo.end.x = x;
dbd243b1 1172
2c82c4dc 1173 draw_context.drawinfo.y.over = 1;
1174 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1175 draw_context.drawinfo.y.under = hashed_process_data->height;
dbd243b1 1176
2c82c4dc 1177 draw_context.drawinfo.start.offset.over = 0;
1178 draw_context.drawinfo.start.offset.middle = 0;
1179 draw_context.drawinfo.start.offset.under = 0;
1180 draw_context.drawinfo.end.offset.over = 0;
1181 draw_context.drawinfo.end.offset.middle = 0;
1182 draw_context.drawinfo.end.offset.under = 0;
dbd243b1 1183
2c82c4dc 1184 {
1185 /* Draw the line */
1186 PropertiesLine prop_line = prepare_s_e_line(process);
1187 draw_line((void*)&prop_line, (void*)&draw_context);
dbd243b1 1188
2c82c4dc 1189 }
1190 /* become the last x position */
1191 hashed_process_data->x.middle = x;
1192 hashed_process_data->x.middle_used = TRUE;
1193 hashed_process_data->x.middle_marked = FALSE;
dbd243b1 1194
2c82c4dc 1195 /* Calculate the next good time */
1196 convert_pixels_to_time(width, x+1, time_window,
1197 &hashed_process_data->next_good_time);
1198 }
1199 }
1200
1201 return 0;
1202
1203}
1204
1205
1206
1207/* before_process_release_hook
1208 *
1209 * Draw lines for process event.
1210 *
1211 * @param hook_data ControlFlowData structure of the viewer.
1212 * @param call_data Event context.
1213 *
1214 * This function adds items to be drawn in a queue for each process.
1215 *
1216 */
1217
1218
1219int before_process_release_hook(void *hook_data, void *call_data)
1220{
1221 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1222 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1223
1224 ControlFlowData *control_flow_data = events_request->viewer_data;
1225
1226 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1227
1228 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1229
348c6ba8 1230 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1231
2c82c4dc 1232 LttEvent *e;
1233 e = ltt_tracefile_get_event(tfc->tf);
1234
1235 LttTime evtime = ltt_event_time(e);
1236
1237
1238 guint pid;
1239 {
1240 pid = ltt_event_get_long_unsigned(e, thf->f1);
1241 }
1242
1243 /* Add process to process list (if not present) */
1244 /* Don't care about the process if it's not in the state hash already :
1245 * that means a process that has never done anything in the trace and
1246 * unknown suddently gets destroyed : no state meaningful to show. */
348c6ba8 1247 LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
2c82c4dc 1248
1249 if(process != NULL) {
1250 LttTime birth;
1251 guint pl_height = 0;
1252 HashedProcessData *hashed_process_data = NULL;
1253
1254 ProcessList *process_list = control_flow_data->process_list;
1255
1256 birth = process->creation_time;
1257
1258 /* Cannot use current process : this event happens on another process,
1259 * action done by the parent. */
1260 hashed_process_data = processlist_get_process_data(process_list,
1261 pid,
348c6ba8 1262 process->cpu,
2c82c4dc 1263 &birth,
1264 tfc->t_context->index);
1265 if(unlikely(hashed_process_data == NULL))
1266 {
1267 g_assert(pid == 0 || pid != process->ppid);
1268 /* Process not present */
1269 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1270 ProcessInfo *process_info;
1271 processlist_add(process_list,
1272 drawing,
1273 pid,
348c6ba8 1274 process->cpu,
2c82c4dc 1275 process->ppid,
1276 &birth,
1277 tfc->t_context->index,
f4b88a7d 1278 process->name,
2c82c4dc 1279 &pl_height,
1280 &process_info,
1281 &hashed_process_data);
1282 gtk_widget_set_size_request(drawing->drawing_area,
1283 -1,
1284 pl_height);
1285 gtk_widget_queue_draw(drawing->drawing_area);
1286 }
1287
1288 /* Now, the process is in the state hash and our own process hash.
1289 * We definitely can draw the items related to the ending state.
1290 */
1291
1292 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1293 evtime) > 0))
1294 {
1295 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1296 TimeWindow time_window =
1297 lttvwindow_get_time_window(control_flow_data->tab);
1298
1299#ifdef EXTRA_CHECK
1300 if(ltt_time_compare(evtime, time_window.start_time) == -1
1301 || ltt_time_compare(evtime, time_window.end_time) == 1)
1302 return;
1303#endif //EXTRA_CHECK
1304 Drawing_t *drawing = control_flow_data->drawing;
1305 guint width = drawing->width;
1306 guint x;
1307 convert_time_to_pixels(
1308 time_window,
1309 evtime,
1310 width,
1311 &x);
1312
1313 /* Draw collision indicator */
1314 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1315 gdk_draw_point(hashed_process_data->pixmap,
1316 drawing->gc,
1317 x,
1318 (hashed_process_data->height/2)-3);
1319 hashed_process_data->x.middle_marked = TRUE;
1320 }
1321 } else {
1322 TimeWindow time_window =
1323 lttvwindow_get_time_window(control_flow_data->tab);
1324
1325#ifdef EXTRA_CHECK
1326 if(ltt_time_compare(evtime, time_window.start_time) == -1
4a24fa1f 1327 || ltt_time_compare(evtime, time_window.end_time) == 1)
1328 return;
2da61677 1329#endif //EXTRA_CHECK
4a24fa1f 1330 Drawing_t *drawing = control_flow_data->drawing;
1331 guint width = drawing->width;
1332 guint x;
1333
1334 convert_time_to_pixels(
1335 time_window,
1336 evtime,
1337 width,
1338 &x);
1339
2da61677 1340
4a24fa1f 1341 /* Jump over draw if we are at the same x position */
1342 if(unlikely(x == hashed_process_data->x.middle &&
1343 hashed_process_data->x.middle_used))
1344 {
1345 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
2da61677 1346 /* Draw collision indicator */
1347 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1348 gdk_draw_point(hashed_process_data->pixmap,
1349 drawing->gc,
1350 x,
1351 (hashed_process_data->height/2)-3);
1352 hashed_process_data->x.middle_marked = TRUE;
1353 }
4a24fa1f 1354 /* jump */
2da61677 1355 } else {
4a24fa1f 1356 DrawContext draw_context;
2da61677 1357
4a24fa1f 1358 /* Now create the drawing context that will be used to draw
1359 * items related to the last state. */
1360 draw_context.drawable = hashed_process_data->pixmap;
1361 draw_context.gc = drawing->gc;
1362 draw_context.pango_layout = drawing->pango_layout;
1363 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1364 draw_context.drawinfo.end.x = x;
2da61677 1365
4a24fa1f 1366 draw_context.drawinfo.y.over = 1;
1367 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1368 draw_context.drawinfo.y.under = hashed_process_data->height;
2da61677 1369
4a24fa1f 1370 draw_context.drawinfo.start.offset.over = 0;
1371 draw_context.drawinfo.start.offset.middle = 0;
1372 draw_context.drawinfo.start.offset.under = 0;
1373 draw_context.drawinfo.end.offset.over = 0;
1374 draw_context.drawinfo.end.offset.middle = 0;
1375 draw_context.drawinfo.end.offset.under = 0;
2da61677 1376
4a24fa1f 1377 {
1378 /* Draw the line */
1379 PropertiesLine prop_line = prepare_s_e_line(process);
1380 draw_line((void*)&prop_line, (void*)&draw_context);
2da61677 1381
2da61677 1382 }
4a24fa1f 1383 /* become the last x position */
1384 hashed_process_data->x.middle = x;
1385 hashed_process_data->x.middle_used = TRUE;
1386 hashed_process_data->x.middle_marked = FALSE;
1387
1388 /* Calculate the next good time */
1389 convert_pixels_to_time(width, x+1, time_window,
1390 &hashed_process_data->next_good_time);
2da61677 1391 }
1392 }
dbd243b1 1393 }
dbd243b1 1394
4a24fa1f 1395 return 0;
dbd243b1 1396}
1397
4a24fa1f 1398
2c82c4dc 1399
1400
1401
1402/* after_process_fork_hook
1403 *
1404 * Create the processlist entry for the child process. Put the last
1405 * position in x at the current time value.
1406 *
1407 * @param hook_data ControlFlowData structure of the viewer.
1408 * @param call_data Event context.
1409 *
1410 * This function adds items to be drawn in a queue for each process.
1411 *
1412 */
1413int after_process_fork_hook(void *hook_data, void *call_data)
1414{
1415 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1416 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1417 ControlFlowData *control_flow_data = events_request->viewer_data;
1418
1419 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1420
1421 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1422
348c6ba8 1423 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1424
2c82c4dc 1425 LttEvent *e;
1426 e = ltt_tracefile_get_event(tfc->tf);
1427
1428 LttTime evtime = ltt_event_time(e);
1429
1430 guint child_pid;
1431 {
1432 child_pid = ltt_event_get_long_unsigned(e, thf->f2);
1433 }
1434
1435 /* Add process to process list (if not present) */
1436 LttvProcessState *process_child;
1437 LttTime birth;
1438 guint pl_height = 0;
1439 HashedProcessData *hashed_process_data_child = NULL;
1440
1441 ProcessList *process_list = control_flow_data->process_list;
1442
1443 /* Find child in the list... */
348c6ba8 1444 process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
2c82c4dc 1445 /* It should exist, because we are after the state update. */
1446 g_assert(process_child != NULL);
1447
1448 birth = process_child->creation_time;
1449
1450 /* Cannot use current process, because this action is done by the parent
1451 * on its child. */
1452 hashed_process_data_child = processlist_get_process_data(process_list,
1453 child_pid,
348c6ba8 1454 process_child->cpu,
2c82c4dc 1455 &birth,
1456 tfc->t_context->index);
1457 if(likely(hashed_process_data_child == NULL))
1458 {
1459 g_assert(child_pid == 0 || child_pid != process_child->ppid);
1460 /* Process not present */
1461 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1462 ProcessInfo *process_info;
1463 processlist_add(process_list,
1464 drawing,
1465 child_pid,
348c6ba8 1466 process_child->cpu,
2c82c4dc 1467 process_child->ppid,
1468 &birth,
1469 tfc->t_context->index,
f4b88a7d 1470 process_child->name,
2c82c4dc 1471 &pl_height,
1472 &process_info,
1473 &hashed_process_data_child);
1474 gtk_widget_set_size_request(drawing->drawing_area,
1475 -1,
1476 pl_height);
1477 gtk_widget_queue_draw(drawing->drawing_area);
1478 }
1479
1480
1481 if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1482 evtime) <= 0))
1483 {
1484 TimeWindow time_window =
1485 lttvwindow_get_time_window(control_flow_data->tab);
1486
1487#ifdef EXTRA_CHECK
1488 if(ltt_time_compare(evtime, time_window.start_time) == -1
1489 || ltt_time_compare(evtime, time_window.end_time) == 1)
1490 return;
1491#endif //EXTRA_CHECK
1492 Drawing_t *drawing = control_flow_data->drawing;
1493 guint width = drawing->width;
1494 guint new_x;
1495 convert_time_to_pixels(
1496 time_window,
1497 evtime,
1498 width,
1499 &new_x);
1500
1501 if(likely(hashed_process_data_child->x.over != new_x)) {
1502 hashed_process_data_child->x.over = new_x;
1503 hashed_process_data_child->x.over_used = FALSE;
1504 hashed_process_data_child->x.over_marked = FALSE;
1505 }
1506 if(likely(hashed_process_data_child->x.middle != new_x)) {
1507 hashed_process_data_child->x.middle = new_x;
1508 hashed_process_data_child->x.middle_used = FALSE;
1509 hashed_process_data_child->x.middle_marked = FALSE;
1510 }
1511 if(likely(hashed_process_data_child->x.under != new_x)) {
1512 hashed_process_data_child->x.under = new_x;
1513 hashed_process_data_child->x.under_used = FALSE;
1514 hashed_process_data_child->x.under_marked = FALSE;
1515 }
1516 }
1517 return 0;
1518}
1519
1520
1521
1522/* after_process_exit_hook
1523 *
1524 * Create the processlist entry for the child process. Put the last
1525 * position in x at the current time value.
1526 *
1527 * @param hook_data ControlFlowData structure of the viewer.
1528 * @param call_data Event context.
1529 *
1530 * This function adds items to be drawn in a queue for each process.
1531 *
1532 */
1533int after_process_exit_hook(void *hook_data, void *call_data)
1534{
1535 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1536 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1537 ControlFlowData *control_flow_data = events_request->viewer_data;
1538
1539 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1540
1541 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1542
348c6ba8 1543 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1544
2c82c4dc 1545 LttEvent *e;
1546 e = ltt_tracefile_get_event(tfc->tf);
1547
1548 LttTime evtime = ltt_event_time(e);
1549
1550 /* Add process to process list (if not present) */
348c6ba8 1551 //LttvProcessState *process = tfs->process;
1552 guint cpu = ltt_tracefile_num(tfc->tf);
1553 LttvProcessState *process = ts->running_process[cpu];
1554
1555 /* It should exist, because we are after the state update. */
1556 g_assert(process != NULL);
1557
2c82c4dc 1558 guint pid = process->pid;
1559 LttTime birth;
1560 guint pl_height = 0;
1561 HashedProcessData *hashed_process_data = NULL;
1562
1563 ProcessList *process_list = control_flow_data->process_list;
1564
2c82c4dc 1565 birth = process->creation_time;
1566
348c6ba8 1567 if(likely(process_list->current_hash_data[cpu] != NULL) ){
1568 hashed_process_data = process_list->current_hash_data[cpu];
2c82c4dc 1569 } else {
1570 hashed_process_data = processlist_get_process_data(process_list,
1571 pid,
348c6ba8 1572 process->cpu,
2c82c4dc 1573 &birth,
1574 tfc->t_context->index);
1575 if(unlikely(hashed_process_data == NULL))
1576 {
1577 g_assert(pid == 0 || pid != process->ppid);
1578 /* Process not present */
1579 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1580 ProcessInfo *process_info;
1581 processlist_add(process_list,
1582 drawing,
1583 pid,
348c6ba8 1584 process->cpu,
2c82c4dc 1585 process->ppid,
1586 &birth,
1587 tfc->t_context->index,
f4b88a7d 1588 process->name,
2c82c4dc 1589 &pl_height,
1590 &process_info,
1591 &hashed_process_data);
1592 gtk_widget_set_size_request(drawing->drawing_area,
1593 -1,
1594 pl_height);
1595 gtk_widget_queue_draw(drawing->drawing_area);
1596 }
1597
1598 /* Set the current process */
348c6ba8 1599 process_list->current_hash_data[process->cpu] =
2c82c4dc 1600 hashed_process_data;
1601 }
1602
1603 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1604 evtime) <= 0))
1605 {
1606 TimeWindow time_window =
1607 lttvwindow_get_time_window(control_flow_data->tab);
dbd243b1 1608
2c82c4dc 1609#ifdef EXTRA_CHECK
1610 if(ltt_time_compare(evtime, time_window.start_time) == -1
1611 || ltt_time_compare(evtime, time_window.end_time) == 1)
1612 return;
1613#endif //EXTRA_CHECK
1614 Drawing_t *drawing = control_flow_data->drawing;
1615 guint width = drawing->width;
1616 guint new_x;
1617 convert_time_to_pixels(
1618 time_window,
1619 evtime,
1620 width,
1621 &new_x);
1622 if(unlikely(hashed_process_data->x.middle != new_x)) {
1623 hashed_process_data->x.middle = new_x;
1624 hashed_process_data->x.middle_used = FALSE;
1625 hashed_process_data->x.middle_marked = FALSE;
1626 }
1627 }
dbd243b1 1628
2c82c4dc 1629 return 0;
1630}
dbd243b1 1631
1632
f4b88a7d 1633/* Get the filename of the process to print */
1634int after_fs_exec_hook(void *hook_data, void *call_data)
1635{
1636 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1637 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1638 ControlFlowData *control_flow_data = events_request->viewer_data;
1639
1640 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1641
1642 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1643
1644 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1645
1646 guint cpu = ltt_tracefile_num(tfc->tf);
1647 LttvProcessState *process = ts->running_process[cpu];
1648 g_assert(process != NULL);
1649
1650 guint pid = process->pid;
1651
1652 /* Well, the process_out existed : we must get it in the process hash
1653 * or add it, and draw its items.
1654 */
1655 /* Add process to process list (if not present) */
1656 guint pl_height = 0;
1657 HashedProcessData *hashed_process_data = NULL;
1658 ProcessList *process_list = control_flow_data->process_list;
1659 LttTime birth = process->creation_time;
1660
1661 if(likely(process_list->current_hash_data[cpu] != NULL)) {
1662 hashed_process_data = process_list->current_hash_data[cpu];
1663 } else {
1664 hashed_process_data = processlist_get_process_data(process_list,
1665 pid,
1666 process->cpu,
1667 &birth,
1668 tfc->t_context->index);
1669 if(unlikely(hashed_process_data == NULL))
1670 {
1671 g_assert(pid == 0 || pid != process->ppid);
1672 ProcessInfo *process_info;
1673 /* Process not present */
1674 Drawing_t *drawing = control_flow_data->drawing;
1675 processlist_add(process_list,
1676 drawing,
1677 pid,
1678 process->cpu,
1679 process->ppid,
1680 &birth,
1681 tfc->t_context->index,
1682 process->name,
1683 &pl_height,
1684 &process_info,
1685 &hashed_process_data);
1686 gtk_widget_set_size_request(drawing->drawing_area,
1687 -1,
1688 pl_height);
1689 gtk_widget_queue_draw(drawing->drawing_area);
1690 }
1691 /* Set the current process */
1692 process_list->current_hash_data[process->cpu] =
1693 hashed_process_data;
1694 }
1695
1696 processlist_set_name(process_list, process->name, hashed_process_data);
1697
1698 return 0;
1699
1700}
1701
1702
1703
1704
1b238973 1705gint update_time_window_hook(void *hook_data, void *call_data)
f7afe191 1706{
a56a1ba4 1707 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
a43d67ba 1708 Drawing_t *drawing = control_flow_data->drawing;
1c736ed5 1709 ProcessList *process_list = control_flow_data->process_list;
a43d67ba 1710
224446ce 1711 const TimeWindowNotifyData *time_window_nofify_data =
1712 ((const TimeWindowNotifyData *)call_data);
1713
14963be0 1714 TimeWindow *old_time_window =
224446ce 1715 time_window_nofify_data->old_time_window;
1716 TimeWindow *new_time_window =
1717 time_window_nofify_data->new_time_window;
a56a1ba4 1718
3cb8b205 1719 /* Update the ruler */
1720 drawing_update_ruler(control_flow_data->drawing,
1721 new_time_window);
1722
1723
a56a1ba4 1724 /* Two cases : zoom in/out or scrolling */
1725
1726 /* In order to make sure we can reuse the old drawing, the scale must
1727 * be the same and the new time interval being partly located in the
1728 * currently shown time interval. (reuse is only for scrolling)
1729 */
1730
2eef04b5 1731 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
14963be0 1732 old_time_window->start_time.tv_sec,
1733 old_time_window->start_time.tv_nsec,
1734 old_time_window->time_width.tv_sec,
1735 old_time_window->time_width.tv_nsec);
a56a1ba4 1736
2eef04b5 1737 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
14963be0 1738 new_time_window->start_time.tv_sec,
1739 new_time_window->start_time.tv_nsec,
1740 new_time_window->time_width.tv_sec,
1741 new_time_window->time_width.tv_nsec);
a56a1ba4 1742
14963be0 1743 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
1744 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
a56a1ba4 1745 {
1746 /* Same scale (scrolling) */
1747 g_info("scrolling");
14963be0 1748 LttTime *ns = &new_time_window->start_time;
20640e70 1749 LttTime *nw = &new_time_window->time_width;
14963be0 1750 LttTime *os = &old_time_window->start_time;
20640e70 1751 LttTime *ow = &old_time_window->time_width;
6f26fc38 1752 LttTime old_end = old_time_window->end_time;
1753 LttTime new_end = new_time_window->end_time;
a56a1ba4 1754 //if(ns<os+w<ns+w)
1755 //if(ns<os+w && os+w<ns+w)
1756 //if(ns<old_end && os<ns)
1757 if(ltt_time_compare(*ns, old_end) == -1
1758 && ltt_time_compare(*os, *ns) == -1)
1759 {
1760 g_info("scrolling near right");
1761 /* Scroll right, keep right part of the screen */
1762 guint x = 0;
51705146 1763 guint width = control_flow_data->drawing->width;
a56a1ba4 1764 convert_time_to_pixels(
a18124ff 1765 *old_time_window,
a56a1ba4 1766 *ns,
1767 width,
1768 &x);
1769
1770 /* Copy old data to new location */
1c736ed5 1771 copy_pixmap_region(process_list,
1772 NULL,
1773 control_flow_data->drawing->drawing_area->style->black_gc,
1774 NULL,
1775 x, 0,
1776 0, 0,
1777 control_flow_data->drawing->width-x+SAFETY, -1);
1778
6395d57c 1779 if(drawing->damage_begin == drawing->damage_end)
1780 drawing->damage_begin = control_flow_data->drawing->width-x;
1781 else
1782 drawing->damage_begin = 0;
1783
1784 drawing->damage_end = control_flow_data->drawing->width;
1785
a56a1ba4 1786 /* Clear the data request background, but not SAFETY */
1c736ed5 1787 rectangle_pixmap(process_list,
cfe526b1 1788 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 1789 TRUE,
6395d57c 1790 drawing->damage_begin+SAFETY, 0,
1791 drawing->damage_end - drawing->damage_begin, // do not overlap
1c736ed5 1792 -1);
7abb23ad 1793 gtk_widget_queue_draw(drawing->drawing_area);
1794 //gtk_widget_queue_draw_area (drawing->drawing_area,
1795 // 0,0,
1796 // control_flow_data->drawing->width,
1797 // control_flow_data->drawing->height);
a43d67ba 1798
a56a1ba4 1799 /* Get new data for the rest. */
501d5405 1800 drawing_data_request(control_flow_data->drawing,
6395d57c 1801 drawing->damage_begin, 0,
1802 drawing->damage_end - drawing->damage_begin,
501d5405 1803 control_flow_data->drawing->height);
a56a1ba4 1804 } else {
1805 //if(ns<os<ns+w)
1806 //if(ns<os && os<ns+w)
1807 //if(ns<os && os<new_end)
1808 if(ltt_time_compare(*ns,*os) == -1
1809 && ltt_time_compare(*os,new_end) == -1)
1810 {
1811 g_info("scrolling near left");
1812 /* Scroll left, keep left part of the screen */
1813 guint x = 0;
51705146 1814 guint width = control_flow_data->drawing->width;
a56a1ba4 1815 convert_time_to_pixels(
a18124ff 1816 *new_time_window,
a56a1ba4 1817 *os,
1818 width,
1819 &x);
6395d57c 1820
a56a1ba4 1821 /* Copy old data to new location */
1c736ed5 1822 copy_pixmap_region (process_list,
1823 NULL,
cfe526b1 1824 control_flow_data->drawing->drawing_area->style->black_gc,
1c736ed5 1825 NULL,
a56a1ba4 1826 0, 0,
1827 x, 0,
1828 -1, -1);
1829
6395d57c 1830 if(drawing->damage_begin == drawing->damage_end)
1831 drawing->damage_end = x;
1832 else
1833 drawing->damage_end =
51705146 1834 control_flow_data->drawing->width;
6395d57c 1835
1836 drawing->damage_begin = 0;
1837
1c736ed5 1838 rectangle_pixmap (process_list,
cfe526b1 1839 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 1840 TRUE,
6395d57c 1841 drawing->damage_begin, 0,
1842 drawing->damage_end - drawing->damage_begin, // do not overlap
1c736ed5 1843 -1);
a43d67ba 1844
7abb23ad 1845 gtk_widget_queue_draw(drawing->drawing_area);
1846 //gtk_widget_queue_draw_area (drawing->drawing_area,
1847 // 0,0,
1848 // control_flow_data->drawing->width,
1849 // control_flow_data->drawing->height);
a43d67ba 1850
6395d57c 1851
a56a1ba4 1852 /* Get new data for the rest. */
501d5405 1853 drawing_data_request(control_flow_data->drawing,
6395d57c 1854 drawing->damage_begin, 0,
1855 drawing->damage_end - drawing->damage_begin,
501d5405 1856 control_flow_data->drawing->height);
a56a1ba4 1857
a56a1ba4 1858 } else {
a43d67ba 1859 if(ltt_time_compare(*ns,*os) == 0)
1860 {
1861 g_info("not scrolling");
1862 } else {
1863 g_info("scrolling far");
1864 /* Cannot reuse any part of the screen : far jump */
1865
1866
1c736ed5 1867 rectangle_pixmap (process_list,
a43d67ba 1868 control_flow_data->drawing->drawing_area->style->black_gc,
1869 TRUE,
a56a1ba4 1870 0, 0,
a43d67ba 1871 control_flow_data->drawing->width+SAFETY, // do not overlap
1c736ed5 1872 -1);
a43d67ba 1873
7abb23ad 1874 //gtk_widget_queue_draw_area (drawing->drawing_area,
1875 // 0,0,
1876 // control_flow_data->drawing->width,
1877 // control_flow_data->drawing->height);
1878 gtk_widget_queue_draw(drawing->drawing_area);
a43d67ba 1879
6395d57c 1880 drawing->damage_begin = 0;
1881 drawing->damage_end = control_flow_data->drawing->width;
1882
a43d67ba 1883 drawing_data_request(control_flow_data->drawing,
a43d67ba 1884 0, 0,
1885 control_flow_data->drawing->width,
1886 control_flow_data->drawing->height);
1887
1888 }
a56a1ba4 1889 }
1890 }
1891 } else {
1892 /* Different scale (zoom) */
1893 g_info("zoom");
1894
1c736ed5 1895 rectangle_pixmap (process_list,
cfe526b1 1896 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 1897 TRUE,
1898 0, 0,
501d5405 1899 control_flow_data->drawing->width+SAFETY, // do not overlap
1c736ed5 1900 -1);
a56a1ba4 1901
7abb23ad 1902 //gtk_widget_queue_draw_area (drawing->drawing_area,
1903 // 0,0,
1904 // control_flow_data->drawing->width,
1905 // control_flow_data->drawing->height);
1906 gtk_widget_queue_draw(drawing->drawing_area);
a56a1ba4 1907
6395d57c 1908 drawing->damage_begin = 0;
1909 drawing->damage_end = control_flow_data->drawing->width;
1910
501d5405 1911 drawing_data_request(control_flow_data->drawing,
a56a1ba4 1912 0, 0,
501d5405 1913 control_flow_data->drawing->width,
1914 control_flow_data->drawing->height);
a56a1ba4 1915 }
1916
3cb8b205 1917
1918
a56a1ba4 1919 return 0;
f7afe191 1920}
1921
6395d57c 1922gint traceset_notify(void *hook_data, void *call_data)
1923{
1924 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1925 Drawing_t *drawing = control_flow_data->drawing;
6395d57c 1926
6395d57c 1927
b9a010a2 1928 drawing_clear(control_flow_data->drawing);
1929 processlist_clear(control_flow_data->process_list);
07390ec1 1930 gtk_widget_set_size_request(
1931 control_flow_data->drawing->drawing_area,
1932 -1, processlist_get_height(control_flow_data->process_list));
d9267eec 1933 redraw_notify(control_flow_data, NULL);
6395d57c 1934
d9267eec 1935 request_background_data(control_flow_data);
6395d57c 1936
1937 return FALSE;
1938}
1939
ca0f8a8e 1940gint redraw_notify(void *hook_data, void *call_data)
1941{
1942 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1943 Drawing_t *drawing = control_flow_data->drawing;
1944 GtkWidget *widget = drawing->drawing_area;
1945
1946 drawing->damage_begin = 0;
51705146 1947 drawing->damage_end = drawing->width;
ca0f8a8e 1948
49217bd4 1949 /* fun feature, to be separated someday... */
1950 drawing_clear(control_flow_data->drawing);
1951 processlist_clear(control_flow_data->process_list);
07390ec1 1952 gtk_widget_set_size_request(
1953 control_flow_data->drawing->drawing_area,
1954 -1, processlist_get_height(control_flow_data->process_list));
1c736ed5 1955 // Clear the images
1956 rectangle_pixmap (control_flow_data->process_list,
ca0f8a8e 1957 widget->style->black_gc,
1958 TRUE,
1959 0, 0,
f3b7430d 1960 drawing->alloc_width,
1c736ed5 1961 -1);
ca0f8a8e 1962
f3b7430d 1963 gtk_widget_queue_draw(drawing->drawing_area);
4a24fa1f 1964
ca0f8a8e 1965 if(drawing->damage_begin < drawing->damage_end)
1966 {
1967 drawing_data_request(drawing,
ca0f8a8e 1968 drawing->damage_begin,
1969 0,
1970 drawing->damage_end-drawing->damage_begin,
51705146 1971 drawing->height);
ca0f8a8e 1972 }
1973
7abb23ad 1974 //gtk_widget_queue_draw_area(drawing->drawing_area,
1975 // 0,0,
1976 // drawing->width,
1977 // drawing->height);
ca0f8a8e 1978 return FALSE;
1979
1980}
1981
1982
1983gint continue_notify(void *hook_data, void *call_data)
a43d67ba 1984{
1985 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
ca0f8a8e 1986 Drawing_t *drawing = control_flow_data->drawing;
a43d67ba 1987
6395d57c 1988 //g_assert(widget->allocation.width == drawing->damage_end);
ca0f8a8e 1989
1990 if(drawing->damage_begin < drawing->damage_end)
1991 {
1992 drawing_data_request(drawing,
ca0f8a8e 1993 drawing->damage_begin,
1994 0,
1995 drawing->damage_end-drawing->damage_begin,
51705146 1996 drawing->height);
ca0f8a8e 1997 }
1998
1999 return FALSE;
2000}
2001
2002
1b238973 2003gint update_current_time_hook(void *hook_data, void *call_data)
f7afe191 2004{
14963be0 2005 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
a43d67ba 2006 Drawing_t *drawing = control_flow_data->drawing;
a56a1ba4 2007
224446ce 2008 LttTime current_time = *((LttTime*)call_data);
a56a1ba4 2009
ca0f8a8e 2010 TimeWindow time_window =
2011 lttvwindow_get_time_window(control_flow_data->tab);
a56a1ba4 2012
ca0f8a8e 2013 LttTime time_begin = time_window.start_time;
2014 LttTime width = time_window.time_width;
90ef7e4a 2015 LttTime half_width;
2016 {
2017 guint64 time_ll = ltt_time_to_uint64(width);
2018 time_ll = time_ll >> 1; /* divide by two */
2019 half_width = ltt_time_from_uint64(time_ll);
2020 }
a56a1ba4 2021 LttTime time_end = ltt_time_add(time_begin, width);
2022
2023 LttvTracesetContext * tsc =
ca0f8a8e 2024 lttvwindow_get_traceset_context(control_flow_data->tab);
a56a1ba4 2025
ca0f8a8e 2026 LttTime trace_start = tsc->time_span.start_time;
2027 LttTime trace_end = tsc->time_span.end_time;
a56a1ba4 2028
2eef04b5 2029 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
224446ce 2030 current_time.tv_nsec);
a56a1ba4 2031
2032
2033
2034 /* If current time is inside time interval, just move the highlight
2035 * bar */
2036
2037 /* Else, we have to change the time interval. We have to tell it
2038 * to the main window. */
2039 /* The time interval change will take care of placing the current
2040 * time at the center of the visible area, or nearest possible if we are
2041 * at one end of the trace. */
2042
2043
dbc0ef8a 2044 if(ltt_time_compare(current_time, time_begin) < 0)
a56a1ba4 2045 {
224446ce 2046 TimeWindow new_time_window;
2047
2048 if(ltt_time_compare(current_time,
dbc0ef8a 2049 ltt_time_add(trace_start,half_width)) < 0)
a56a1ba4 2050 time_begin = trace_start;
2051 else
224446ce 2052 time_begin = ltt_time_sub(current_time,half_width);
a56a1ba4 2053
224446ce 2054 new_time_window.start_time = time_begin;
2055 new_time_window.time_width = width;
a18124ff 2056 new_time_window.time_width_double = ltt_time_to_double(width);
6f26fc38 2057 new_time_window.end_time = ltt_time_add(time_begin, width);
a56a1ba4 2058
e800cf84 2059 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
a56a1ba4 2060 }
dbc0ef8a 2061 else if(ltt_time_compare(current_time, time_end) > 0)
a56a1ba4 2062 {
224446ce 2063 TimeWindow new_time_window;
2064
dbc0ef8a 2065 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
a56a1ba4 2066 time_begin = ltt_time_sub(trace_end,width);
2067 else
224446ce 2068 time_begin = ltt_time_sub(current_time,half_width);
a56a1ba4 2069
224446ce 2070 new_time_window.start_time = time_begin;
2071 new_time_window.time_width = width;
a18124ff 2072 new_time_window.time_width_double = ltt_time_to_double(width);
6f26fc38 2073 new_time_window.end_time = ltt_time_add(time_begin, width);
a56a1ba4 2074
e800cf84 2075 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
a56a1ba4 2076
2077 }
7abb23ad 2078 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2079
a56a1ba4 2080
2081 return 0;
f7afe191 2082}
2083
8b90e648 2084typedef struct _ClosureData {
ca0f8a8e 2085 EventsRequest *events_request;
d0cd7f09 2086 LttvTracesetState *tss;
b9a010a2 2087 LttTime end_time;
bc8d270b 2088 guint x_end;
8b90e648 2089} ClosureData;
a56a1ba4 2090
8b90e648 2091
e800cf84 2092void draw_closure(gpointer key, gpointer value, gpointer user_data)
2093{
a56a1ba4 2094 ProcessInfo *process_info = (ProcessInfo*)key;
2095 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
2096 ClosureData *closure_data = (ClosureData*)user_data;
2097
e800cf84 2098 EventsRequest *events_request = closure_data->events_request;
2099 ControlFlowData *control_flow_data = events_request->viewer_data;
a56a1ba4 2100
e800cf84 2101 LttvTracesetState *tss = closure_data->tss;
d6fef890 2102 LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
a56a1ba4 2103
e800cf84 2104 LttTime evtime = closure_data->end_time;
d0cd7f09 2105
e800cf84 2106 {
2107 /* For the process */
2108 /* First, check if the current process is in the state computation
2109 * process list. If it is there, that means we must add it right now and
2110 * draw items from the beginning of the read for it. If it is not
2111 * present, it's a new process and it was not present : it will
2112 * be added after the state update. */
31b6868d 2113#ifdef EXTRA_CHECK
e800cf84 2114 g_assert(lttv_traceset_number(tsc->ts) > 0);
31b6868d 2115#endif //EXTRA_CHECK
2c82c4dc 2116 LttvTraceContext *tc = tsc->traces[process_info->trace_num];
348c6ba8 2117 LttvTraceState *ts = (LttvTraceState*)tc;
2c82c4dc 2118
348c6ba8 2119#if 0
2c82c4dc 2120 //FIXME : optimize data structures.
2121 LttvTracefileState *tfs;
2122 LttvTracefileContext *tfc;
2123 guint i;
2124 for(i=0;i<tc->tracefiles->len;i++) {
2125 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
2126 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
2127 && ltt_tracefile_num(tfc->tf) == process_info->cpu)
2128 break;
2129
2130 }
2131 g_assert(i<tc->tracefiles->len);
2132 tfs = LTTV_TRACEFILE_STATE(tfc);
348c6ba8 2133#endif //0
2c82c4dc 2134 // LttvTracefileState *tfs =
2135 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2136 // tracefiles[process_info->cpu];
2da61677 2137
e800cf84 2138 LttvProcessState *process;
348c6ba8 2139 process = lttv_state_find_process(ts, process_info->cpu,
e025a729 2140 process_info->pid);
a56a1ba4 2141
1d1df11d 2142 if(unlikely(process != NULL)) {
e800cf84 2143
2144 /* Only draw for processes that are currently in the trace states */
ad2e83ba 2145
5c230fc4 2146 ProcessList *process_list = control_flow_data->process_list;
1d1df11d 2147#ifdef EXTRA_CHECK
e800cf84 2148 /* Should be alike when background info is ready */
2149 if(control_flow_data->background_info_waiting==0)
2150 g_assert(ltt_time_compare(process->creation_time,
2151 process_info->birth) == 0);
1d1df11d 2152#endif //EXTRA_CHECK
e800cf84 2153
2154 /* Now, the process is in the state hash and our own process hash.
2155 * We definitely can draw the items related to the ending state.
2156 */
2157
1d1df11d 2158 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
2159 evtime) <= 0))
e800cf84 2160 {
fd22065b 2161 TimeWindow time_window =
2162 lttvwindow_get_time_window(control_flow_data->tab);
2163
2164#ifdef EXTRA_CHECK
2165 if(ltt_time_compare(evtime, time_window.start_time) == -1
2166 || ltt_time_compare(evtime, time_window.end_time) == 1)
2167 return;
2168#endif //EXTRA_CHECK
d6fef890 2169 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 2170 guint width = drawing->width;
a56a1ba4 2171
bc8d270b 2172 guint x = closure_data->x_end;
8b90e648 2173
4b7dc462 2174 DrawContext draw_context;
2175
e800cf84 2176 /* Now create the drawing context that will be used to draw
2177 * items related to the last state. */
1c736ed5 2178 draw_context.drawable = hashed_process_data->pixmap;
e800cf84 2179 draw_context.gc = drawing->gc;
2180 draw_context.pango_layout = drawing->pango_layout;
e800cf84 2181 draw_context.drawinfo.end.x = x;
2182
1c736ed5 2183 draw_context.drawinfo.y.over = 1;
2184 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
2185 draw_context.drawinfo.y.under = hashed_process_data->height;
e800cf84 2186
2187 draw_context.drawinfo.start.offset.over = 0;
2188 draw_context.drawinfo.start.offset.middle = 0;
2189 draw_context.drawinfo.start.offset.under = 0;
2190 draw_context.drawinfo.end.offset.over = 0;
2191 draw_context.drawinfo.end.offset.middle = 0;
2192 draw_context.drawinfo.end.offset.under = 0;
9a1ec01b 2193#if 0
4b7dc462 2194 /* Jump over draw if we are at the same x position */
2195 if(x == hashed_process_data->x.over)
e800cf84 2196 {
4b7dc462 2197 /* jump */
2198 } else {
23093869 2199 draw_context.drawinfo.start.x = hashed_process_data->x.over;
2200 /* Draw the line */
2201 PropertiesLine prop_line = prepare_execmode_line(process);
2202 draw_line((void*)&prop_line, (void*)&draw_context);
2203
4b7dc462 2204 hashed_process_data->x.over = x;
23093869 2205 }
9a1ec01b 2206#endif //0
4b7dc462 2207
1d1df11d 2208 if(unlikely(x == hashed_process_data->x.middle &&
2209 hashed_process_data->x.middle_used)) {
b2743953 2210#if 0 /* do not mark closure : not missing information */
e72908ed 2211 if(hashed_process_data->x.middle_marked == FALSE) {
2212 /* Draw collision indicator */
2213 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
2214 gdk_draw_point(drawing->pixmap,
2215 drawing->gc,
2216 x,
2c6618bc 2217 y+(height/2)-3);
de4ea1ad 2218 hashed_process_data->x.middle_marked = TRUE;
e72908ed 2219 }
b2743953 2220#endif //0
4b7dc462 2221 /* Jump */
2222 } else {
23093869 2223 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
e800cf84 2224 /* Draw the line */
9a1ec01b 2225 PropertiesLine prop_line = prepare_s_e_line(process);
e800cf84 2226 draw_line((void*)&prop_line, (void*)&draw_context);
2227
4b7dc462 2228 /* become the last x position */
1d1df11d 2229 if(likely(x != hashed_process_data->x.middle)) {
e72908ed 2230 hashed_process_data->x.middle = x;
2231 /* but don't use the pixel */
2232 hashed_process_data->x.middle_used = FALSE;
b2743953 2233
2234 /* Calculate the next good time */
2235 convert_pixels_to_time(width, x+1, time_window,
2236 &hashed_process_data->next_good_time);
e72908ed 2237 }
e800cf84 2238 }
e800cf84 2239 }
2240 }
2241 }
2242 return;
8b90e648 2243}
2244
b9a010a2 2245int before_chunk(void *hook_data, void *call_data)
2246{
2247 EventsRequest *events_request = (EventsRequest*)hook_data;
16b9cadb 2248 LttvTracesetState *tss = (LttvTracesetState*)call_data;
7c0125e0 2249 ControlFlowData *cfd = (ControlFlowData*)events_request->viewer_data;
cd3892fe 2250#if 0
7c0125e0 2251 /* Desactivate sort */
2252 gtk_tree_sortable_set_sort_column_id(
2253 GTK_TREE_SORTABLE(cfd->process_list->list_store),
2254 TRACE_COLUMN,
2255 GTK_SORT_ASCENDING);
cd3892fe 2256#endif //0
b9a010a2 2257 drawing_chunk_begin(events_request, tss);
2258
2259 return 0;
2260}
2261
2262int before_request(void *hook_data, void *call_data)
ca0f8a8e 2263{
2264 EventsRequest *events_request = (EventsRequest*)hook_data;
16b9cadb 2265 LttvTracesetState *tss = (LttvTracesetState*)call_data;
7c0125e0 2266
ca0f8a8e 2267 drawing_data_request_begin(events_request, tss);
2268
2269 return 0;
2270}
2271
2272
8b90e648 2273/*
b9a010a2 2274 * after request is necessary in addition of after chunk in order to draw
2275 * lines until the end of the screen. after chunk just draws lines until
2276 * the last event.
2277 *
8b90e648 2278 * for each process
a56a1ba4 2279 * draw closing line
b9a010a2 2280 * expose
8b90e648 2281 */
b9a010a2 2282int after_request(void *hook_data, void *call_data)
8b90e648 2283{
ca0f8a8e 2284 EventsRequest *events_request = (EventsRequest*)hook_data;
2285 ControlFlowData *control_flow_data = events_request->viewer_data;
16b9cadb 2286 LttvTracesetState *tss = (LttvTracesetState*)call_data;
a56a1ba4 2287
5c230fc4 2288 ProcessList *process_list = control_flow_data->process_list;
b9a010a2 2289 LttTime end_time = events_request->end_time;
2290
2291 ClosureData closure_data;
2292 closure_data.events_request = (EventsRequest*)hook_data;
2293 closure_data.tss = tss;
2294 closure_data.end_time = end_time;
2295
bc8d270b 2296 TimeWindow time_window =
2297 lttvwindow_get_time_window(control_flow_data->tab);
2298 guint width = control_flow_data->drawing->width;
2299 convert_time_to_pixels(
2300 time_window,
2301 end_time,
2302 width,
2303 &closure_data.x_end);
2304
2305
b9a010a2 2306 /* Draw last items */
2307 g_hash_table_foreach(process_list->process_hash, draw_closure,
2308 (void*)&closure_data);
7c0125e0 2309
b9a010a2 2310
2311 /* Request expose */
2312 drawing_request_expose(events_request, tss, end_time);
2313 return 0;
2314}
2315
2316/*
2317 * for each process
2318 * draw closing line
e800cf84 2319 * expose
b9a010a2 2320 */
2321int after_chunk(void *hook_data, void *call_data)
2322{
2323 EventsRequest *events_request = (EventsRequest*)hook_data;
2324 ControlFlowData *control_flow_data = events_request->viewer_data;
16b9cadb 2325 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2326 LttvTracesetContext *tsc = (LttvTracesetContext*)call_data;
b9a010a2 2327 LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc);
2328 LttTime end_time;
2329
5c230fc4 2330 ProcessList *process_list = control_flow_data->process_list;
b9a010a2 2331
40debf7b 2332 g_free(process_list->current_hash_data);
2333 process_list->current_hash_data = NULL;
2334
e800cf84 2335 if(tfc != NULL)
2336 end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time);
0c5dbe3b 2337 else /* end of traceset, or position now out of request : end */
2338 end_time = events_request->end_time;
2339
a56a1ba4 2340 ClosureData closure_data;
ca0f8a8e 2341 closure_data.events_request = (EventsRequest*)hook_data;
2342 closure_data.tss = tss;
b9a010a2 2343 closure_data.end_time = end_time;
a56a1ba4 2344
bc8d270b 2345 TimeWindow time_window =
2346 lttvwindow_get_time_window(control_flow_data->tab);
2347 guint width = control_flow_data->drawing->width;
2348 convert_time_to_pixels(
2349 time_window,
2350 end_time,
2351 width,
2352 &closure_data.x_end);
2353
b9a010a2 2354 /* Draw last items */
14963be0 2355 g_hash_table_foreach(process_list->process_hash, draw_closure,
a56a1ba4 2356 (void*)&closure_data);
cd3892fe 2357#if 0
7c0125e0 2358 /* Reactivate sort */
2359 gtk_tree_sortable_set_sort_column_id(
2360 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2361 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2362 GTK_SORT_ASCENDING);
2363
2364 update_index_to_pixmap(control_flow_data->process_list);
cd3892fe 2365 /* Request a full expose : drawing scrambled */
2366 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2367#endif //0
2368 /* Request expose (updates damages zone also) */
b9a010a2 2369 drawing_request_expose(events_request, tss, end_time);
ca0f8a8e 2370
2371 return 0;
8b90e648 2372}
2373
This page took 0.183767 seconds and 4 git commands to generate.