cf3881b091f3bb0c417d22e17acef5e61bf9d3c6
[lttv.git] / lttv / modules / gui / controlflow / drawing.c
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 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <gtk/gtk.h>
24 #include <gdk/gdk.h>
25 #include <string.h>
26
27 #include <lttv/lttv.h>
28 #include <lttvwindow/lttvwindow.h>
29 #include <lttv/state.h>
30 #include <lttv/hook.h>
31
32 #include "drawing.h"
33 #include "eventhooks.h"
34 #include "cfv.h"
35
36 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
37
38 //FIXME
39 // fixed #define TRACE_NUMBER 0
40 #define EXTRA_ALLOC 1024 // pixels
41
42
43 #if 0 /* colors for two lines representation */
44 GdkColor drawing_colors[NUM_COLORS] =
45 { /* Pixel, R, G, B */
46 { 0, 0, 0, 0 }, /* COL_BLACK */
47 { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_WHITE */
48 { 0, 0x0FFF, 0xFFFF, 0xFFFF }, /* COL_WAIT_FORK : pale blue */
49 { 0, 0xFFFF, 0xFFFF, 0x0000 }, /* COL_WAIT_CPU : yellow */
50 { 0, 0xFFFF, 0xA000, 0xFCFF }, /* COL_EXIT : pale magenta */
51 { 0, 0xFFFF, 0x0000, 0xFFFF }, /* COL_ZOMBIE : purple */
52 { 0, 0xFFFF, 0x0000, 0x0000 }, /* COL_WAIT : red */
53 { 0, 0x0000, 0xFFFF, 0x0000 }, /* COL_RUN : green */
54 { 0, 0x8800, 0xFFFF, 0x8A00 }, /* COL_USER_MODE : pale green */
55 { 0, 0x09FF, 0x01FF, 0xFFFF }, /* COL_SYSCALL : blue */
56 { 0, 0xF900, 0x4200, 0xFF00 }, /* COL_TRAP : pale purple */
57 { 0, 0xFFFF, 0x5AFF, 0x01FF }, /* COL_IRQ : orange */
58 { 0, 0xFFFF, 0xFFFF, 0xFFFF } /* COL_MODE_UNKNOWN : white */
59
60 };
61 #endif //0
62
63
64 GdkColor drawing_colors[NUM_COLORS] =
65 { /* Pixel, R, G, B */
66 { 0, 0, 0, 0 }, /* COL_BLACK */
67 { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_WHITE */
68 { 0, 0x0000, 0xFF00, 0x0000 }, /* COL_RUN_USER_MODE : green */
69 { 0, 0x0100, 0x9E00, 0xFFFF }, /* COL_RUN_SYSCALL : pale blue */
70 { 0, 0xFF00, 0xFF00, 0x0100 }, /* COL_RUN_TRAP : yellow */
71 { 0, 0xFFFF, 0x5E00, 0x0000 }, /* COL_RUN_IRQ : orange */
72 { 0, 0xFFFF, 0x9400, 0x9600 }, /* COL_RUN_SOFT_IRQ : pink */
73 { 0, 0x6600, 0x0000, 0x0000 }, /* COL_WAIT : dark red */
74 { 0, 0x7700, 0x7700, 0x0000 }, /* COL_WAIT_CPU : dark yellow */
75 { 0, 0x6400, 0x0000, 0x5D00 }, /* COL_ZOMBIE : dark purple */
76 { 0, 0x0700, 0x6400, 0x0000 }, /* COL_WAIT_FORK : dark green */
77 { 0, 0x8900, 0x0000, 0x8400 }, /* COL_EXIT : "less dark" magenta */
78 { 0, 0x0000, 0x0000, 0x0000 }, /* COL_DEAD : black */
79 { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_MODE_UNKNOWN : white */
80 { 0, 0xFFFF, 0xFFFF, 0xFFFF } /* COL_UNNAMED : white */
81
82 };
83
84 /*
85 RUN+USER MODE green
86 RUN+SYSCALL
87 RUN+TRAP
88 RUN+IRQ
89 WAIT+foncé
90 WAIT CPU + WAIT FORK vert foncé ou jaune
91 IRQ rouge
92 TRAP: orange
93 SYSCALL: bleu pâle
94
95 ZOMBIE + WAIT EXIT
96 */
97
98
99 /*****************************************************************************
100 * drawing functions *
101 *****************************************************************************/
102
103 static gboolean
104 expose_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data );
105
106 static gboolean
107 motion_notify_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
108
109
110 /* Function responsible for updating the exposed area.
111 * It must do an events request to the lttvwindow API to ask for this update.
112 * Note : this function cannot clear the background, because it may
113 * erase drawing already present (SAFETY).
114 */
115 void drawing_data_request(Drawing_t *drawing,
116 gint x, gint y,
117 gint width,
118 gint height)
119 {
120 if(width < 0) return ;
121 if(height < 0) return ;
122
123
124 Tab *tab = drawing->control_flow_data->tab;
125 TimeWindow time_window = lttvwindow_get_time_window(tab);
126 LttvTraceset *traceset = lttvwindow_get_traceset(tab);
127 if(lttv_traceset_number(traceset) <= 0){
128 return;
129 }
130
131 ControlFlowData *control_flow_data = drawing->control_flow_data;
132 // (ControlFlowData*)g_object_get_data(
133 // G_OBJECT(drawing->drawing_area), "control_flow_data");
134
135 LttTime start, time_end;
136 LttTime window_end = time_window.end_time;
137
138 g_debug("req : window start_time : %lu, %lu", time_window.start_time.tv_sec,
139 time_window.start_time.tv_nsec);
140
141 g_debug("req : window time width : %lu, %lu", time_window.time_width.tv_sec,
142 time_window.time_width.tv_nsec);
143
144 g_debug("req : window_end : %lu, %lu", window_end.tv_sec,
145 window_end.tv_nsec);
146
147 g_debug("x is : %i, x+width is : %i", x, x+width);
148
149 convert_pixels_to_time(drawing->width, x,
150 time_window,
151 &start);
152
153 convert_pixels_to_time(drawing->width, x+width,
154 time_window,
155 &time_end);
156 time_end = ltt_time_add(time_end, ltt_time_one); // because main window
157 // doesn't deliver end time.
158
159 lttvwindow_events_request_remove_all(tab,
160 control_flow_data);
161
162 {
163 LttvHooks *event_hook = lttv_hooks_new();
164 g_assert(event_hook);
165
166 lttv_hooks_add(event_hook,before_execmode_hook , control_flow_data, LTTV_PRIO_STATE-5);
167 #ifdef BABEL_CLEANUP
168 lttv_hooks_add(event_hook,syscall_exit , control_flow_data, LTTV_PRIO_STATE);
169 lttv_hooks_add(event_hook,irq_entry , control_flow_data, LTTV_PRIO_STATE);
170 lttv_hooks_add(event_hook,irq_exit , control_flow_data, LTTV_PRIO_STATE);
171 lttv_hooks_add(event_hook,soft_irq_raise , control_flow_data, LTTV_PRIO_STATE);
172 lttv_hooks_add(event_hook,soft_irq_entry , control_flow_data, LTTV_PRIO_STATE);
173 lttv_hooks_add(event_hook,soft_irq_exit , control_flow_data, LTTV_PRIO_STATE);
174 #endif //babel_cleanup
175 lttv_hooks_add(event_hook,before_schedchange_hook , control_flow_data, LTTV_PRIO_STATE-5);
176 #ifdef BABEL_CLEANUP
177 lttv_hooks_add(event_hook,sched_try_wakeup , control_flow_data, LTTV_PRIO_STATE);
178 lttv_hooks_add(event_hook,process_exit , control_flow_data, LTTV_PRIO_STATE);
179 lttv_hooks_add(event_hook,process_free , control_flow_data, LTTV_PRIO_STATE);
180 lttv_hooks_add(event_hook,process_exec , control_flow_data, LTTV_PRIO_STATE);
181 lttv_hooks_add(event_hook,enum_process_state , control_flow_data, LTTV_PRIO_STATE);
182 lttv_hooks_add(event_hook,statedump_end , control_flow_data, LTTV_PRIO_STATE);
183 lttv_hooks_add(event_hook,enum_interrupt , control_flow_data, LTTV_PRIO_STATE);
184 #endif //babel_cleanup
185 lttv_hooks_add(event_hook, before_trywakeup_hook, control_flow_data, LTTV_PRIO_STATE-5);
186 lttv_hooks_add(event_hook, before_process_exit_hook, control_flow_data, LTTV_PRIO_STATE-5);
187 lttv_hooks_add(event_hook, before_process_release_hook, control_flow_data, LTTV_PRIO_STATE-5);
188 lttv_hooks_add(event_hook, before_statedump_end, control_flow_data, LTTV_PRIO_STATE-5);
189
190 lttv_hooks_add(event_hook, after_schedchange_hook, control_flow_data, LTTV_PRIO_STATE+5);
191 lttv_hooks_add(event_hook, after_process_fork_hook, control_flow_data, LTTV_PRIO_STATE+5);
192 lttv_hooks_add(event_hook, after_process_exit_hook, control_flow_data, LTTV_PRIO_STATE+5);
193 lttv_hooks_add(event_hook, after_event_enum_process_hook, control_flow_data, LTTV_PRIO_STATE+5);
194
195 guint i, nb_trace;
196
197 nb_trace = lttv_traceset_number(traceset);
198 // FIXME (fixed) : eventually request for more traces
199 for(i = 0 ; i < nb_trace ; i++) {
200 EventsRequest *events_request = g_new(EventsRequest, 1);
201 // Create the hooks
202 //LttvHooks *event = lttv_hooks_new();
203
204 LttvHooks *before_chunk_traceset = lttv_hooks_new();
205 LttvHooks *after_chunk_traceset = lttv_hooks_new();
206 LttvHooks *before_request_hook = lttv_hooks_new();
207 LttvHooks *after_request_hook = lttv_hooks_new();
208
209 lttv_hooks_add(before_chunk_traceset,
210 before_chunk,
211 events_request,
212 LTTV_PRIO_DEFAULT);
213
214 lttv_hooks_add(after_chunk_traceset,
215 after_chunk,
216 events_request,
217 LTTV_PRIO_DEFAULT);
218
219 lttv_hooks_add(before_request_hook,
220 before_request,
221 events_request,
222 LTTV_PRIO_DEFAULT);
223
224 lttv_hooks_add(after_request_hook,
225 after_request,
226 events_request,
227 LTTV_PRIO_DEFAULT);
228
229
230 // Fill the events request
231 events_request->owner = control_flow_data;
232 events_request->viewer_data = control_flow_data;
233 events_request->servicing = FALSE;
234 events_request->start_time = start;
235 events_request->start_position = NULL;
236 events_request->stop_flag = FALSE;
237 events_request->end_time = time_end;
238 events_request->num_events = G_MAXUINT;
239 events_request->end_position = NULL;
240 events_request->trace = i; //fixed /* FIXME */
241 events_request->before_chunk_traceset = before_chunk_traceset;
242 events_request->before_chunk_trace = NULL;
243 events_request->before_chunk_tracefile = NULL;
244 events_request->event = event_hook;
245 events_request->after_chunk_tracefile = NULL;
246 events_request->after_chunk_trace = NULL;
247 events_request->after_chunk_traceset = after_chunk_traceset;
248 events_request->before_request = before_request_hook;
249 events_request->after_request = after_request_hook;
250
251 g_debug("req : start : %lu, %lu", start.tv_sec,
252 start.tv_nsec);
253
254 g_debug("req : end : %lu, %lu", time_end.tv_sec,
255 time_end.tv_nsec);
256
257 lttvwindow_events_request(tab, events_request);
258 }
259
260
261 }
262 }
263
264
265 static void set_last_start(gpointer key, gpointer value, gpointer user_data)
266 {
267 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
268 guint x = GPOINTER_TO_UINT(user_data);
269
270 hashed_process_data->x.over = x;
271 hashed_process_data->x.over_used = FALSE;
272 hashed_process_data->x.over_marked = FALSE;
273 hashed_process_data->x.middle = x;
274 hashed_process_data->x.middle_used = FALSE;
275 hashed_process_data->x.middle_marked = FALSE;
276 hashed_process_data->x.under = x;
277 hashed_process_data->x.under_used = FALSE;
278 hashed_process_data->x.under_marked = FALSE;
279 hashed_process_data->next_good_time = ltt_time_zero;
280
281 return;
282 }
283 void drawing_data_request_begin(EventsRequest *events_request)
284 {
285 g_debug("Begin of data request");
286 ControlFlowData *cfd = events_request->viewer_data;
287 TimeWindow time_window =
288 lttvwindow_get_time_window(cfd->tab);
289
290 guint width = cfd->drawing->width;
291 guint x=0;
292
293 cfd->drawing->last_start = events_request->start_time;
294
295 convert_time_to_pixels(
296 time_window,
297 events_request->start_time,
298 width,
299 &x);
300
301 g_hash_table_foreach(cfd->process_list->process_hash, set_last_start,
302 GUINT_TO_POINTER(x));
303
304 }
305 void drawing_chunk_begin(EventsRequest *events_request, LttvTraceset *ts)
306 {
307 g_debug("Begin of chunk");
308 ControlFlowData *cfd = events_request->viewer_data;
309 //LttTime current_time = lttv_traceset_context_get_current_tfc(tsc)->timestamp;
310 guint i;
311 guint nb_trace = lttv_traceset_number(ts);
312
313 if(!cfd->process_list->current_hash_data) {
314 cfd->process_list->current_hash_data = g_new(HashedProcessData**,nb_trace);
315 for(i = 0 ; i < nb_trace ; i++) {
316 guint num_cpu = lttv_trace_get_num_cpu( lttv_traceset_get(ts, i));
317 cfd->process_list->current_hash_data[i] = g_new(HashedProcessData*,num_cpu);
318 memset(cfd->process_list->current_hash_data[i], 0,
319 sizeof(HashedProcessData*)*num_cpu);
320 }
321 }
322 //cfd->drawing->last_start = LTT_TIME_MIN(current_time,
323 // events_request->end_time);
324 }
325
326
327 void drawing_request_expose(EventsRequest *events_request,
328 LttTime end_time)
329 {
330 gint x, width;
331 guint x_end;
332
333 ControlFlowData *cfd = events_request->viewer_data;
334 Drawing_t *drawing = cfd->drawing;
335
336 TimeWindow time_window = lttvwindow_get_time_window(cfd->tab);
337
338 g_debug("request expose");
339
340 convert_time_to_pixels(
341 time_window,
342 end_time,
343 drawing->width,
344 &x_end);
345 x = drawing->damage_begin;
346
347 width = x_end - x;
348
349 drawing->damage_begin = x+width;
350
351 // FIXME ?
352 gtk_widget_queue_draw_area ( drawing->drawing_area,
353 x, 0,
354 width, drawing->drawing_area->allocation.height);
355
356 /* Update directly when scrolling */
357 gdk_window_process_updates(drawing->drawing_area->window,
358 TRUE);
359 }
360
361 /* Callbacks */
362
363
364 /* Create a new backing pixmap of the appropriate size */
365 /* As the scaling will always change, it's of no use to copy old
366 * pixmap.
367 *
368 * Only change the size if width changes. The height is specified and changed
369 * when process ID are added or removed from the process list.
370 */
371 static gboolean
372 configure_event( GtkWidget *widget, GdkEventConfigure *event,
373 gpointer user_data)
374 {
375 Drawing_t *drawing = (Drawing_t*)user_data;
376
377
378 /* First, get the new time interval of the main window */
379 /* we assume (see documentation) that the main window
380 * has updated the time interval before this configure gets
381 * executed.
382 */
383 //lttvwindow_get_time_window(drawing->control_flow_data->mw,
384 // &drawing->control_flow_data->time_window);
385
386 /* New pixmap, size of the configure event */
387 //GdkPixmap *pixmap = gdk_pixmap_new(widget->window,
388 // widget->allocation.width + SAFETY,
389 // widget->allocation.height + SAFETY,
390 // -1);
391
392 if(widget->allocation.width != drawing->width) {
393 g_debug("drawing configure event");
394 g_debug("New alloc draw size : %i by %i",widget->allocation.width,
395 widget->allocation.height);
396
397 drawing->width = widget->allocation.width;
398
399 if(drawing->alloc_width < widget->allocation.width) {
400 //if(drawing->pixmap)
401 // gdk_pixmap_unref(drawing->pixmap);
402
403 //drawing->pixmap = gdk_pixmap_new(widget->window,
404 // drawing->width + SAFETY + EXTRA_ALLOC,
405 // drawing->height + EXTRA_ALLOC,
406 // -1);
407 drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC;
408 drawing->alloc_height = drawing->height + EXTRA_ALLOC;
409 update_pixmap_size(drawing->control_flow_data->process_list,
410 drawing->alloc_width);
411 update_index_to_pixmap(drawing->control_flow_data->process_list);
412 }
413 drawing->height = widget->allocation.height;
414
415 //ProcessList_get_height
416 // (GuiControlFlow_get_process_list(drawing->control_flow_data)),
417
418
419 // Clear the image
420 //gdk_draw_rectangle (drawing->pixmap,
421 // widget->style->black_gc,
422 // TRUE,
423 // 0, 0,
424 // drawing->width+SAFETY,
425 // drawing->height);
426
427 //g_info("init data request");
428
429
430 /* Initial data request */
431 /* no, do initial data request in the expose event */
432 // Do not need to ask for data of 1 pixel : not synchronized with
433 // main window time at this moment.
434 //drawing_data_request(drawing, &drawing->pixmap, 0, 0,
435 // widget->allocation.width,
436 // widget->allocation.height);
437
438 //drawing->width = widget->allocation.width;
439 //drawing->height = widget->allocation.height;
440
441 drawing->damage_begin = 0;
442 drawing->damage_end = widget->allocation.width;
443
444 if((widget->allocation.width != 1 &&
445 widget->allocation.height != 1)
446 && drawing->damage_begin < drawing->damage_end)
447 {
448
449 rectangle_pixmap (drawing->control_flow_data->process_list,
450 drawing->drawing_area->style->black_gc,
451 TRUE,
452 0, 0,
453 drawing->alloc_width, // do not overlap
454 -1);
455
456
457 drawing_data_request(drawing,
458 drawing->damage_begin,
459 0,
460 drawing->damage_end - drawing->damage_begin,
461 drawing->height);
462 }
463 }
464 return TRUE;
465 }
466
467
468 /* Redraw the screen from the backing pixmap */
469 static gboolean
470 expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data )
471 {
472 Drawing_t *drawing = (Drawing_t*)user_data;
473
474 ControlFlowData *control_flow_data =
475 (ControlFlowData*)g_object_get_data(
476 G_OBJECT(widget),
477 "control_flow_data");
478 #if 0
479 if(unlikely(drawing->gc == NULL)) {
480 drawing->gc = gdk_gc_new(drawing->drawing_area->window);
481 gdk_gc_copy(drawing->gc, drawing->drawing_area->style->black_gc);
482 }
483 #endif //0
484 TimeWindow time_window =
485 lttvwindow_get_time_window(control_flow_data->tab);
486 LttTime current_time =
487 lttvwindow_get_current_time(control_flow_data->tab);
488
489 guint cursor_x=0;
490
491 LttTime window_end = time_window.end_time;
492
493 /* update the screen from the pixmap buffer */
494 #if 0
495 gdk_draw_pixmap(widget->window,
496 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
497 drawing->pixmap,
498 event->area.x, event->area.y,
499 event->area.x, event->area.y,
500 event->area.width, event->area.height);
501 #endif //0
502 drawing->height = processlist_get_height(control_flow_data->process_list);
503 #if 0
504 copy_pixmap_to_screen(control_flow_data->process_list,
505 widget->window,
506 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
507 event->area.x, event->area.y,
508 event->area.width, event->area.height);
509 #endif //0
510 copy_pixmap_to_screen(control_flow_data->process_list,
511 widget->window,
512 drawing->gc,
513 event->area.x, event->area.y,
514 event->area.width, event->area.height);
515
516
517 /* Erase the dotted lines left.. */
518 if(widget->allocation.height > drawing->height)
519 {
520 gdk_draw_rectangle (widget->window,
521 drawing->drawing_area->style->black_gc,
522 TRUE,
523 event->area.x, drawing->height,
524 event->area.width, // do not overlap
525 widget->allocation.height - drawing->height);
526 }
527 if(ltt_time_compare(time_window.start_time, current_time) <= 0 &&
528 ltt_time_compare(window_end, current_time) >= 0)
529 {
530 /* Draw the dotted lines */
531 convert_time_to_pixels(
532 time_window,
533 current_time,
534 drawing->width,
535 &cursor_x);
536
537 #if 0
538 if(drawing->dotted_gc == NULL) {
539
540 drawing->dotted_gc = gdk_gc_new(drawing->drawing_area->window);
541 gdk_gc_copy(drawing->dotted_gc, widget->style->white_gc);
542
543 gint8 dash_list[] = { 1, 2 };
544 gdk_gc_set_line_attributes(drawing->dotted_gc,
545 1,
546 GDK_LINE_ON_OFF_DASH,
547 GDK_CAP_BUTT,
548 GDK_JOIN_MITER);
549 gdk_gc_set_dashes(drawing->dotted_gc,
550 0,
551 dash_list,
552 2);
553 }
554 #endif //0
555 gint height_tot = MAX(widget->allocation.height, drawing->height);
556 gdk_draw_line(widget->window,
557 drawing->dotted_gc,
558 cursor_x, 0,
559 cursor_x, height_tot);
560 }
561 return FALSE;
562 }
563
564 static gboolean
565 after_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer user_data )
566 {
567 //g_assert(0);
568 g_debug("AFTER EXPOSE");
569
570 return FALSE;
571
572
573 }
574
575 #if 0
576 void
577 tree_row_activated(GtkTreeModel *treemodel,
578 GtkTreePath *arg1,
579 GtkTreeViewColumn *arg2,
580 gpointer user_data)
581 {
582 ControlFlowData *cfd = (ControlFlowData*)user_data;
583 Drawing_t *drawing = cfd->drawing;
584 GtkTreeView *treeview = cfd->process_list->process_list_widget;
585 gint *path_indices;
586 gint height;
587
588 path_indices = gtk_tree_path_get_indices (arg1);
589
590 height = get_cell_height(cfd->process_list,
591 GTK_TREE_VIEW(treeview));
592 drawing->horizontal_sel = height * path_indices[0];
593 g_critical("new hor sel : %i", drawing->horizontal_sel);
594 }
595 #endif //0
596
597 /* mouse click */
598 static gboolean
599 button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
600 {
601 ControlFlowData *control_flow_data =
602 (ControlFlowData*)g_object_get_data(
603 G_OBJECT(widget),
604 "control_flow_data");
605 Drawing_t *drawing = control_flow_data->drawing;
606 TimeWindow time_window =
607 lttvwindow_get_time_window(control_flow_data->tab);
608
609 g_debug("click");
610 if(event->button == 1)
611 {
612 LttTime time;
613
614 /* left mouse button click */
615 g_debug("x click is : %f", event->x);
616
617 convert_pixels_to_time(drawing->width, (guint)event->x,
618 time_window,
619 &time);
620
621 lttvwindow_report_current_time(control_flow_data->tab, time);
622
623 }
624
625 return FALSE;
626 }
627
628 static gboolean
629 scrollbar_size_allocate(GtkWidget *widget,
630 GtkAllocation *allocation,
631 gpointer user_data)
632 {
633 Drawing_t *drawing = (Drawing_t*)user_data;
634
635 gtk_widget_set_size_request(drawing->padding, allocation->width, -1);
636 //gtk_widget_queue_resize(drawing->padding);
637 //gtk_widget_queue_resize(drawing->ruler);
638 gtk_container_check_resize(GTK_CONTAINER(drawing->ruler_hbox));
639 return 0;
640 }
641
642
643
644 Drawing_t *drawing_construct(ControlFlowData *control_flow_data)
645 {
646 Drawing_t *drawing = g_new(Drawing_t, 1);
647
648 drawing->control_flow_data = control_flow_data;
649
650 drawing->vbox = gtk_vbox_new(FALSE, 1);
651
652
653 drawing->ruler_hbox = gtk_hbox_new(FALSE, 1);
654 drawing->ruler = gtk_drawing_area_new ();
655 //gtk_widget_set_size_request(drawing->ruler, -1, 27);
656
657 drawing->padding = gtk_drawing_area_new ();
658 //gtk_widget_set_size_request(drawing->padding, -1, 27);
659 gtk_box_pack_start(GTK_BOX(drawing->ruler_hbox), drawing->ruler,
660 TRUE, TRUE, 0);
661 gtk_box_pack_end(GTK_BOX(drawing->ruler_hbox), drawing->padding,
662 FALSE, FALSE, 0);
663
664
665
666 drawing->drawing_area = gtk_drawing_area_new ();
667
668 drawing->gc = NULL;
669
670 drawing->hbox = gtk_hbox_new(FALSE, 1);
671 drawing->viewport = gtk_viewport_new(NULL, control_flow_data->v_adjust);
672 drawing->scrollbar = gtk_vscrollbar_new(control_flow_data->v_adjust);
673 gtk_box_pack_start(GTK_BOX(drawing->hbox), drawing->viewport,
674 TRUE, TRUE, 0);
675 gtk_box_pack_end(GTK_BOX(drawing->hbox), drawing->scrollbar,
676 FALSE, FALSE, 0);
677
678 //drawing->scrolled_window =
679 // gtk_scrolled_window_new (NULL,
680 // control_flow_data->v_adjust);
681
682 //gtk_scrolled_window_set_policy(
683 // GTK_SCROLLED_WINDOW(drawing->scrolled_window),
684 // GTK_POLICY_NEVER,
685 // GTK_POLICY_AUTOMATIC);
686
687 gtk_container_add(GTK_CONTAINER(drawing->viewport),
688 drawing->drawing_area);
689 //gtk_scrolled_window_add_with_viewport(
690 // GTK_SCROLLED_WINDOW(drawing->scrolled_window),
691 // drawing->drawing_area);
692
693 gtk_box_pack_start(GTK_BOX(drawing->vbox), drawing->ruler_hbox,
694 FALSE, FALSE, 0);
695 gtk_box_pack_end(GTK_BOX(drawing->vbox), drawing->hbox,
696 TRUE, TRUE, 0);
697
698 drawing->pango_layout =
699 gtk_widget_create_pango_layout(drawing->drawing_area, NULL);
700
701 drawing->height = 1;
702 drawing->width = 1;
703 drawing->depth = 0;
704 drawing->alloc_height = 1;
705 drawing->alloc_width = 1;
706
707 drawing->damage_begin = 0;
708 drawing->damage_end = 0;
709 drawing->horizontal_sel = -1;
710
711 //gtk_widget_set_size_request(drawing->drawing_area->window, 50, 50);
712 g_object_set_data_full(
713 G_OBJECT(drawing->drawing_area),
714 "Link_drawing_Data",
715 drawing,
716 (GDestroyNotify)drawing_destroy);
717
718 g_object_set_data(
719 G_OBJECT(drawing->ruler),
720 "drawing",
721 drawing);
722
723
724 //gtk_widget_modify_bg( drawing->drawing_area,
725 // GTK_STATE_NORMAL,
726 // &CF_Colors[BLACK]);
727
728 //gdk_window_get_geometry(drawing->drawing_area->window,
729 // NULL, NULL,
730 // &(drawing->width),
731 // &(drawing->height),
732 // -1);
733
734 //drawing->pixmap = gdk_pixmap_new(
735 // drawing->drawing_area->window,
736 // drawing->width,
737 // drawing->height,
738 // drawing->depth);
739
740 //drawing->pixmap = NULL;
741
742 // drawing->pixmap = gdk_pixmap_new(drawing->drawing_area->window,
743 // drawing->drawing_area->allocation.width,
744 // drawing->drawing_area->allocation.height,
745 // -1);
746
747 g_signal_connect (G_OBJECT(drawing->drawing_area),
748 "configure_event",
749 G_CALLBACK (configure_event),
750 (gpointer)drawing);
751
752 g_signal_connect (G_OBJECT(drawing->ruler),
753 "expose_event",
754 G_CALLBACK(expose_ruler),
755 (gpointer)drawing);
756
757 gtk_widget_add_events(drawing->ruler, GDK_POINTER_MOTION_MASK);
758
759 g_signal_connect (G_OBJECT(drawing->ruler),
760 "motion-notify-event",
761 G_CALLBACK(motion_notify_ruler),
762 (gpointer)drawing);
763
764
765 g_signal_connect (G_OBJECT(drawing->scrollbar),
766 "size-allocate",
767 G_CALLBACK(scrollbar_size_allocate),
768 (gpointer)drawing);
769
770
771
772 g_signal_connect (G_OBJECT(drawing->drawing_area),
773 "expose_event",
774 G_CALLBACK (expose_event),
775 (gpointer)drawing);
776
777 g_signal_connect_after (G_OBJECT(drawing->drawing_area),
778 "expose_event",
779 G_CALLBACK (after_expose_event),
780 (gpointer)drawing);
781
782 g_signal_connect (G_OBJECT(drawing->drawing_area),
783 "button-press-event",
784 G_CALLBACK (button_press_event),
785 (gpointer)drawing);
786
787
788 gtk_widget_show(drawing->ruler);
789 gtk_widget_show(drawing->padding);
790 gtk_widget_show(drawing->ruler_hbox);
791
792 gtk_widget_show(drawing->drawing_area);
793 //gtk_widget_show(drawing->scrolled_window);
794 gtk_widget_show(drawing->viewport);
795 gtk_widget_show(drawing->scrollbar);
796 gtk_widget_show(drawing->hbox);
797
798 /* Allocate the colors */
799 GdkColormap* colormap = gdk_colormap_get_system();
800 gboolean success[NUM_COLORS];
801 gdk_colormap_alloc_colors(colormap, drawing_colors, NUM_COLORS, FALSE,
802 TRUE, success);
803
804 drawing->gc =
805 gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
806 drawing->dotted_gc =
807 gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
808
809 gdk_gc_copy(drawing->gc,
810 main_window_get_widget(control_flow_data->tab)->style->black_gc);
811 gdk_gc_copy(drawing->dotted_gc,
812 main_window_get_widget(control_flow_data->tab)->style->white_gc);
813
814 gint8 dash_list[] = { 1, 2 };
815 gdk_gc_set_line_attributes(drawing->dotted_gc,
816 1,
817 GDK_LINE_ON_OFF_DASH,
818 GDK_CAP_BUTT,
819 GDK_JOIN_MITER);
820 gdk_gc_set_dashes(drawing->dotted_gc,
821 0,
822 dash_list,
823 2);
824
825 drawing->ruler_gc_butt =
826 gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
827 gdk_gc_copy(drawing->ruler_gc_butt,
828 main_window_get_widget(control_flow_data->tab)->style->black_gc);
829 drawing->ruler_gc_round =
830 gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window));
831 gdk_gc_copy(drawing->ruler_gc_round,
832 main_window_get_widget(control_flow_data->tab)->style->black_gc);
833
834
835 gdk_gc_set_line_attributes(drawing->ruler_gc_butt,
836 2,
837 GDK_LINE_SOLID,
838 GDK_CAP_BUTT,
839 GDK_JOIN_MITER);
840
841 gdk_gc_set_line_attributes(drawing->ruler_gc_round,
842 2,
843 GDK_LINE_SOLID,
844 GDK_CAP_ROUND,
845 GDK_JOIN_ROUND);
846
847
848 return drawing;
849 }
850
851 void drawing_destroy(Drawing_t *drawing)
852 {
853 g_info("drawing_destroy %p", drawing);
854
855 /* Free the colors */
856 GdkColormap* colormap = gdk_colormap_get_system();
857
858 gdk_colormap_free_colors(colormap, drawing_colors, NUM_COLORS);
859
860
861
862 // Do not unref here, Drawing_t destroyed by it's widget.
863 //g_object_unref( G_OBJECT(drawing->drawing_area));
864 if(drawing->gc != NULL)
865 gdk_gc_unref(drawing->gc);
866
867 g_object_unref(drawing->pango_layout);
868 if(drawing->dotted_gc != NULL) gdk_gc_unref(drawing->dotted_gc);
869 if(drawing->ruler_gc_butt != NULL) gdk_gc_unref(drawing->ruler_gc_butt);
870 if(drawing->ruler_gc_round != NULL) gdk_gc_unref(drawing->ruler_gc_round);
871
872 g_free(drawing);
873 g_info("drawing_destroy end");
874 }
875
876 GtkWidget *drawing_get_drawing_area(Drawing_t *drawing)
877 {
878 return drawing->drawing_area;
879 }
880
881 GtkWidget *drawing_get_widget(Drawing_t *drawing)
882 {
883 return drawing->vbox;
884 }
885
886 void drawing_draw_line( Drawing_t *drawing,
887 GdkPixmap *pixmap,
888 guint x1, guint y1,
889 guint x2, guint y2,
890 GdkGC *GC)
891 {
892 gdk_draw_line (pixmap,
893 GC,
894 x1, y1, x2, y2);
895 }
896
897 void drawing_clear(Drawing_t *drawing)
898 {
899 //if (drawing->pixmap)
900 // gdk_pixmap_unref(drawing->pixmap);
901 ControlFlowData *cfd = drawing->control_flow_data;
902
903
904 rectangle_pixmap(cfd->process_list,
905 drawing->drawing_area->style->black_gc,
906 TRUE,
907 0, 0,
908 drawing->alloc_width, // do not overlap
909 -1);
910
911 //drawing->height = 1;
912 /* Allocate a new pixmap with new height */
913 //drawing->pixmap = gdk_pixmap_new(drawing->drawing_area->window,
914 // drawing->width + SAFETY + EXTRA_ALLOC,
915 // drawing->height + EXTRA_ALLOC,
916 // -1);
917 //drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC;
918 //drawing->alloc_height = drawing->height + EXTRA_ALLOC;
919
920 //gtk_widget_set_size_request(drawing->drawing_area,
921 // -1,
922 // drawing->height);
923 //gtk_widget_queue_resize_no_redraw(drawing->drawing_area);
924
925 /* ask for the buffer to be redrawn */
926 gtk_widget_queue_draw ( drawing->drawing_area);
927 }
928
929 #if 0
930 /* Insert a square corresponding to a new process in the list */
931 /* Applies to whole drawing->width */
932 void drawing_insert_square(Drawing_t *drawing,
933 guint y,
934 guint height)
935 {
936 //GdkRectangle update_rect;
937 gboolean reallocate = FALSE;
938 GdkPixmap *new_pixmap;
939
940 /* Allocate a new pixmap with new height */
941 if(drawing->alloc_height < drawing->height + height) {
942
943 new_pixmap = gdk_pixmap_new(drawing->drawing_area->window,
944 drawing->width + SAFETY + EXTRA_ALLOC,
945 drawing->height + height + EXTRA_ALLOC,
946 -1);
947 drawing->alloc_width = drawing->width + SAFETY + EXTRA_ALLOC;
948 drawing->alloc_height = drawing->height + height + EXTRA_ALLOC;
949 reallocate = TRUE;
950
951 /* Copy the high region */
952 gdk_draw_pixmap (new_pixmap,
953 drawing->drawing_area->style->black_gc,
954 drawing->pixmap,
955 0, 0,
956 0, 0,
957 drawing->width + SAFETY, y);
958
959 } else {
960 new_pixmap = drawing->pixmap;
961 }
962
963 //GdkPixmap *pixmap = gdk_pixmap_new(drawing->drawing_area->window,
964 // drawing->width + SAFETY,
965 // drawing->height + height,
966 // -1);
967
968 /* add an empty square */
969 gdk_draw_rectangle (new_pixmap,
970 drawing->drawing_area->style->black_gc,
971 TRUE,
972 0, y,
973 drawing->width + SAFETY, // do not overlap
974 height);
975
976 /* copy the bottom of the region */
977 gdk_draw_pixmap (new_pixmap,
978 drawing->drawing_area->style->black_gc,
979 drawing->pixmap,
980 0, y,
981 0, y + height,
982 drawing->width+SAFETY, drawing->height - y);
983
984
985 if(reallocate && likely(drawing->pixmap)) {
986 gdk_pixmap_unref(drawing->pixmap);
987 drawing->pixmap = new_pixmap;
988 }
989
990 if(unlikely(drawing->height==1)) drawing->height = height;
991 else drawing->height += height;
992
993 gtk_widget_set_size_request(drawing->drawing_area,
994 -1,
995 drawing->height);
996 gtk_widget_queue_resize_no_redraw(drawing->drawing_area);
997
998 /* ask for the buffer to be redrawn */
999 gtk_widget_queue_draw_area ( drawing->drawing_area,
1000 0, y,
1001 drawing->width, drawing->height-y);
1002 }
1003
1004
1005 /* Remove a square corresponding to a removed process in the list */
1006 void drawing_remove_square(Drawing_t *drawing,
1007 guint y,
1008 guint height)
1009 {
1010 GdkPixmap *pixmap;
1011
1012 if(unlikely((guint)drawing->height == height)) {
1013 //pixmap = gdk_pixmap_new(
1014 // drawing->drawing_area->window,
1015 // drawing->width + SAFETY,
1016 // 1,
1017 // -1);
1018 pixmap = drawing->pixmap;
1019 drawing->height=1;
1020 } else {
1021 /* Allocate a new pixmap with new height */
1022 //pixmap = gdk_pixmap_new(
1023 // drawing->drawing_area->window,
1024 // drawing->width + SAFETY,
1025 // drawing->height - height,
1026 // -1);
1027 /* Keep the same preallocated pixmap */
1028 pixmap = drawing->pixmap;
1029
1030 /* Copy the high region */
1031 gdk_draw_pixmap (pixmap,
1032 drawing->drawing_area->style->black_gc,
1033 drawing->pixmap,
1034 0, 0,
1035 0, 0,
1036 drawing->width + SAFETY, y);
1037
1038 /* Copy up the bottom of the region */
1039 gdk_draw_pixmap (pixmap,
1040 drawing->drawing_area->style->black_gc,
1041 drawing->pixmap,
1042 0, y + height,
1043 0, y,
1044 drawing->width, drawing->height - y - height);
1045
1046 drawing->height-=height;
1047 }
1048
1049 //if(likely(drawing->pixmap))
1050 // gdk_pixmap_unref(drawing->pixmap);
1051
1052 //drawing->pixmap = pixmap;
1053
1054 gtk_widget_set_size_request(drawing->drawing_area,
1055 -1,
1056 drawing->height);
1057 gtk_widget_queue_resize_no_redraw(drawing->drawing_area);
1058 /* ask for the buffer to be redrawn */
1059 gtk_widget_queue_draw_area ( drawing->drawing_area,
1060 0, y,
1061 drawing->width, MAX(drawing->height-y, 1));
1062 }
1063 #endif //0
1064
1065 void drawing_update_ruler(Drawing_t *drawing, TimeWindow *time_window)
1066 {
1067 gtk_widget_queue_draw(drawing->ruler);
1068 }
1069
1070 /* Redraw the ruler */
1071 static gboolean
1072 expose_ruler( GtkWidget *widget, GdkEventExpose *event, gpointer user_data )
1073 {
1074 Drawing_t *drawing = (Drawing_t*)user_data;
1075 TimeWindow time_window = lttvwindow_get_time_window(drawing->control_flow_data->tab);
1076 gchar text[255];
1077
1078 PangoContext *context;
1079 PangoLayout *layout;
1080 PangoFontDescription *FontDesc;
1081 PangoRectangle ink_rect;
1082 gint global_width=0;
1083 GdkColor foreground = { 0, 0, 0, 0 };
1084 GdkColor background = { 0, 0xffff, 0xffff, 0xffff };
1085
1086 LttTime window_end = time_window.end_time;
1087 LttTime half_width =
1088 ltt_time_div(time_window.time_width,2.0);
1089 LttTime window_middle =
1090 ltt_time_add(half_width,
1091 time_window.start_time);
1092 g_debug("ruler expose event");
1093
1094 gdk_draw_rectangle (drawing->ruler->window,
1095 drawing->ruler->style->white_gc,
1096 TRUE,
1097 event->area.x, event->area.y,
1098 event->area.width,
1099 event->area.height);
1100
1101 gdk_draw_line (drawing->ruler->window,
1102 drawing->ruler_gc_butt,
1103 event->area.x, 1,
1104 event->area.x + event->area.width, 1);
1105
1106
1107 snprintf(text, 255, "%lus\n%luns",
1108 time_window.start_time.tv_sec,
1109 time_window.start_time.tv_nsec);
1110
1111 layout = gtk_widget_create_pango_layout(drawing->drawing_area, NULL);
1112
1113 context = pango_layout_get_context(layout);
1114 FontDesc = pango_context_get_font_description(context);
1115
1116 pango_font_description_set_size(FontDesc, 6*PANGO_SCALE);
1117 pango_layout_context_changed(layout);
1118
1119 pango_layout_set_text(layout, text, -1);
1120 pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
1121 global_width += ink_rect.width;
1122
1123 gdk_draw_layout_with_colors(drawing->ruler->window,
1124 drawing->ruler_gc_butt,
1125 0,
1126 6,
1127 layout, &foreground, &background);
1128
1129 gdk_draw_line (drawing->ruler->window,
1130 drawing->ruler_gc_round,
1131 1, 1,
1132 1, 7);
1133
1134
1135 snprintf(text, 255, "%lus\n%luns", window_end.tv_sec,
1136 window_end.tv_nsec);
1137
1138 pango_layout_set_text(layout, text, -1);
1139 pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
1140 global_width += ink_rect.width;
1141
1142 if(global_width <= drawing->ruler->allocation.width)
1143 {
1144 gdk_draw_layout_with_colors(drawing->ruler->window,
1145 drawing->ruler_gc_butt,
1146 drawing->ruler->allocation.width - ink_rect.width,
1147 6,
1148 layout, &foreground, &background);
1149
1150 gdk_draw_line (drawing->ruler->window,
1151 drawing->ruler_gc_butt,
1152 drawing->ruler->allocation.width-1, 1,
1153 drawing->ruler->allocation.width-1, 7);
1154 }
1155
1156
1157 snprintf(text, 255, "%lus\n%luns", window_middle.tv_sec,
1158 window_middle.tv_nsec);
1159
1160 pango_layout_set_text(layout, text, -1);
1161 pango_layout_get_pixel_extents(layout, &ink_rect, NULL);
1162 global_width += ink_rect.width;
1163
1164 if(global_width <= drawing->ruler->allocation.width)
1165 {
1166 gdk_draw_layout_with_colors(drawing->ruler->window,
1167 drawing->ruler_gc_butt,
1168 (drawing->ruler->allocation.width - ink_rect.width)/2,
1169 6,
1170 layout, &foreground, &background);
1171
1172 gdk_draw_line (drawing->ruler->window,
1173 drawing->ruler_gc_butt,
1174 drawing->ruler->allocation.width/2, 1,
1175 drawing->ruler->allocation.width/2, 7);
1176
1177
1178
1179
1180 }
1181
1182 g_object_unref(layout);
1183
1184 return FALSE;
1185 }
1186
1187
1188 /* notify mouse on ruler */
1189 static gboolean
1190 motion_notify_ruler(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
1191 {
1192 //g_debug("motion");
1193 //eventually follow mouse and show time here
1194 return 0;
1195 }
This page took 0.056354 seconds and 3 git commands to generate.