add get start time monotonic
[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
703b25fa 91static gint background_ready(void *hook_data, void *call_data)
6395d57c 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 */
3f7f592e 116static void request_background_data(ControlFlowData *control_flow_data)
6395d57c 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,
8e680509 537 ltt_tracefile_num(tfc->tf),
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,
8e680509 549 ltt_tracefile_num(tfc->tf),
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 }
8e680509 671 } else
672 g_warning("Cannot find pin_in in schedchange %u", pid_in);
b9a010a2 673 }
b9a010a2 674 return 0;
675
676
b9a010a2 677
a56a1ba4 678
51705146 679 /* Text dump */
80a52ff8 680#ifdef DONTSHOW
a56a1ba4 681 GString *string = g_string_new("");;
682 gboolean field_names = TRUE, state = TRUE;
80a52ff8 683
e9a9c513 684 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
685 g_string_append_printf(string,"\n");
686
687 if(state) {
688 g_string_append_printf(string, " %s",
689 g_quark_to_string(tfs->process->state->s));
690 }
691
692 g_info("%s",string->str);
693
a56a1ba4 694 g_string_free(string, TRUE);
695
696 /* End of text dump */
80a52ff8 697#endif //DONTSHOW
50439712 698
f0d936c0 699}
700
e92eabaf 701/* after_schedchange_hook
b9a010a2 702 *
703 * The draw after hook is called by the reading API to have a
704 * particular event drawn on the screen.
705 * @param hook_data ControlFlowData structure of the viewer.
706 * @param call_data Event context.
707 *
708 * This function adds items to be drawn in a queue for each process.
709 *
710 */
e92eabaf 711int after_schedchange_hook(void *hook_data, void *call_data)
f0d936c0 712{
2c82c4dc 713 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
714 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
ca0f8a8e 715 ControlFlowData *control_flow_data = events_request->viewer_data;
50439712 716
a56a1ba4 717 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
50439712 718
719 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
720
348c6ba8 721 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
722
b9a010a2 723 LttEvent *e;
2c82c4dc 724 e = ltt_tracefile_get_event(tfc->tf);
b9a010a2 725
726 LttTime evtime = ltt_event_time(e);
b9a010a2 727
10a1069a 728 /* Add process to process list (if not present) */
2eef04b5 729 LttvProcessState *process_in;
10a1069a 730 LttTime birth;
1c736ed5 731 guint pl_height = 0;
10a1069a 732 HashedProcessData *hashed_process_data_in = NULL;
b9a010a2 733
5c230fc4 734 ProcessList *process_list = control_flow_data->process_list;
10a1069a 735
736 guint pid_in;
737 {
738 guint pid_out;
2c82c4dc 739 pid_out = ltt_event_get_long_unsigned(e, thf->f1);
740 pid_in = ltt_event_get_long_unsigned(e, thf->f2);
10a1069a 741 }
b9a010a2 742
743
10a1069a 744 /* Find process pid_in in the list... */
348c6ba8 745 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
746 //process_in = tfs->process;
747 guint cpu = ltt_tracefile_num(tfc->tf);
748 process_in = ts->running_process[cpu];
10a1069a 749 /* It should exist, because we are after the state update. */
96947fcf 750#ifdef EXTRA_CHECK
10a1069a 751 g_assert(process_in != NULL);
96947fcf 752#endif //EXTRA_CHECK
10a1069a 753 birth = process_in->creation_time;
b9a010a2 754
ac4e21cf 755 hashed_process_data_in = processlist_get_process_data(process_list,
10a1069a 756 pid_in,
348c6ba8 757 process_in->cpu,
10a1069a 758 &birth,
ac4e21cf 759 tfc->t_context->index);
760 if(hashed_process_data_in == NULL)
10a1069a 761 {
762 g_assert(pid_in == 0 || pid_in != process_in->ppid);
4e86ae2e 763 ProcessInfo *process_info;
1c736ed5 764 Drawing_t *drawing = control_flow_data->drawing;
10a1069a 765 /* Process not present */
766 processlist_add(process_list,
1c736ed5 767 drawing,
10a1069a 768 pid_in,
348c6ba8 769 process_in->cpu,
10a1069a 770 process_in->ppid,
771 &birth,
772 tfc->t_context->index,
f4b88a7d 773 process_in->name,
10a1069a 774 &pl_height,
4e86ae2e 775 &process_info,
10a1069a 776 &hashed_process_data_in);
1c736ed5 777 gtk_widget_set_size_request(drawing->drawing_area,
778 -1,
779 pl_height);
780 gtk_widget_queue_draw(drawing->drawing_area);
b9a010a2 781 }
40debf7b 782 /* Set the current process */
348c6ba8 783 process_list->current_hash_data[process_in->cpu] =
40debf7b 784 hashed_process_data_in;
10a1069a 785
b2743953 786 if(ltt_time_compare(hashed_process_data_in->next_good_time,
787 evtime) <= 0)
788 {
fd22065b 789 TimeWindow time_window =
790 lttvwindow_get_time_window(control_flow_data->tab);
791
792#ifdef EXTRA_CHECK
793 if(ltt_time_compare(evtime, time_window.start_time) == -1
794 || ltt_time_compare(evtime, time_window.end_time) == 1)
795 return;
796#endif //EXTRA_CHECK
d6fef890 797 Drawing_t *drawing = control_flow_data->drawing;
798 guint width = drawing->width;
b2743953 799 guint new_x;
800
801 convert_time_to_pixels(
802 time_window,
803 evtime,
804 width,
805 &new_x);
e72908ed 806
b2743953 807 if(hashed_process_data_in->x.middle != new_x) {
808 hashed_process_data_in->x.middle = new_x;
809 hashed_process_data_in->x.middle_used = FALSE;
810 hashed_process_data_in->x.middle_marked = FALSE;
811 }
812 }
b9a010a2 813 return 0;
4a24fa1f 814}
b9a010a2 815
816
817
e72908ed 818
4a24fa1f 819/* before_execmode_hook
820 *
821 * This function basically draw lines and icons. Two types of lines are drawn :
822 * one small (3 pixels?) representing the state of the process and the second
823 * type is thicker (10 pixels?) representing on which CPU a process is running
824 * (and this only in running state).
825 *
826 * Extremums of the lines :
827 * x_min : time of the last event context for this process kept in memory.
828 * x_max : time of the current event.
829 * y : middle of the process in the process list. The process is found in the
830 * list, therefore is it's position in pixels.
831 *
832 * The choice of lines'color is defined by the context of the last event for this
833 * process.
834 */
835
e72908ed 836
4a24fa1f 837int before_execmode_hook(void *hook_data, void *call_data)
838{
839 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
840 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
b9a010a2 841 ControlFlowData *control_flow_data = events_request->viewer_data;
842
843 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
844
845 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
b9a010a2 846
4a24fa1f 847 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
848
50439712 849 LttEvent *e;
4a24fa1f 850 e = ltt_tracefile_get_event(tfc->tf);
50439712 851
9444deae 852 LttTime evtime = ltt_event_time(e);
9444deae 853
4a24fa1f 854 /* we are in a execmode, before the state update. We must draw the
855 * items corresponding to the state before it changes : now is the right
856 * time to do it.
857 */
858 /* For the pid */
859 //LttvProcessState *process = tfs->process;
860 guint cpu = ltt_tracefile_num(tfc->tf);
861 LttvProcessState *process = ts->running_process[cpu];
862 g_assert(process != NULL);
23093869 863
10a1069a 864 guint pid = process->pid;
23093869 865
10a1069a 866 /* Well, the process_out existed : we must get it in the process hash
867 * or add it, and draw its items.
868 */
869 /* Add process to process list (if not present) */
1c736ed5 870 guint pl_height = 0;
10a1069a 871 HashedProcessData *hashed_process_data = NULL;
5c230fc4 872 ProcessList *process_list = control_flow_data->process_list;
10a1069a 873 LttTime birth = process->creation_time;
40debf7b 874
348c6ba8 875 if(likely(process_list->current_hash_data[cpu] != NULL)) {
876 hashed_process_data = process_list->current_hash_data[cpu];
40debf7b 877 } else {
ac4e21cf 878 hashed_process_data = processlist_get_process_data(process_list,
40debf7b 879 pid,
348c6ba8 880 process->cpu,
40debf7b 881 &birth,
ac4e21cf 882 tfc->t_context->index);
1d1df11d 883 if(unlikely(hashed_process_data == NULL))
40debf7b 884 {
885 g_assert(pid == 0 || pid != process->ppid);
886 ProcessInfo *process_info;
887 /* Process not present */
1c736ed5 888 Drawing_t *drawing = control_flow_data->drawing;
40debf7b 889 processlist_add(process_list,
1c736ed5 890 drawing,
40debf7b 891 pid,
348c6ba8 892 process->cpu,
40debf7b 893 process->ppid,
894 &birth,
895 tfc->t_context->index,
f4b88a7d 896 process->name,
40debf7b 897 &pl_height,
898 &process_info,
899 &hashed_process_data);
1c736ed5 900 gtk_widget_set_size_request(drawing->drawing_area,
901 -1,
902 pl_height);
903 gtk_widget_queue_draw(drawing->drawing_area);
40debf7b 904 }
905 /* Set the current process */
348c6ba8 906 process_list->current_hash_data[process->cpu] =
40debf7b 907 hashed_process_data;
10a1069a 908 }
23093869 909
10a1069a 910 /* Now, the process is in the state hash and our own process hash.
911 * We definitely can draw the items related to the ending state.
912 */
b2743953 913
1d1df11d 914 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
915 evtime) > 0))
10a1069a 916 {
1d1df11d 917 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
fd22065b 918 TimeWindow time_window =
919 lttvwindow_get_time_window(control_flow_data->tab);
920
921#ifdef EXTRA_CHECK
922 if(ltt_time_compare(evtime, time_window.start_time) == -1
923 || ltt_time_compare(evtime, time_window.end_time) == 1)
924 return;
925#endif //EXTRA_CHECK
d6fef890 926 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 927 guint width = drawing->width;
b2743953 928 guint x;
929 convert_time_to_pixels(
930 time_window,
931 evtime,
932 width,
933 &x);
934
935 /* Draw collision indicator */
936 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 937 gdk_draw_point(hashed_process_data->pixmap,
b2743953 938 drawing->gc,
939 x,
1c736ed5 940 (hashed_process_data->height/2)-3);
b2743953 941 hashed_process_data->x.middle_marked = TRUE;
942 }
943 } else {
fd22065b 944 TimeWindow time_window =
945 lttvwindow_get_time_window(control_flow_data->tab);
946
947#ifdef EXTRA_CHECK
948 if(ltt_time_compare(evtime, time_window.start_time) == -1
949 || ltt_time_compare(evtime, time_window.end_time) == 1)
950 return;
951#endif //EXTRA_CHECK
d6fef890 952 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 953 guint width = drawing->width;
10a1069a 954 guint x;
dbd243b1 955
10a1069a 956 convert_time_to_pixels(
a18124ff 957 time_window,
10a1069a 958 evtime,
959 width,
960 &x);
dbd243b1 961
23093869 962
4b7dc462 963 /* Jump over draw if we are at the same x position */
1d1df11d 964 if(unlikely(x == hashed_process_data->x.middle &&
965 hashed_process_data->x.middle_used))
10a1069a 966 {
1d1df11d 967 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
e72908ed 968 /* Draw collision indicator */
969 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 970 gdk_draw_point(hashed_process_data->pixmap,
e72908ed 971 drawing->gc,
972 x,
1c736ed5 973 (hashed_process_data->height/2)-3);
de4ea1ad 974 hashed_process_data->x.middle_marked = TRUE;
e72908ed 975 }
4b7dc462 976 /* jump */
977 } else {
978
979 DrawContext draw_context;
980 /* Now create the drawing context that will be used to draw
981 * items related to the last state. */
1c736ed5 982 draw_context.drawable = hashed_process_data->pixmap;
4b7dc462 983 draw_context.gc = drawing->gc;
984 draw_context.pango_layout = drawing->pango_layout;
9a1ec01b 985 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
4b7dc462 986 draw_context.drawinfo.end.x = x;
987
1c736ed5 988 draw_context.drawinfo.y.over = 1;
989 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
990 draw_context.drawinfo.y.under = hashed_process_data->height;
4b7dc462 991
992 draw_context.drawinfo.start.offset.over = 0;
993 draw_context.drawinfo.start.offset.middle = 0;
994 draw_context.drawinfo.start.offset.under = 0;
995 draw_context.drawinfo.end.offset.over = 0;
996 draw_context.drawinfo.end.offset.middle = 0;
997 draw_context.drawinfo.end.offset.under = 0;
998
999 {
1000 /* Draw the line */
9a1ec01b 1001 PropertiesLine prop_line = prepare_s_e_line(process);
4b7dc462 1002 draw_line((void*)&prop_line, (void*)&draw_context);
23093869 1003
4b7dc462 1004 }
1005 /* become the last x position */
9a1ec01b 1006 hashed_process_data->x.middle = x;
e72908ed 1007 hashed_process_data->x.middle_used = TRUE;
1008 hashed_process_data->x.middle_marked = FALSE;
b2743953 1009
1010 /* Calculate the next good time */
1011 convert_pixels_to_time(width, x+1, time_window,
1012 &hashed_process_data->next_good_time);
23093869 1013 }
1014 }
1015
1016 return 0;
1017}
1018
4a24fa1f 1019/* before_process_exit_hook
23093869 1020 *
4a24fa1f 1021 * Draw lines for process event.
1022 *
23093869 1023 * @param hook_data ControlFlowData structure of the viewer.
1024 * @param call_data Event context.
1025 *
1026 * This function adds items to be drawn in a queue for each process.
1027 *
1028 */
8869ac08 1029
1030
4a24fa1f 1031int before_process_exit_hook(void *hook_data, void *call_data)
1032{
2c82c4dc 1033 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1034 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
4a24fa1f 1035
23093869 1036 ControlFlowData *control_flow_data = events_request->viewer_data;
1037
1038 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1039
1040 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
23093869 1041
4a24fa1f 1042 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1043
23093869 1044 LttEvent *e;
2c82c4dc 1045 e = ltt_tracefile_get_event(tfc->tf);
23093869 1046
1047 LttTime evtime = ltt_event_time(e);
23093869 1048
10a1069a 1049 /* Add process to process list (if not present) */
4a24fa1f 1050 //LttvProcessState *process = tfs->process;
1051 guint cpu = ltt_tracefile_num(tfc->tf);
1052 LttvProcessState *process = ts->running_process[cpu];
1053 guint pid = process->pid;
10a1069a 1054 LttTime birth;
1c736ed5 1055 guint pl_height = 0;
10a1069a 1056 HashedProcessData *hashed_process_data = NULL;
23093869 1057
5c230fc4 1058 ProcessList *process_list = control_flow_data->process_list;
4a24fa1f 1059
10a1069a 1060 g_assert(process != NULL);
23093869 1061
10a1069a 1062 birth = process->creation_time;
23093869 1063
4a24fa1f 1064 if(likely(process_list->current_hash_data[cpu] != NULL)) {
1065 hashed_process_data = process_list->current_hash_data[cpu];
40debf7b 1066 } else {
ac4e21cf 1067 hashed_process_data = processlist_get_process_data(process_list,
4a24fa1f 1068 pid,
1069 process->cpu,
1070 &birth,
1071 tfc->t_context->index);
1d1df11d 1072 if(unlikely(hashed_process_data == NULL))
40debf7b 1073 {
1074 g_assert(pid == 0 || pid != process->ppid);
1075 /* Process not present */
1c736ed5 1076 Drawing_t *drawing = control_flow_data->drawing;
40debf7b 1077 ProcessInfo *process_info;
1078 processlist_add(process_list,
1c736ed5 1079 drawing,
40debf7b 1080 pid,
4a24fa1f 1081 process->cpu,
40debf7b 1082 process->ppid,
1083 &birth,
1084 tfc->t_context->index,
4a24fa1f 1085 process->name,
40debf7b 1086 &pl_height,
1087 &process_info,
1088 &hashed_process_data);
4a24fa1f 1089 gtk_widget_set_size_request(drawing->drawing_area,
1090 -1,
1091 pl_height);
1092 gtk_widget_queue_draw(drawing->drawing_area);
40debf7b 1093 }
23093869 1094 }
40debf7b 1095
4a24fa1f 1096 /* Now, the process is in the state hash and our own process hash.
1097 * We definitely can draw the items related to the ending state.
1098 */
1099
1100 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1101 evtime) > 0))
b2743953 1102 {
4a24fa1f 1103 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1104 TimeWindow time_window =
1105 lttvwindow_get_time_window(control_flow_data->tab);
1106
1107#ifdef EXTRA_CHECK
1108 if(ltt_time_compare(evtime, time_window.start_time) == -1
1109 || ltt_time_compare(evtime, time_window.end_time) == 1)
1110 return;
1111#endif //EXTRA_CHECK
1112 Drawing_t *drawing = control_flow_data->drawing;
1113 guint width = drawing->width;
1114 guint x;
1115 convert_time_to_pixels(
1116 time_window,
1117 evtime,
1118 width,
1119 &x);
1120
1121 /* Draw collision indicator */
1122 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1123 gdk_draw_point(hashed_process_data->pixmap,
1124 drawing->gc,
1125 x,
1126 (hashed_process_data->height/2)-3);
1127 hashed_process_data->x.middle_marked = TRUE;
1128 }
1129 } else {
fd22065b 1130 TimeWindow time_window =
1131 lttvwindow_get_time_window(control_flow_data->tab);
1132
1133#ifdef EXTRA_CHECK
1134 if(ltt_time_compare(evtime, time_window.start_time) == -1
1135 || ltt_time_compare(evtime, time_window.end_time) == 1)
1136 return;
1137#endif //EXTRA_CHECK
d6fef890 1138 Drawing_t *drawing = control_flow_data->drawing;
1139 guint width = drawing->width;
4a24fa1f 1140 guint x;
1141
2c82c4dc 1142 convert_time_to_pixels(
1143 time_window,
1144 evtime,
1145 width,
1146 &x);
1147
b2743953 1148
2c82c4dc 1149 /* Jump over draw if we are at the same x position */
1150 if(unlikely(x == hashed_process_data->x.middle &&
1151 hashed_process_data->x.middle_used))
1152 {
1153 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
b2743953 1154 /* Draw collision indicator */
1155 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1c736ed5 1156 gdk_draw_point(hashed_process_data->pixmap,
b2743953 1157 drawing->gc,
1158 x,
1c736ed5 1159 (hashed_process_data->height/2)-3);
b2743953 1160 hashed_process_data->x.middle_marked = TRUE;
1161 }
2c82c4dc 1162 /* jump */
b2743953 1163 } else {
2c82c4dc 1164 DrawContext draw_context;
fd22065b 1165
2c82c4dc 1166 /* Now create the drawing context that will be used to draw
1167 * items related to the last state. */
1168 draw_context.drawable = hashed_process_data->pixmap;
1169 draw_context.gc = drawing->gc;
1170 draw_context.pango_layout = drawing->pango_layout;
1171 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1172 draw_context.drawinfo.end.x = x;
dbd243b1 1173
2c82c4dc 1174 draw_context.drawinfo.y.over = 1;
1175 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1176 draw_context.drawinfo.y.under = hashed_process_data->height;
dbd243b1 1177
2c82c4dc 1178 draw_context.drawinfo.start.offset.over = 0;
1179 draw_context.drawinfo.start.offset.middle = 0;
1180 draw_context.drawinfo.start.offset.under = 0;
1181 draw_context.drawinfo.end.offset.over = 0;
1182 draw_context.drawinfo.end.offset.middle = 0;
1183 draw_context.drawinfo.end.offset.under = 0;
dbd243b1 1184
2c82c4dc 1185 {
1186 /* Draw the line */
1187 PropertiesLine prop_line = prepare_s_e_line(process);
1188 draw_line((void*)&prop_line, (void*)&draw_context);
dbd243b1 1189
2c82c4dc 1190 }
1191 /* become the last x position */
1192 hashed_process_data->x.middle = x;
1193 hashed_process_data->x.middle_used = TRUE;
1194 hashed_process_data->x.middle_marked = FALSE;
dbd243b1 1195
2c82c4dc 1196 /* Calculate the next good time */
1197 convert_pixels_to_time(width, x+1, time_window,
1198 &hashed_process_data->next_good_time);
1199 }
1200 }
1201
1202 return 0;
1203
1204}
1205
1206
1207
1208/* before_process_release_hook
1209 *
1210 * Draw lines for process event.
1211 *
1212 * @param hook_data ControlFlowData structure of the viewer.
1213 * @param call_data Event context.
1214 *
1215 * This function adds items to be drawn in a queue for each process.
1216 *
1217 */
1218
1219
1220int before_process_release_hook(void *hook_data, void *call_data)
1221{
1222 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1223 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1224
1225 ControlFlowData *control_flow_data = events_request->viewer_data;
1226
1227 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1228
1229 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1230
348c6ba8 1231 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1232
2c82c4dc 1233 LttEvent *e;
1234 e = ltt_tracefile_get_event(tfc->tf);
1235
1236 LttTime evtime = ltt_event_time(e);
1237
1238
1239 guint pid;
1240 {
1241 pid = ltt_event_get_long_unsigned(e, thf->f1);
1242 }
1243
1244 /* Add process to process list (if not present) */
1245 /* Don't care about the process if it's not in the state hash already :
1246 * that means a process that has never done anything in the trace and
1247 * unknown suddently gets destroyed : no state meaningful to show. */
348c6ba8 1248 LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
2c82c4dc 1249
1250 if(process != NULL) {
1251 LttTime birth;
1252 guint pl_height = 0;
1253 HashedProcessData *hashed_process_data = NULL;
1254
1255 ProcessList *process_list = control_flow_data->process_list;
1256
1257 birth = process->creation_time;
1258
1259 /* Cannot use current process : this event happens on another process,
1260 * action done by the parent. */
1261 hashed_process_data = processlist_get_process_data(process_list,
1262 pid,
348c6ba8 1263 process->cpu,
2c82c4dc 1264 &birth,
1265 tfc->t_context->index);
1266 if(unlikely(hashed_process_data == NULL))
1267 {
1268 g_assert(pid == 0 || pid != process->ppid);
1269 /* Process not present */
1270 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1271 ProcessInfo *process_info;
1272 processlist_add(process_list,
1273 drawing,
1274 pid,
348c6ba8 1275 process->cpu,
2c82c4dc 1276 process->ppid,
1277 &birth,
1278 tfc->t_context->index,
f4b88a7d 1279 process->name,
2c82c4dc 1280 &pl_height,
1281 &process_info,
1282 &hashed_process_data);
1283 gtk_widget_set_size_request(drawing->drawing_area,
1284 -1,
1285 pl_height);
1286 gtk_widget_queue_draw(drawing->drawing_area);
1287 }
1288
1289 /* Now, the process is in the state hash and our own process hash.
1290 * We definitely can draw the items related to the ending state.
1291 */
1292
1293 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1294 evtime) > 0))
1295 {
1296 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1297 TimeWindow time_window =
1298 lttvwindow_get_time_window(control_flow_data->tab);
1299
1300#ifdef EXTRA_CHECK
1301 if(ltt_time_compare(evtime, time_window.start_time) == -1
1302 || ltt_time_compare(evtime, time_window.end_time) == 1)
1303 return;
1304#endif //EXTRA_CHECK
1305 Drawing_t *drawing = control_flow_data->drawing;
1306 guint width = drawing->width;
1307 guint x;
1308 convert_time_to_pixels(
1309 time_window,
1310 evtime,
1311 width,
1312 &x);
1313
1314 /* Draw collision indicator */
1315 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1316 gdk_draw_point(hashed_process_data->pixmap,
1317 drawing->gc,
1318 x,
1319 (hashed_process_data->height/2)-3);
1320 hashed_process_data->x.middle_marked = TRUE;
1321 }
1322 } else {
1323 TimeWindow time_window =
1324 lttvwindow_get_time_window(control_flow_data->tab);
1325
1326#ifdef EXTRA_CHECK
1327 if(ltt_time_compare(evtime, time_window.start_time) == -1
4a24fa1f 1328 || ltt_time_compare(evtime, time_window.end_time) == 1)
1329 return;
2da61677 1330#endif //EXTRA_CHECK
4a24fa1f 1331 Drawing_t *drawing = control_flow_data->drawing;
1332 guint width = drawing->width;
1333 guint x;
1334
1335 convert_time_to_pixels(
1336 time_window,
1337 evtime,
1338 width,
1339 &x);
1340
2da61677 1341
4a24fa1f 1342 /* Jump over draw if we are at the same x position */
1343 if(unlikely(x == hashed_process_data->x.middle &&
1344 hashed_process_data->x.middle_used))
1345 {
1346 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
2da61677 1347 /* Draw collision indicator */
1348 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1349 gdk_draw_point(hashed_process_data->pixmap,
1350 drawing->gc,
1351 x,
1352 (hashed_process_data->height/2)-3);
1353 hashed_process_data->x.middle_marked = TRUE;
1354 }
4a24fa1f 1355 /* jump */
2da61677 1356 } else {
4a24fa1f 1357 DrawContext draw_context;
2da61677 1358
4a24fa1f 1359 /* Now create the drawing context that will be used to draw
1360 * items related to the last state. */
1361 draw_context.drawable = hashed_process_data->pixmap;
1362 draw_context.gc = drawing->gc;
1363 draw_context.pango_layout = drawing->pango_layout;
1364 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1365 draw_context.drawinfo.end.x = x;
2da61677 1366
4a24fa1f 1367 draw_context.drawinfo.y.over = 1;
1368 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1369 draw_context.drawinfo.y.under = hashed_process_data->height;
2da61677 1370
4a24fa1f 1371 draw_context.drawinfo.start.offset.over = 0;
1372 draw_context.drawinfo.start.offset.middle = 0;
1373 draw_context.drawinfo.start.offset.under = 0;
1374 draw_context.drawinfo.end.offset.over = 0;
1375 draw_context.drawinfo.end.offset.middle = 0;
1376 draw_context.drawinfo.end.offset.under = 0;
2da61677 1377
4a24fa1f 1378 {
1379 /* Draw the line */
1380 PropertiesLine prop_line = prepare_s_e_line(process);
1381 draw_line((void*)&prop_line, (void*)&draw_context);
2da61677 1382
2da61677 1383 }
4a24fa1f 1384 /* become the last x position */
1385 hashed_process_data->x.middle = x;
1386 hashed_process_data->x.middle_used = TRUE;
1387 hashed_process_data->x.middle_marked = FALSE;
1388
1389 /* Calculate the next good time */
1390 convert_pixels_to_time(width, x+1, time_window,
1391 &hashed_process_data->next_good_time);
2da61677 1392 }
1393 }
dbd243b1 1394 }
dbd243b1 1395
4a24fa1f 1396 return 0;
dbd243b1 1397}
1398
4a24fa1f 1399
2c82c4dc 1400
1401
1402
1403/* after_process_fork_hook
1404 *
1405 * Create the processlist entry for the child process. Put the last
1406 * position in x at the current time value.
1407 *
1408 * @param hook_data ControlFlowData structure of the viewer.
1409 * @param call_data Event context.
1410 *
1411 * This function adds items to be drawn in a queue for each process.
1412 *
1413 */
1414int after_process_fork_hook(void *hook_data, void *call_data)
1415{
1416 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1417 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1418 ControlFlowData *control_flow_data = events_request->viewer_data;
1419
1420 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1421
1422 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1423
348c6ba8 1424 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1425
2c82c4dc 1426 LttEvent *e;
1427 e = ltt_tracefile_get_event(tfc->tf);
1428
1429 LttTime evtime = ltt_event_time(e);
1430
1431 guint child_pid;
1432 {
1433 child_pid = ltt_event_get_long_unsigned(e, thf->f2);
1434 }
1435
1436 /* Add process to process list (if not present) */
1437 LttvProcessState *process_child;
1438 LttTime birth;
1439 guint pl_height = 0;
1440 HashedProcessData *hashed_process_data_child = NULL;
1441
1442 ProcessList *process_list = control_flow_data->process_list;
1443
1444 /* Find child in the list... */
348c6ba8 1445 process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
2c82c4dc 1446 /* It should exist, because we are after the state update. */
1447 g_assert(process_child != NULL);
1448
1449 birth = process_child->creation_time;
1450
1451 /* Cannot use current process, because this action is done by the parent
1452 * on its child. */
1453 hashed_process_data_child = processlist_get_process_data(process_list,
1454 child_pid,
348c6ba8 1455 process_child->cpu,
2c82c4dc 1456 &birth,
1457 tfc->t_context->index);
1458 if(likely(hashed_process_data_child == NULL))
1459 {
1460 g_assert(child_pid == 0 || child_pid != process_child->ppid);
1461 /* Process not present */
1462 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1463 ProcessInfo *process_info;
1464 processlist_add(process_list,
1465 drawing,
1466 child_pid,
348c6ba8 1467 process_child->cpu,
2c82c4dc 1468 process_child->ppid,
1469 &birth,
1470 tfc->t_context->index,
f4b88a7d 1471 process_child->name,
2c82c4dc 1472 &pl_height,
1473 &process_info,
1474 &hashed_process_data_child);
1475 gtk_widget_set_size_request(drawing->drawing_area,
1476 -1,
1477 pl_height);
1478 gtk_widget_queue_draw(drawing->drawing_area);
1479 }
1480
1481
1482 if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1483 evtime) <= 0))
1484 {
1485 TimeWindow time_window =
1486 lttvwindow_get_time_window(control_flow_data->tab);
1487
1488#ifdef EXTRA_CHECK
1489 if(ltt_time_compare(evtime, time_window.start_time) == -1
1490 || ltt_time_compare(evtime, time_window.end_time) == 1)
1491 return;
1492#endif //EXTRA_CHECK
1493 Drawing_t *drawing = control_flow_data->drawing;
1494 guint width = drawing->width;
1495 guint new_x;
1496 convert_time_to_pixels(
1497 time_window,
1498 evtime,
1499 width,
1500 &new_x);
1501
1502 if(likely(hashed_process_data_child->x.over != new_x)) {
1503 hashed_process_data_child->x.over = new_x;
1504 hashed_process_data_child->x.over_used = FALSE;
1505 hashed_process_data_child->x.over_marked = FALSE;
1506 }
1507 if(likely(hashed_process_data_child->x.middle != new_x)) {
1508 hashed_process_data_child->x.middle = new_x;
1509 hashed_process_data_child->x.middle_used = FALSE;
1510 hashed_process_data_child->x.middle_marked = FALSE;
1511 }
1512 if(likely(hashed_process_data_child->x.under != new_x)) {
1513 hashed_process_data_child->x.under = new_x;
1514 hashed_process_data_child->x.under_used = FALSE;
1515 hashed_process_data_child->x.under_marked = FALSE;
1516 }
1517 }
1518 return 0;
1519}
1520
1521
1522
1523/* after_process_exit_hook
1524 *
1525 * Create the processlist entry for the child process. Put the last
1526 * position in x at the current time value.
1527 *
1528 * @param hook_data ControlFlowData structure of the viewer.
1529 * @param call_data Event context.
1530 *
1531 * This function adds items to be drawn in a queue for each process.
1532 *
1533 */
1534int after_process_exit_hook(void *hook_data, void *call_data)
1535{
1536 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1537 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1538 ControlFlowData *control_flow_data = events_request->viewer_data;
1539
1540 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1541
1542 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1543
348c6ba8 1544 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1545
2c82c4dc 1546 LttEvent *e;
1547 e = ltt_tracefile_get_event(tfc->tf);
1548
1549 LttTime evtime = ltt_event_time(e);
1550
1551 /* Add process to process list (if not present) */
348c6ba8 1552 //LttvProcessState *process = tfs->process;
1553 guint cpu = ltt_tracefile_num(tfc->tf);
1554 LttvProcessState *process = ts->running_process[cpu];
1555
1556 /* It should exist, because we are after the state update. */
1557 g_assert(process != NULL);
1558
2c82c4dc 1559 guint pid = process->pid;
1560 LttTime birth;
1561 guint pl_height = 0;
1562 HashedProcessData *hashed_process_data = NULL;
1563
1564 ProcessList *process_list = control_flow_data->process_list;
1565
2c82c4dc 1566 birth = process->creation_time;
1567
348c6ba8 1568 if(likely(process_list->current_hash_data[cpu] != NULL) ){
1569 hashed_process_data = process_list->current_hash_data[cpu];
2c82c4dc 1570 } else {
1571 hashed_process_data = processlist_get_process_data(process_list,
1572 pid,
348c6ba8 1573 process->cpu,
2c82c4dc 1574 &birth,
1575 tfc->t_context->index);
1576 if(unlikely(hashed_process_data == NULL))
1577 {
1578 g_assert(pid == 0 || pid != process->ppid);
1579 /* Process not present */
1580 Drawing_t *drawing = control_flow_data->drawing;
2c82c4dc 1581 ProcessInfo *process_info;
1582 processlist_add(process_list,
1583 drawing,
1584 pid,
348c6ba8 1585 process->cpu,
2c82c4dc 1586 process->ppid,
1587 &birth,
1588 tfc->t_context->index,
f4b88a7d 1589 process->name,
2c82c4dc 1590 &pl_height,
1591 &process_info,
1592 &hashed_process_data);
1593 gtk_widget_set_size_request(drawing->drawing_area,
1594 -1,
1595 pl_height);
1596 gtk_widget_queue_draw(drawing->drawing_area);
1597 }
1598
1599 /* Set the current process */
348c6ba8 1600 process_list->current_hash_data[process->cpu] =
2c82c4dc 1601 hashed_process_data;
1602 }
1603
1604 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1605 evtime) <= 0))
1606 {
1607 TimeWindow time_window =
1608 lttvwindow_get_time_window(control_flow_data->tab);
dbd243b1 1609
2c82c4dc 1610#ifdef EXTRA_CHECK
1611 if(ltt_time_compare(evtime, time_window.start_time) == -1
1612 || ltt_time_compare(evtime, time_window.end_time) == 1)
1613 return;
1614#endif //EXTRA_CHECK
1615 Drawing_t *drawing = control_flow_data->drawing;
1616 guint width = drawing->width;
1617 guint new_x;
1618 convert_time_to_pixels(
1619 time_window,
1620 evtime,
1621 width,
1622 &new_x);
1623 if(unlikely(hashed_process_data->x.middle != new_x)) {
1624 hashed_process_data->x.middle = new_x;
1625 hashed_process_data->x.middle_used = FALSE;
1626 hashed_process_data->x.middle_marked = FALSE;
1627 }
1628 }
dbd243b1 1629
2c82c4dc 1630 return 0;
1631}
dbd243b1 1632
1633
f4b88a7d 1634/* Get the filename of the process to print */
1635int after_fs_exec_hook(void *hook_data, void *call_data)
1636{
1637 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1638 EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1639 ControlFlowData *control_flow_data = events_request->viewer_data;
1640
1641 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1642
1643 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1644
1645 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1646
1647 guint cpu = ltt_tracefile_num(tfc->tf);
1648 LttvProcessState *process = ts->running_process[cpu];
1649 g_assert(process != NULL);
1650
1651 guint pid = process->pid;
1652
1653 /* Well, the process_out existed : we must get it in the process hash
1654 * or add it, and draw its items.
1655 */
1656 /* Add process to process list (if not present) */
1657 guint pl_height = 0;
1658 HashedProcessData *hashed_process_data = NULL;
1659 ProcessList *process_list = control_flow_data->process_list;
1660 LttTime birth = process->creation_time;
1661
1662 if(likely(process_list->current_hash_data[cpu] != NULL)) {
1663 hashed_process_data = process_list->current_hash_data[cpu];
1664 } else {
1665 hashed_process_data = processlist_get_process_data(process_list,
1666 pid,
1667 process->cpu,
1668 &birth,
1669 tfc->t_context->index);
1670 if(unlikely(hashed_process_data == NULL))
1671 {
1672 g_assert(pid == 0 || pid != process->ppid);
1673 ProcessInfo *process_info;
1674 /* Process not present */
1675 Drawing_t *drawing = control_flow_data->drawing;
1676 processlist_add(process_list,
1677 drawing,
1678 pid,
1679 process->cpu,
1680 process->ppid,
1681 &birth,
1682 tfc->t_context->index,
1683 process->name,
1684 &pl_height,
1685 &process_info,
1686 &hashed_process_data);
1687 gtk_widget_set_size_request(drawing->drawing_area,
1688 -1,
1689 pl_height);
1690 gtk_widget_queue_draw(drawing->drawing_area);
1691 }
1692 /* Set the current process */
1693 process_list->current_hash_data[process->cpu] =
1694 hashed_process_data;
1695 }
1696
1697 processlist_set_name(process_list, process->name, hashed_process_data);
1698
1699 return 0;
1700
1701}
1702
1703
1704
1705
1b238973 1706gint update_time_window_hook(void *hook_data, void *call_data)
f7afe191 1707{
a56a1ba4 1708 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
a43d67ba 1709 Drawing_t *drawing = control_flow_data->drawing;
1c736ed5 1710 ProcessList *process_list = control_flow_data->process_list;
a43d67ba 1711
224446ce 1712 const TimeWindowNotifyData *time_window_nofify_data =
1713 ((const TimeWindowNotifyData *)call_data);
1714
14963be0 1715 TimeWindow *old_time_window =
224446ce 1716 time_window_nofify_data->old_time_window;
1717 TimeWindow *new_time_window =
1718 time_window_nofify_data->new_time_window;
a56a1ba4 1719
3cb8b205 1720 /* Update the ruler */
1721 drawing_update_ruler(control_flow_data->drawing,
1722 new_time_window);
1723
1724
a56a1ba4 1725 /* Two cases : zoom in/out or scrolling */
1726
1727 /* In order to make sure we can reuse the old drawing, the scale must
1728 * be the same and the new time interval being partly located in the
1729 * currently shown time interval. (reuse is only for scrolling)
1730 */
1731
2eef04b5 1732 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
14963be0 1733 old_time_window->start_time.tv_sec,
1734 old_time_window->start_time.tv_nsec,
1735 old_time_window->time_width.tv_sec,
1736 old_time_window->time_width.tv_nsec);
a56a1ba4 1737
2eef04b5 1738 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
14963be0 1739 new_time_window->start_time.tv_sec,
1740 new_time_window->start_time.tv_nsec,
1741 new_time_window->time_width.tv_sec,
1742 new_time_window->time_width.tv_nsec);
a56a1ba4 1743
14963be0 1744 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
1745 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
a56a1ba4 1746 {
1747 /* Same scale (scrolling) */
1748 g_info("scrolling");
14963be0 1749 LttTime *ns = &new_time_window->start_time;
20640e70 1750 LttTime *nw = &new_time_window->time_width;
14963be0 1751 LttTime *os = &old_time_window->start_time;
20640e70 1752 LttTime *ow = &old_time_window->time_width;
6f26fc38 1753 LttTime old_end = old_time_window->end_time;
1754 LttTime new_end = new_time_window->end_time;
a56a1ba4 1755 //if(ns<os+w<ns+w)
1756 //if(ns<os+w && os+w<ns+w)
1757 //if(ns<old_end && os<ns)
1758 if(ltt_time_compare(*ns, old_end) == -1
1759 && ltt_time_compare(*os, *ns) == -1)
1760 {
1761 g_info("scrolling near right");
1762 /* Scroll right, keep right part of the screen */
1763 guint x = 0;
51705146 1764 guint width = control_flow_data->drawing->width;
a56a1ba4 1765 convert_time_to_pixels(
a18124ff 1766 *old_time_window,
a56a1ba4 1767 *ns,
1768 width,
1769 &x);
1770
1771 /* Copy old data to new location */
1c736ed5 1772 copy_pixmap_region(process_list,
1773 NULL,
1774 control_flow_data->drawing->drawing_area->style->black_gc,
1775 NULL,
1776 x, 0,
1777 0, 0,
1778 control_flow_data->drawing->width-x+SAFETY, -1);
1779
6395d57c 1780 if(drawing->damage_begin == drawing->damage_end)
1781 drawing->damage_begin = control_flow_data->drawing->width-x;
1782 else
1783 drawing->damage_begin = 0;
1784
1785 drawing->damage_end = control_flow_data->drawing->width;
1786
a56a1ba4 1787 /* Clear the data request background, but not SAFETY */
1c736ed5 1788 rectangle_pixmap(process_list,
cfe526b1 1789 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 1790 TRUE,
6395d57c 1791 drawing->damage_begin+SAFETY, 0,
1792 drawing->damage_end - drawing->damage_begin, // do not overlap
1c736ed5 1793 -1);
7abb23ad 1794 gtk_widget_queue_draw(drawing->drawing_area);
1795 //gtk_widget_queue_draw_area (drawing->drawing_area,
1796 // 0,0,
1797 // control_flow_data->drawing->width,
1798 // control_flow_data->drawing->height);
a43d67ba 1799
a56a1ba4 1800 /* Get new data for the rest. */
501d5405 1801 drawing_data_request(control_flow_data->drawing,
6395d57c 1802 drawing->damage_begin, 0,
1803 drawing->damage_end - drawing->damage_begin,
501d5405 1804 control_flow_data->drawing->height);
a56a1ba4 1805 } else {
1806 //if(ns<os<ns+w)
1807 //if(ns<os && os<ns+w)
1808 //if(ns<os && os<new_end)
1809 if(ltt_time_compare(*ns,*os) == -1
1810 && ltt_time_compare(*os,new_end) == -1)
1811 {
1812 g_info("scrolling near left");
1813 /* Scroll left, keep left part of the screen */
1814 guint x = 0;
51705146 1815 guint width = control_flow_data->drawing->width;
a56a1ba4 1816 convert_time_to_pixels(
a18124ff 1817 *new_time_window,
a56a1ba4 1818 *os,
1819 width,
1820 &x);
6395d57c 1821
a56a1ba4 1822 /* Copy old data to new location */
1c736ed5 1823 copy_pixmap_region (process_list,
1824 NULL,
cfe526b1 1825 control_flow_data->drawing->drawing_area->style->black_gc,
1c736ed5 1826 NULL,
a56a1ba4 1827 0, 0,
1828 x, 0,
1829 -1, -1);
1830
6395d57c 1831 if(drawing->damage_begin == drawing->damage_end)
1832 drawing->damage_end = x;
1833 else
1834 drawing->damage_end =
51705146 1835 control_flow_data->drawing->width;
6395d57c 1836
1837 drawing->damage_begin = 0;
1838
1c736ed5 1839 rectangle_pixmap (process_list,
cfe526b1 1840 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 1841 TRUE,
6395d57c 1842 drawing->damage_begin, 0,
1843 drawing->damage_end - drawing->damage_begin, // do not overlap
1c736ed5 1844 -1);
a43d67ba 1845
7abb23ad 1846 gtk_widget_queue_draw(drawing->drawing_area);
1847 //gtk_widget_queue_draw_area (drawing->drawing_area,
1848 // 0,0,
1849 // control_flow_data->drawing->width,
1850 // control_flow_data->drawing->height);
a43d67ba 1851
6395d57c 1852
a56a1ba4 1853 /* Get new data for the rest. */
501d5405 1854 drawing_data_request(control_flow_data->drawing,
6395d57c 1855 drawing->damage_begin, 0,
1856 drawing->damage_end - drawing->damage_begin,
501d5405 1857 control_flow_data->drawing->height);
a56a1ba4 1858
a56a1ba4 1859 } else {
a43d67ba 1860 if(ltt_time_compare(*ns,*os) == 0)
1861 {
1862 g_info("not scrolling");
1863 } else {
1864 g_info("scrolling far");
1865 /* Cannot reuse any part of the screen : far jump */
1866
1867
1c736ed5 1868 rectangle_pixmap (process_list,
a43d67ba 1869 control_flow_data->drawing->drawing_area->style->black_gc,
1870 TRUE,
a56a1ba4 1871 0, 0,
a43d67ba 1872 control_flow_data->drawing->width+SAFETY, // do not overlap
1c736ed5 1873 -1);
a43d67ba 1874
7abb23ad 1875 //gtk_widget_queue_draw_area (drawing->drawing_area,
1876 // 0,0,
1877 // control_flow_data->drawing->width,
1878 // control_flow_data->drawing->height);
1879 gtk_widget_queue_draw(drawing->drawing_area);
a43d67ba 1880
6395d57c 1881 drawing->damage_begin = 0;
1882 drawing->damage_end = control_flow_data->drawing->width;
1883
a43d67ba 1884 drawing_data_request(control_flow_data->drawing,
a43d67ba 1885 0, 0,
1886 control_flow_data->drawing->width,
1887 control_flow_data->drawing->height);
1888
1889 }
a56a1ba4 1890 }
1891 }
1892 } else {
1893 /* Different scale (zoom) */
1894 g_info("zoom");
1895
1c736ed5 1896 rectangle_pixmap (process_list,
cfe526b1 1897 control_flow_data->drawing->drawing_area->style->black_gc,
a56a1ba4 1898 TRUE,
1899 0, 0,
501d5405 1900 control_flow_data->drawing->width+SAFETY, // do not overlap
1c736ed5 1901 -1);
a56a1ba4 1902
7abb23ad 1903 //gtk_widget_queue_draw_area (drawing->drawing_area,
1904 // 0,0,
1905 // control_flow_data->drawing->width,
1906 // control_flow_data->drawing->height);
1907 gtk_widget_queue_draw(drawing->drawing_area);
a56a1ba4 1908
6395d57c 1909 drawing->damage_begin = 0;
1910 drawing->damage_end = control_flow_data->drawing->width;
1911
501d5405 1912 drawing_data_request(control_flow_data->drawing,
a56a1ba4 1913 0, 0,
501d5405 1914 control_flow_data->drawing->width,
1915 control_flow_data->drawing->height);
a56a1ba4 1916 }
1917
3cb8b205 1918
1919
a56a1ba4 1920 return 0;
f7afe191 1921}
1922
6395d57c 1923gint traceset_notify(void *hook_data, void *call_data)
1924{
1925 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1926 Drawing_t *drawing = control_flow_data->drawing;
6395d57c 1927
6395d57c 1928
b9a010a2 1929 drawing_clear(control_flow_data->drawing);
1930 processlist_clear(control_flow_data->process_list);
07390ec1 1931 gtk_widget_set_size_request(
1932 control_flow_data->drawing->drawing_area,
1933 -1, processlist_get_height(control_flow_data->process_list));
d9267eec 1934 redraw_notify(control_flow_data, NULL);
6395d57c 1935
d9267eec 1936 request_background_data(control_flow_data);
6395d57c 1937
1938 return FALSE;
1939}
1940
ca0f8a8e 1941gint redraw_notify(void *hook_data, void *call_data)
1942{
1943 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1944 Drawing_t *drawing = control_flow_data->drawing;
1945 GtkWidget *widget = drawing->drawing_area;
1946
1947 drawing->damage_begin = 0;
51705146 1948 drawing->damage_end = drawing->width;
ca0f8a8e 1949
49217bd4 1950 /* fun feature, to be separated someday... */
1951 drawing_clear(control_flow_data->drawing);
1952 processlist_clear(control_flow_data->process_list);
07390ec1 1953 gtk_widget_set_size_request(
1954 control_flow_data->drawing->drawing_area,
1955 -1, processlist_get_height(control_flow_data->process_list));
1c736ed5 1956 // Clear the images
1957 rectangle_pixmap (control_flow_data->process_list,
ca0f8a8e 1958 widget->style->black_gc,
1959 TRUE,
1960 0, 0,
f3b7430d 1961 drawing->alloc_width,
1c736ed5 1962 -1);
ca0f8a8e 1963
f3b7430d 1964 gtk_widget_queue_draw(drawing->drawing_area);
4a24fa1f 1965
ca0f8a8e 1966 if(drawing->damage_begin < drawing->damage_end)
1967 {
1968 drawing_data_request(drawing,
ca0f8a8e 1969 drawing->damage_begin,
1970 0,
1971 drawing->damage_end-drawing->damage_begin,
51705146 1972 drawing->height);
ca0f8a8e 1973 }
1974
7abb23ad 1975 //gtk_widget_queue_draw_area(drawing->drawing_area,
1976 // 0,0,
1977 // drawing->width,
1978 // drawing->height);
ca0f8a8e 1979 return FALSE;
1980
1981}
1982
1983
1984gint continue_notify(void *hook_data, void *call_data)
a43d67ba 1985{
1986 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
ca0f8a8e 1987 Drawing_t *drawing = control_flow_data->drawing;
a43d67ba 1988
6395d57c 1989 //g_assert(widget->allocation.width == drawing->damage_end);
ca0f8a8e 1990
1991 if(drawing->damage_begin < drawing->damage_end)
1992 {
1993 drawing_data_request(drawing,
ca0f8a8e 1994 drawing->damage_begin,
1995 0,
1996 drawing->damage_end-drawing->damage_begin,
51705146 1997 drawing->height);
ca0f8a8e 1998 }
1999
2000 return FALSE;
2001}
2002
2003
1b238973 2004gint update_current_time_hook(void *hook_data, void *call_data)
f7afe191 2005{
14963be0 2006 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
a43d67ba 2007 Drawing_t *drawing = control_flow_data->drawing;
a56a1ba4 2008
224446ce 2009 LttTime current_time = *((LttTime*)call_data);
a56a1ba4 2010
ca0f8a8e 2011 TimeWindow time_window =
2012 lttvwindow_get_time_window(control_flow_data->tab);
a56a1ba4 2013
ca0f8a8e 2014 LttTime time_begin = time_window.start_time;
2015 LttTime width = time_window.time_width;
90ef7e4a 2016 LttTime half_width;
2017 {
2018 guint64 time_ll = ltt_time_to_uint64(width);
2019 time_ll = time_ll >> 1; /* divide by two */
2020 half_width = ltt_time_from_uint64(time_ll);
2021 }
a56a1ba4 2022 LttTime time_end = ltt_time_add(time_begin, width);
2023
2024 LttvTracesetContext * tsc =
ca0f8a8e 2025 lttvwindow_get_traceset_context(control_flow_data->tab);
a56a1ba4 2026
ca0f8a8e 2027 LttTime trace_start = tsc->time_span.start_time;
2028 LttTime trace_end = tsc->time_span.end_time;
a56a1ba4 2029
2eef04b5 2030 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
224446ce 2031 current_time.tv_nsec);
a56a1ba4 2032
2033
2034
2035 /* If current time is inside time interval, just move the highlight
2036 * bar */
2037
2038 /* Else, we have to change the time interval. We have to tell it
2039 * to the main window. */
2040 /* The time interval change will take care of placing the current
2041 * time at the center of the visible area, or nearest possible if we are
2042 * at one end of the trace. */
2043
2044
dbc0ef8a 2045 if(ltt_time_compare(current_time, time_begin) < 0)
a56a1ba4 2046 {
224446ce 2047 TimeWindow new_time_window;
2048
2049 if(ltt_time_compare(current_time,
dbc0ef8a 2050 ltt_time_add(trace_start,half_width)) < 0)
a56a1ba4 2051 time_begin = trace_start;
2052 else
224446ce 2053 time_begin = ltt_time_sub(current_time,half_width);
a56a1ba4 2054
224446ce 2055 new_time_window.start_time = time_begin;
2056 new_time_window.time_width = width;
a18124ff 2057 new_time_window.time_width_double = ltt_time_to_double(width);
6f26fc38 2058 new_time_window.end_time = ltt_time_add(time_begin, width);
a56a1ba4 2059
e800cf84 2060 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
a56a1ba4 2061 }
dbc0ef8a 2062 else if(ltt_time_compare(current_time, time_end) > 0)
a56a1ba4 2063 {
224446ce 2064 TimeWindow new_time_window;
2065
dbc0ef8a 2066 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
a56a1ba4 2067 time_begin = ltt_time_sub(trace_end,width);
2068 else
224446ce 2069 time_begin = ltt_time_sub(current_time,half_width);
a56a1ba4 2070
224446ce 2071 new_time_window.start_time = time_begin;
2072 new_time_window.time_width = width;
a18124ff 2073 new_time_window.time_width_double = ltt_time_to_double(width);
6f26fc38 2074 new_time_window.end_time = ltt_time_add(time_begin, width);
a56a1ba4 2075
e800cf84 2076 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
a56a1ba4 2077
2078 }
7abb23ad 2079 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2080
a56a1ba4 2081
2082 return 0;
f7afe191 2083}
2084
8b90e648 2085typedef struct _ClosureData {
ca0f8a8e 2086 EventsRequest *events_request;
d0cd7f09 2087 LttvTracesetState *tss;
b9a010a2 2088 LttTime end_time;
bc8d270b 2089 guint x_end;
8b90e648 2090} ClosureData;
a56a1ba4 2091
8b90e648 2092
e800cf84 2093void draw_closure(gpointer key, gpointer value, gpointer user_data)
2094{
a56a1ba4 2095 ProcessInfo *process_info = (ProcessInfo*)key;
2096 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
2097 ClosureData *closure_data = (ClosureData*)user_data;
2098
e800cf84 2099 EventsRequest *events_request = closure_data->events_request;
2100 ControlFlowData *control_flow_data = events_request->viewer_data;
a56a1ba4 2101
e800cf84 2102 LttvTracesetState *tss = closure_data->tss;
d6fef890 2103 LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
a56a1ba4 2104
e800cf84 2105 LttTime evtime = closure_data->end_time;
d0cd7f09 2106
e800cf84 2107 {
2108 /* For the process */
2109 /* First, check if the current process is in the state computation
2110 * process list. If it is there, that means we must add it right now and
2111 * draw items from the beginning of the read for it. If it is not
2112 * present, it's a new process and it was not present : it will
2113 * be added after the state update. */
31b6868d 2114#ifdef EXTRA_CHECK
e800cf84 2115 g_assert(lttv_traceset_number(tsc->ts) > 0);
31b6868d 2116#endif //EXTRA_CHECK
2c82c4dc 2117 LttvTraceContext *tc = tsc->traces[process_info->trace_num];
348c6ba8 2118 LttvTraceState *ts = (LttvTraceState*)tc;
2c82c4dc 2119
348c6ba8 2120#if 0
2c82c4dc 2121 //FIXME : optimize data structures.
2122 LttvTracefileState *tfs;
2123 LttvTracefileContext *tfc;
2124 guint i;
2125 for(i=0;i<tc->tracefiles->len;i++) {
2126 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
2127 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
2128 && ltt_tracefile_num(tfc->tf) == process_info->cpu)
2129 break;
2130
2131 }
2132 g_assert(i<tc->tracefiles->len);
2133 tfs = LTTV_TRACEFILE_STATE(tfc);
348c6ba8 2134#endif //0
2c82c4dc 2135 // LttvTracefileState *tfs =
2136 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2137 // tracefiles[process_info->cpu];
2da61677 2138
e800cf84 2139 LttvProcessState *process;
348c6ba8 2140 process = lttv_state_find_process(ts, process_info->cpu,
e025a729 2141 process_info->pid);
a56a1ba4 2142
1d1df11d 2143 if(unlikely(process != NULL)) {
e800cf84 2144
2145 /* Only draw for processes that are currently in the trace states */
ad2e83ba 2146
5c230fc4 2147 ProcessList *process_list = control_flow_data->process_list;
1d1df11d 2148#ifdef EXTRA_CHECK
e800cf84 2149 /* Should be alike when background info is ready */
2150 if(control_flow_data->background_info_waiting==0)
2151 g_assert(ltt_time_compare(process->creation_time,
2152 process_info->birth) == 0);
1d1df11d 2153#endif //EXTRA_CHECK
e800cf84 2154
2155 /* Now, the process is in the state hash and our own process hash.
2156 * We definitely can draw the items related to the ending state.
2157 */
2158
1d1df11d 2159 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
2160 evtime) <= 0))
e800cf84 2161 {
fd22065b 2162 TimeWindow time_window =
2163 lttvwindow_get_time_window(control_flow_data->tab);
2164
2165#ifdef EXTRA_CHECK
2166 if(ltt_time_compare(evtime, time_window.start_time) == -1
2167 || ltt_time_compare(evtime, time_window.end_time) == 1)
2168 return;
2169#endif //EXTRA_CHECK
d6fef890 2170 Drawing_t *drawing = control_flow_data->drawing;
96947fcf 2171 guint width = drawing->width;
a56a1ba4 2172
bc8d270b 2173 guint x = closure_data->x_end;
8b90e648 2174
4b7dc462 2175 DrawContext draw_context;
2176
e800cf84 2177 /* Now create the drawing context that will be used to draw
2178 * items related to the last state. */
1c736ed5 2179 draw_context.drawable = hashed_process_data->pixmap;
e800cf84 2180 draw_context.gc = drawing->gc;
2181 draw_context.pango_layout = drawing->pango_layout;
e800cf84 2182 draw_context.drawinfo.end.x = x;
2183
1c736ed5 2184 draw_context.drawinfo.y.over = 1;
2185 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
2186 draw_context.drawinfo.y.under = hashed_process_data->height;
e800cf84 2187
2188 draw_context.drawinfo.start.offset.over = 0;
2189 draw_context.drawinfo.start.offset.middle = 0;
2190 draw_context.drawinfo.start.offset.under = 0;
2191 draw_context.drawinfo.end.offset.over = 0;
2192 draw_context.drawinfo.end.offset.middle = 0;
2193 draw_context.drawinfo.end.offset.under = 0;
9a1ec01b 2194#if 0
4b7dc462 2195 /* Jump over draw if we are at the same x position */
2196 if(x == hashed_process_data->x.over)
e800cf84 2197 {
4b7dc462 2198 /* jump */
2199 } else {
23093869 2200 draw_context.drawinfo.start.x = hashed_process_data->x.over;
2201 /* Draw the line */
2202 PropertiesLine prop_line = prepare_execmode_line(process);
2203 draw_line((void*)&prop_line, (void*)&draw_context);
2204
4b7dc462 2205 hashed_process_data->x.over = x;
23093869 2206 }
9a1ec01b 2207#endif //0
4b7dc462 2208
1d1df11d 2209 if(unlikely(x == hashed_process_data->x.middle &&
2210 hashed_process_data->x.middle_used)) {
b2743953 2211#if 0 /* do not mark closure : not missing information */
e72908ed 2212 if(hashed_process_data->x.middle_marked == FALSE) {
2213 /* Draw collision indicator */
2214 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
2215 gdk_draw_point(drawing->pixmap,
2216 drawing->gc,
2217 x,
2c6618bc 2218 y+(height/2)-3);
de4ea1ad 2219 hashed_process_data->x.middle_marked = TRUE;
e72908ed 2220 }
b2743953 2221#endif //0
4b7dc462 2222 /* Jump */
2223 } else {
23093869 2224 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
e800cf84 2225 /* Draw the line */
9a1ec01b 2226 PropertiesLine prop_line = prepare_s_e_line(process);
e800cf84 2227 draw_line((void*)&prop_line, (void*)&draw_context);
2228
4b7dc462 2229 /* become the last x position */
1d1df11d 2230 if(likely(x != hashed_process_data->x.middle)) {
e72908ed 2231 hashed_process_data->x.middle = x;
2232 /* but don't use the pixel */
2233 hashed_process_data->x.middle_used = FALSE;
b2743953 2234
2235 /* Calculate the next good time */
2236 convert_pixels_to_time(width, x+1, time_window,
2237 &hashed_process_data->next_good_time);
e72908ed 2238 }
e800cf84 2239 }
e800cf84 2240 }
2241 }
2242 }
2243 return;
8b90e648 2244}
2245
b9a010a2 2246int before_chunk(void *hook_data, void *call_data)
2247{
2248 EventsRequest *events_request = (EventsRequest*)hook_data;
16b9cadb 2249 LttvTracesetState *tss = (LttvTracesetState*)call_data;
7c0125e0 2250 ControlFlowData *cfd = (ControlFlowData*)events_request->viewer_data;
cd3892fe 2251#if 0
7c0125e0 2252 /* Desactivate sort */
2253 gtk_tree_sortable_set_sort_column_id(
2254 GTK_TREE_SORTABLE(cfd->process_list->list_store),
2255 TRACE_COLUMN,
2256 GTK_SORT_ASCENDING);
cd3892fe 2257#endif //0
b9a010a2 2258 drawing_chunk_begin(events_request, tss);
2259
2260 return 0;
2261}
2262
2263int before_request(void *hook_data, void *call_data)
ca0f8a8e 2264{
2265 EventsRequest *events_request = (EventsRequest*)hook_data;
16b9cadb 2266 LttvTracesetState *tss = (LttvTracesetState*)call_data;
7c0125e0 2267
ca0f8a8e 2268 drawing_data_request_begin(events_request, tss);
2269
2270 return 0;
2271}
2272
2273
8b90e648 2274/*
b9a010a2 2275 * after request is necessary in addition of after chunk in order to draw
2276 * lines until the end of the screen. after chunk just draws lines until
2277 * the last event.
2278 *
8b90e648 2279 * for each process
a56a1ba4 2280 * draw closing line
b9a010a2 2281 * expose
8b90e648 2282 */
b9a010a2 2283int after_request(void *hook_data, void *call_data)
8b90e648 2284{
ca0f8a8e 2285 EventsRequest *events_request = (EventsRequest*)hook_data;
2286 ControlFlowData *control_flow_data = events_request->viewer_data;
16b9cadb 2287 LttvTracesetState *tss = (LttvTracesetState*)call_data;
a56a1ba4 2288
5c230fc4 2289 ProcessList *process_list = control_flow_data->process_list;
b9a010a2 2290 LttTime end_time = events_request->end_time;
2291
2292 ClosureData closure_data;
2293 closure_data.events_request = (EventsRequest*)hook_data;
2294 closure_data.tss = tss;
2295 closure_data.end_time = end_time;
2296
bc8d270b 2297 TimeWindow time_window =
2298 lttvwindow_get_time_window(control_flow_data->tab);
2299 guint width = control_flow_data->drawing->width;
2300 convert_time_to_pixels(
2301 time_window,
2302 end_time,
2303 width,
2304 &closure_data.x_end);
2305
2306
b9a010a2 2307 /* Draw last items */
2308 g_hash_table_foreach(process_list->process_hash, draw_closure,
2309 (void*)&closure_data);
7c0125e0 2310
b9a010a2 2311
2312 /* Request expose */
2313 drawing_request_expose(events_request, tss, end_time);
2314 return 0;
2315}
2316
2317/*
2318 * for each process
2319 * draw closing line
e800cf84 2320 * expose
b9a010a2 2321 */
2322int after_chunk(void *hook_data, void *call_data)
2323{
2324 EventsRequest *events_request = (EventsRequest*)hook_data;
2325 ControlFlowData *control_flow_data = events_request->viewer_data;
16b9cadb 2326 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2327 LttvTracesetContext *tsc = (LttvTracesetContext*)call_data;
b9a010a2 2328 LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc);
2329 LttTime end_time;
2330
5c230fc4 2331 ProcessList *process_list = control_flow_data->process_list;
b9a010a2 2332
40debf7b 2333 g_free(process_list->current_hash_data);
2334 process_list->current_hash_data = NULL;
2335
e800cf84 2336 if(tfc != NULL)
2337 end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time);
0c5dbe3b 2338 else /* end of traceset, or position now out of request : end */
2339 end_time = events_request->end_time;
2340
a56a1ba4 2341 ClosureData closure_data;
ca0f8a8e 2342 closure_data.events_request = (EventsRequest*)hook_data;
2343 closure_data.tss = tss;
b9a010a2 2344 closure_data.end_time = end_time;
a56a1ba4 2345
bc8d270b 2346 TimeWindow time_window =
2347 lttvwindow_get_time_window(control_flow_data->tab);
2348 guint width = control_flow_data->drawing->width;
2349 convert_time_to_pixels(
2350 time_window,
2351 end_time,
2352 width,
2353 &closure_data.x_end);
2354
b9a010a2 2355 /* Draw last items */
14963be0 2356 g_hash_table_foreach(process_list->process_hash, draw_closure,
a56a1ba4 2357 (void*)&closure_data);
cd3892fe 2358#if 0
7c0125e0 2359 /* Reactivate sort */
2360 gtk_tree_sortable_set_sort_column_id(
2361 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2362 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2363 GTK_SORT_ASCENDING);
2364
2365 update_index_to_pixmap(control_flow_data->process_list);
cd3892fe 2366 /* Request a full expose : drawing scrambled */
2367 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2368#endif //0
2369 /* Request expose (updates damages zone also) */
b9a010a2 2370 drawing_request_expose(events_request, tss, end_time);
ca0f8a8e 2371
2372 return 0;
8b90e648 2373}
2374
This page took 0.181674 seconds and 4 git commands to generate.