2 *------------------------------------------------------------------
3 * Copyright (c) 2005-2019 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include <gdk/gdkkeysyms.h>
25 #include <vppinfra/format.h>
26 #include <vppinfra/elog.h>
30 * The main event display view.
32 * Important variables:
34 * "da" -- the drawing area, aka the screen representation of the
37 * "pm" -- the backing pixmap for the drawing area. Note that
38 * all graphics operations target this backing
39 * store, then call gtk_widget_draw to copy a rectangle from
40 * the backing store onto the screen.
42 * "s_v1" -- pointer to the current v1_geometry_t object.
48 * s_view1_topbutton("Top")
49 * s_view1_vscroll (vertical scrollbar)
50 * s_view1_bottombutton("Bottom")
52 * s_view1_startbutton("Start");
53 * s_view1_hscroll(horizontal scrollbar)
54 * s_view1_endbutton("End")
55 * s_view1_zoominbutton("Zoomin")
56 * s_view1_searchbutton("Search")
57 * s_view1_searchagainbutton("Search Again")
58 * s_view1_zoomoutbutton("Zoomout")
66 GdkFont *g_font; /* a fixed-width font to use */
67 /* color format: 0 (for static colors), r (0-64k), g (0-64k), b (0-64k) */
68 GdkColor fg_black = {0, 0, 0, 0};
69 GdkColor fg_red = {0, 65535, 0, 0};
70 GdkColor bg_white = {0, 65535, 65535, 65535};
71 static boolean summary_mode = TRUE; /* start out in summary mode */
72 static boolean color_mode = FALSE; /* start out in monochrome mode */
79 * user_data values passed to view1_button_click_callback,
80 * which is used by the various action buttons noted above
82 enum view1_button_click {
90 ANOMALY_THRESHOLD_BUTTON,
118 SRCH_CHASE_FORWARD = 0,
119 SRCH_CHASE_BACKWARD = 1,
122 static GtkWidget *s_view1_hbox; /* see box heirarchy chart */
123 static GtkWidget *s_view1_vbox; /* see box heirarchy chart */
124 static GtkWidget *da; /* main drawing area */
125 static GdkPixmap *pm; /* and its backing pixmap */
126 static GdkCursor *norm_cursor; /* the "normal" cursor */
129 * view geometry parameters
132 * Y increases down the page.
133 * Strip origin is at the top
135 * Don't put your fingers in your mouth.
137 * Most of these values are in pixels
140 typedef struct v1_geometry {
141 int pid_ax_width; /* Width of the PID axis */
142 int time_ax_height; /* Height of the time axis */
143 int time_ax_spacing; /* TimeAxis: Space between tick-marks */
144 int strip_height; /* Height of a regular PID trace */
145 int pop_offset; /* Vertical offset of the detail box */
146 int pid_ax_offset; /* Vertical offset of the PID axis */
147 int event_offset; /* Vertical offset of the event boxes */
148 int total_height; /* total height of da, see configure_event */
149 int total_width; /* ditto, for width */
150 double last_time_interval; /* last time interval, in f64 seconds */
151 double anomaly_threshold_stddevs; /* Anomaly detection threshold */
154 int first_pid_index; /* Index of first displayed PID */
155 int npids; /* Max number of displayed pids */
156 ulonglong minvistime; /* in usec */
157 ulonglong maxvistime; /* in usec */
159 /* Anomaly detection statistics */
160 f64 *means, *variances, *two_stddevs;
166 /* The active geometry object */
167 static v1_geometry_t s_v1record;
168 static v1_geometry_t *s_v1 = &s_v1record;
170 /* The color array */
171 static GdkColor *s_color;
174 typedef struct snapshot {
175 struct snapshot *next;
176 /* Screen geometry */
177 v1_geometry_t geometry;
178 boolean show_event[NEVENTS];
181 * Note: not worth recomputing the vertical scrollbar, just save
184 gfloat vscroll_value;
185 boolean summary_mode;
189 static snapshot_t *s_snapshots;
190 static snapshot_t *s_cursnap;
191 static event_t *s_last_selected_event;
194 * various widgets, see the box heirarchy chart above
195 * The toolkit keeps track of these things, we could lose many of
198 static GtkWidget *s_view1_vmenubox;
199 static GtkWidget *s_view1_topbutton;
200 static GtkWidget *s_view1_bottombutton;
201 static GtkWidget *s_view1_more_traces_button;
202 static GtkWidget *s_view1_less_traces_button;
204 static GtkWidget *s_view1_hmenubox;
205 static GtkWidget *s_view1_hmenubox2;
206 static GtkWidget *s_view1_startbutton;
207 static GtkWidget *s_view1_zoominbutton;
208 static GtkWidget *s_view1_searchbutton;
209 static GtkWidget *s_view1_srchagainbutton;
210 static GtkWidget *s_view1_anomalybutton;
211 static GtkWidget *s_view1_anomalynextbutton;
212 static GtkWidget *s_view1_zoomoutbutton;
213 static GtkWidget *s_view1_endbutton;
215 static GtkWidget *s_view1_snapbutton;
216 static GtkWidget *s_view1_nextbutton;
217 static GtkWidget *s_view1_delbutton;
219 static GtkWidget *s_view1_chase_event_button;
220 static GtkWidget *s_view1_chase_datum_button;
221 static GtkWidget *s_view1_chase_track_button;
222 static GtkWidget *s_view1_unchasebutton;
224 static GtkWidget *s_view1_forward_button;
225 static GtkWidget *s_view1_backward_button;
227 static GtkWidget *s_view1_summary_button;
228 static GtkWidget *s_view1_nosummary_button;
230 static GtkWidget *s_view1_time_slew_right_button;
231 static GtkWidget *s_view1_time_slew_left_button;
233 static GtkWidget *s_view1_anomalythresholdbutton;
235 static GtkWidget *s_view1_hscroll;
236 static GtkObject *s_view1_hsadj;
238 static GtkWidget *s_view1_vscroll;
239 static GtkObject *s_view1_vsadj;
241 static GtkWidget *s_view1_label;
246 static ulong s_srchcode; /* search event code */
247 static ulong s_anomalycode; /* anomaly event code */
248 static int s_srchindex; /* last hit was at this event index */
249 static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */
250 static boolean s_srchfail_up; /* The status line "Search Failed" is up */
251 static int srch_chase_dir; /* search/chase dir, 0=>forward */
257 static int s_print_offset; /* Magic offset added to line, tbox fn codes */
258 static FILE *s_printfp;
261 * Forward reference prototypes
263 static void display_pid_axis(v1_geometry_t *vp);
264 static void display_event_data(v1_geometry_t *vp);
265 static void display_time_axis(v1_geometry_t *vp);
266 static void view1_button_click_callback(GtkButton *item, gpointer data);
272 gint c_view1_draw_width;
273 gint c_view1_draw_height;
276 * Zoom-In / Time Ruler cursor
283 static unsigned char zi_bits[] = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
285 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
286 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
287 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
288 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
289 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
290 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
291 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
292 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
293 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
296 static unsigned char zi_bkgd[] = {
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
298 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
299 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
300 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
301 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
302 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
303 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
304 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
305 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
306 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
309 static GdkCursor *zi_cursor;
310 static GdkPixmap *zi_source, *zi_mask;
313 * Frequently-used small computations, best
314 * done correctly once and instantiated.
317 /****************************************************************************
319 ****************************************************************************/
321 static inline double dtime_per_pixel(v1_geometry_t *vp)
323 return ((double)(vp->maxvistime - vp->minvistime)) /
324 ((double)(vp->total_width - vp->pid_ax_width));
327 /****************************************************************************
329 * Changes the status line. Pass "" to clear the status line.
330 ****************************************************************************/
332 void message_line (char *s)
334 gtk_label_set_text (GTK_LABEL(s_view1_label), s);
337 /****************************************************************************
339 * Changes the window title to include the specified filename.
340 ****************************************************************************/
342 void set_window_title (const char *filename)
345 snprintf(title, sizeof(title), "g2 (%s)", filename);
346 gtk_window_set_title(GTK_WINDOW(g_mainwindow), title);
349 /****************************************************************************
350 * recompute_hscrollbar
351 * Adjust the horizontal scrollbar's adjustment object.
353 * GtkAdjustments are really cool, but have to be set up exactly
354 * right or the various client objects screw up completely.
356 * Note: this function is *not* called when the user clicks the scrollbar.
357 ****************************************************************************/
359 static void recompute_hscrollbar (void)
361 ulonglong current_width;
362 ulonglong event_incdec;
369 ep = (g_events + (g_nevents-1));
370 current_width = s_v1->maxvistime - s_v1->minvistime;
371 event_incdec = (current_width) / 6;
373 adj = GTK_ADJUSTMENT(s_view1_hsadj);
376 * Structure member decoder ring
377 * -----------------------------
378 * lower the minimum possible value
379 * value the current value
380 * upper the maximum possible value
381 * step_increment end button click increment
382 * page_increment click in trough increment
383 * page_size size of currently visible area
386 adj->lower = (gfloat)0.00;
387 adj->value = (gfloat)s_v1->minvistime;
389 /* Minor click: move about 1/6 of a page */
390 adj->step_increment = (gfloat)event_incdec;
392 /* Major click: move about 1/3 of a page. */
393 adj->page_increment = (gfloat)(2*event_incdec);
395 /* allow the user to go a bit past the end */
396 adj->upper = adj->page_increment/3 + (gfloat)(ep->time);
397 adj->page_size = (gfloat)(current_width);
400 * Tell all clients (e.g. the visible scrollbar) to
401 * make themselves look right
403 gtk_adjustment_changed(adj);
404 gtk_adjustment_value_changed(adj);
407 /****************************************************************************
408 * recompute_vscrollbar
409 * Ditto, for the vertical scrollbar
410 ****************************************************************************/
412 static void recompute_vscrollbar (void)
416 adj = GTK_ADJUSTMENT(s_view1_vsadj);
418 adj->lower = (gfloat)0.00;
419 adj->upper = (gfloat)g_npids;
420 adj->value = (gfloat)0.00;
421 adj->step_increment = 1.00;
422 adj->page_increment = (gfloat)(s_v1->npids / 3);
423 adj->page_size = (gfloat)s_v1->npids;
424 gtk_adjustment_changed(adj);
425 gtk_adjustment_value_changed(adj);
428 /****************************************************************************
429 * format_popbox_string
430 ****************************************************************************/
432 elog_main_t elog_main;
434 void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp)
439 sprintf(tmpbuf,"%d:", ep->code);
441 if (ep->flags & EVENT_FLAG_CLIB) {
445 eep = get_clib_event (ep->datum);
447 s = format (0, "%U", format_elog_event, &elog_main, eep);
448 memcpy (tmpbuf, s, vec_len(s));
449 tmpbuf[vec_len(s)] = 0;
454 snprintf(tmpbuf, len, "%s", edp->name);
456 /* Make sure there's a real format string. If so, add it */
459 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
460 /* %s only supported for cpel files */
462 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
463 edp->format, strtab_ref(ep->datum));
465 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
466 edp->format, ep->datum);
474 /****************************************************************************
476 ****************************************************************************/
478 static void add_snapshot(void)
481 snapshot_t *new = g_malloc(sizeof(snapshot_t));
483 memcpy(&new->geometry, s_v1, sizeof(new->geometry));
484 for (i = 0; i < NEVENTS; i++) {
485 new->show_event[i] = g_eventdefs[i].selected;
487 new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids);
488 memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids);
489 new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value;
490 new->summary_mode = summary_mode;
491 new->color_mode = color_mode;
494 new->next = s_snapshots;
503 /****************************************************************************
505 ****************************************************************************/
507 static void next_snapshot(void)
515 infobox("No snapshots", "\nNo snapshots in the ring...\n");
519 next = s_cursnap->next;
525 memcpy(s_v1, &next->geometry, sizeof(next->geometry));
526 for (i = 0; i < NEVENTS; i++) {
527 g_eventdefs[i].selected = next->show_event[i];
529 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
530 color_mode = next->color_mode;
532 * Update summary mode via a button push so that the button state is
533 * updated accordingly. (Should ideally clean up the view/controller
534 * separation properly one day.)
536 if (summary_mode != next->summary_mode) {
537 view1_button_click_callback
538 (NULL, (gpointer)(unsigned long long)
539 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
542 /* Fix the pid structure index mappings */
545 for (i = 0; i < g_npids; i++) {
550 GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value;
551 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
552 recompute_hscrollbar();
553 pointsel_next_snapshot();
554 view1_display_when_idle();
558 /****************************************************************************
560 ****************************************************************************/
562 static void del_snapshot(void)
568 infobox("No snapshots", "\nNo snapshots to delete...\n");
575 while (this && this != s_cursnap) {
580 if (this != s_cursnap) {
581 infobox("BUG", "\nSnapshot AWOL!\n");
585 s_cursnap = this->next;
587 /* middle of the list? */
589 prev->next = this->next;
590 g_free(this->pidvec);
592 } else { /* start of the list */
593 s_snapshots = this->next;
594 g_free(this->pidvec);
598 /* Note: both will be NULL after last delete */
599 if (s_cursnap == NULL)
600 s_cursnap = s_snapshots;
603 /****************************************************************************
606 * VERY primitive right now - not endian or version independent, and only
607 * writes to "snapshots.g2" in the current directory
608 ****************************************************************************/
609 static void write_snapshot(void)
616 if (s_snapshots == NULL) {
617 error = "No snapshots defined";
622 file = fopen("snapshots.g2", "w");
624 error = "Unable to open snapshots.g2";
629 * Simply serialize the arch-dependent binary data, without a care in the
630 * world. Don't come running to me if you try to read it and crash.
632 for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) {
633 if (fwrite(&snap->geometry,
634 sizeof(snap->geometry), 1, file) != 1 ||
635 fwrite(&snap->show_event,
636 sizeof(snap->show_event), 1, file) != 1 ||
638 sizeof(pid_sort_t) * g_npids, 1, file) != 1 ||
639 fwrite(&snap->vscroll_value,
640 sizeof(snap->vscroll_value), 1, file) != 1 ||
641 fwrite(&snap->summary_mode,
642 sizeof(snap->summary_mode), 1, file) != 1 ||
643 fwrite(&snap->color_mode,
644 sizeof(snap->color_mode), 1, file) != 1) {
645 error = "Error writing data";
652 error = "Unable to close file";
657 infobox(error, strerror(errno));
660 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
666 /****************************************************************************
669 * VERY primitive right now - not endian or version independent, and only reads
670 * from "snapshots.g2" in the current directory
671 ****************************************************************************/
672 static void read_snapshot(void)
675 snapshot_t *snap, *next_snap;
676 snapshot_t *new_snaps = NULL;
678 int len, i, records = 0;
681 file = fopen("snapshots.g2", "r");
683 error = "Unable to open snapshots.g2";
687 * Read in the snapshots and link them together. We insert them backwards,
688 * but that's tolerable. If the data is in anyway not what we expect, we'll
689 * probably crash. Sorry.
691 while (!error && !feof(file)) {
692 snap = g_malloc(sizeof(*snap));
693 snap->pidvec = NULL; /* so we can free this if there's an error */
695 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
701 /* insert into list straight away */
702 snap->next = new_snaps;
706 error = "Problem reading first item from file";
709 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
710 error = "Problem reading second item from file";
713 len = sizeof(pid_sort_t) * g_npids;
714 snap->pidvec = g_malloc(len);
715 if (fread(snap->pidvec, len, 1, file) != 1) {
716 error = "Problem reading third item from file";
719 if (fread(&snap->vscroll_value,
720 sizeof(snap->vscroll_value), 1, file) != 1 ||
721 fread(&snap->summary_mode,
722 sizeof(snap->summary_mode), 1, file) != 1 ||
723 fread(&snap->color_mode,
724 sizeof(snap->color_mode), 1, file) != 1) {
725 error = "Problem reading final items from file";
730 * Fix up the pointers from the sorted pid vector back into our pid
731 * data objects, by walking the linked list of pid_data_t objects for
732 * every one looking for a match. This is O(n^2) grossness, but in real
733 * life there aren't that many pids, and it seems zippy enough.
735 for (i = 0; i < g_npids; i++) {
736 for (pp = g_pid_data_list; pp != NULL; pp = pp->next) {
737 if (pp->pid_value == snap->pidvec[i].pid_value) {
742 snap->pidvec[i].pid = pp;
744 error = "Snapshot file referenced unknown pids";
754 error = "Unable to close file";
760 * Problem - clear up any detritus
762 infobox(error, strerror(errno));
763 for (snap = new_snaps; snap != NULL; snap = next_snap) {
764 next_snap = snap->next;
766 g_free(snap->pidvec);
770 * Success! trash the old snapshots and replace with the new
772 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
773 next_snap = snap->next;
774 g_free(snap->pidvec);
778 s_cursnap = s_snapshots = new_snaps;
782 infobox(error, strerror(errno));
785 snprintf(buf, sizeof(buf),
786 "Read %d snapshots from snapshots.g2", records);
791 /****************************************************************************
794 * Set the color for the specified pid_index, or COLOR_DEFAULT to return it
795 * to the usual black.
796 ****************************************************************************/
797 #define COLOR_DEFAULT (-1)
798 static void set_color(int pid_index)
802 psp = (g_pids + pid_index);
805 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
806 else if (pid_index == COLOR_DEFAULT || !color_mode) {
807 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
809 gdk_gc_set_foreground(da->style->black_gc,
810 &s_color[g_pids[pid_index].color_index]);
814 /****************************************************************************
815 * toggle_event_select
816 ****************************************************************************/
818 static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
820 int pid_index, start_index;
823 GdkRectangle hit_rect;
828 double time_per_pixel;
833 time_per_pixel = dtime_per_pixel(vp);
835 start_index = find_event_index (vp->minvistime);
838 if (start_index >= g_nevents)
842 * To see if the mouse hit a visible event, use a variant
843 * of the event display loop.
846 hit_rect.x = (int)event->x;
847 hit_rect.y = (int)event->y;
851 ep = (g_events + start_index);
853 while ((ep->time < vp->maxvistime) &&
854 (ep < (g_events + g_nevents))) {
855 pid_index = ep->pid->pid_index;
857 /* First filter: pid out of range */
858 if ((pid_index < vp->first_pid_index) ||
859 (pid_index >= vp->first_pid_index + vp->npids)) {
864 /* Second filter: event hidden */
865 edp = find_event_definition (ep->code);
866 if (!edp->selected) {
872 * At this point, we know that the point is at least on the
873 * screen. See if the mouse hit within the bounding box
877 * $$$$ maybe keep looping until off the edge,
878 * maintain a "best hit", then declare that one the winner?
881 pid_index -= vp->first_pid_index;
883 y = pid_index*vp->strip_height + vp->event_offset;
885 x = vp->pid_ax_width +
886 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
888 /* Perhaps we're trying to toggle the detail box? */
889 if (ep->flags & EVENT_FLAG_SELECT) {
890 /* Figure out the dimensions of the detail box */
891 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
892 rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED);
893 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
894 ep->flags &= ~EVENT_FLAG_SELECT;
895 view1_display_when_idle();
900 sprintf(tmpbuf, "%ld", ep->code);
902 /* Figure out the dimensions of the regular box */
903 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
905 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
906 /* we hit the rectangle. */
907 if (ep->flags & EVENT_FLAG_SELECT) {
908 ep->flags &= ~EVENT_FLAG_SELECT;
909 view1_display_when_idle();
912 set_color(ep->pid->pid_index);
914 /* It wasn't selected, so put up the detail box */
915 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
916 tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED);
917 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK);
918 ep->flags |= EVENT_FLAG_SELECT;
919 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
920 s_last_selected_event = ep;
929 /****************************************************************************
930 * toggle_track_select
931 ****************************************************************************/
933 static void toggle_track_select (GdkEventButton *event,
944 /* Scan pid/track axis locations, looking for a match */
945 for (i = 0; i < vp->npids; i++) {
946 y = i*vp->strip_height + vp->pid_ax_offset;
947 delta_y = y - event->y;
955 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
959 pid_index = i + vp->first_pid_index;
960 psp = (g_pids + pid_index);
962 view1_display_when_idle();
965 /****************************************************************************
967 ****************************************************************************/
968 static void deselect_tracks (void)
972 for (i = 0; i < g_npids; i++)
973 g_pids[i].selected = 0;
978 /****************************************************************************
980 ****************************************************************************/
982 typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
984 static void move_current_track(GdkEventButton *event,
991 pid_sort_t *new_pidvec;
993 pid_sort_t *pold, *pnew;
999 /* Scan pid/track axis locations, looking for a match */
1000 for (i = 0; i < vp->npids; i++) {
1001 y = i*vp->strip_height + vp->pid_ax_offset;
1002 delta_y = y - event->y;
1010 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
1014 pid_index = i + vp->first_pid_index;
1016 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
1020 if (type == MOVE_TOP) {
1022 *pnew++ = g_pids[pid_index];
1023 for (i = 0; i < pid_index; i++)
1027 for (; i < g_npids; i++)
1030 /* move to bottom */
1031 for (i = 0; i < pid_index; i++)
1035 for (; i < g_npids; i++)
1037 *pnew = g_pids[pid_index];
1041 g_pids = new_pidvec;
1044 * Revert the pid_index mapping to an identity map,
1048 for (i = 0; i < g_npids; i++) {
1053 view1_display_when_idle();
1056 /****************************************************************************
1058 * Process a zoom gesture. The use of doubles is required to avoid
1059 * truncating the various variable values, which in turn would lead to
1060 * some pretty random-looking zoom responses.
1061 ****************************************************************************/
1063 void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1066 double time_per_pixel;
1067 double width_in_pixels;
1068 double center_on_time, width_in_time;
1069 double center_on_pixel;
1072 * Clip the zoom area to the event display area.
1073 * Otherwise, center_on_time - width_in_time is in hyperspace
1074 * to the left of zero
1077 if (e1->x < vp->pid_ax_width)
1078 e1->x = vp->pid_ax_width;
1080 if (e2->x < vp->pid_ax_width)
1081 e2->x = vp->pid_ax_width;
1084 goto loser_zoom_repaint;
1086 xrange = (double) (e2->x - e1->x);
1090 /* Actually, width in pixels of half the zoom area */
1091 width_in_pixels = xrange / 2.00;
1092 time_per_pixel = dtime_per_pixel(vp);
1093 width_in_time = width_in_pixels * time_per_pixel;
1095 /* Center the screen on the center of the zoom area */
1096 center_on_pixel = (double)((e2->x + e1->x) / 2.00) -
1097 (double)vp->pid_ax_width;
1098 center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime;
1101 * Transform back to 64-bit integer microseconds, reset the
1102 * scrollbar, schedule a repaint.
1104 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1105 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1108 recompute_hscrollbar();
1110 view1_display_when_idle();
1113 /****************************************************************************
1116 * Scroll up or down by the specified delta
1118 ****************************************************************************/
1119 static void scroll_y(int delta)
1121 int new_index = s_v1->first_pid_index + delta;
1122 if (new_index + s_v1->npids > g_npids)
1123 new_index = g_npids - s_v1->npids;
1127 if (new_index != s_v1->first_pid_index) {
1128 s_v1->first_pid_index = new_index;
1129 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index;
1130 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1131 view1_display_when_idle();
1135 /****************************************************************************
1136 * view1_handle_key_press_event
1137 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1139 * This routine implements hotkeys for the Quake generation:
1150 * E - toggle summary mode
1151 * C - toggle color mode
1155 * P - persist snapshots to file
1156 * L - load snapshots from file
1160 ****************************************************************************/
1162 view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1166 switch (event->keyval) {
1167 case GDK_w: // zoom in
1168 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1171 case GDK_s: // zoom out
1172 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1175 case GDK_a: // pan left
1176 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1177 if (s_v1->minvistime < delta) {
1178 delta = s_v1->minvistime;
1180 s_v1->minvistime -= delta;
1181 s_v1->maxvistime -= delta;
1182 recompute_hscrollbar();
1185 case GDK_d: // pan right
1186 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1187 if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) {
1189 * @@@ this doesn't seem to quite reach the far right hand
1190 * side correctly - not sure why.
1192 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1194 s_v1->minvistime += delta;
1195 s_v1->maxvistime += delta;
1196 recompute_hscrollbar();
1199 case GDK_r: // pan up
1203 case GDK_f: // pan down
1207 case GDK_t: // fewer tracks
1208 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1211 case GDK_g: // more tracks
1212 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1215 case GDK_e: // toggle summary mode
1216 view1_button_click_callback
1217 (NULL, (gpointer)(unsigned long long)
1218 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
1221 case GDK_c: // toggle color mode
1223 view1_display_when_idle();
1226 case GDK_p: // persist snapshots
1230 case GDK_l: // load snapshots
1234 case GDK_x: // take snapshot
1235 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1238 case GDK_z: // next snapshot
1239 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1242 case GDK_q: // ctrl-q is exit
1243 if (event->state & GDK_CONTROL_MASK) {
1251 /****************************************************************************
1252 * button_press_event
1253 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1255 * This routine implements three functions: zoom-to-area, time ruler, and
1256 * show/hide event detail popup.
1258 * The left mouse button (button 1) has two simultaneous functions: event
1259 * detail popup, and zoom-to-area. If the press and release events occur
1260 * within a small delta-x, it's a detail popup event. Otherwise, it's
1263 * The right mouse button (button 3) implements the time ruler.
1264 ****************************************************************************/
1267 button_press_event (GtkWidget *widget, GdkEventButton *event)
1269 static GdkEventButton press1_event;
1270 static boolean press1_valid;
1271 static GdkEventButton press3_event;
1272 static guint32 last_truler_time;
1273 static boolean press3_valid;
1274 static boolean zoom_bar_up;
1275 int time_ax_y, xdelta;
1277 double time_per_pixel;
1281 switch(event->type) {
1282 case GDK_BUTTON_PRESS:
1283 /* Capture the appropriate starting point */
1284 if (event->button == 1) {
1285 press1_valid = TRUE;
1286 press1_event = *event;
1289 if (event->button == 3) {
1290 press3_valid = TRUE;
1291 press3_event = *event;
1296 case GDK_BUTTON_RELEASE:
1299 press3_valid = FALSE;
1300 /* Fix the cursor, and repaint the screen from scratch */
1301 gdk_window_set_cursor (da->window, norm_cursor);
1302 view1_display_when_idle();
1305 /* Event select / zoom-to-area */
1307 press1_valid = FALSE;
1308 xdelta = (int)(press1_event.x - event->x);
1312 /* is the mouse more or less where it started? */
1314 /* Control-left-mouse => sink the track */
1315 /* Shift-left-mouse => raise the track */
1316 if ((press1_event.state & GDK_CONTROL_MASK) ==
1318 move_current_track(event, s_v1, MOVE_BOTTOM);
1319 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1321 move_current_track(event, s_v1, MOVE_TOP);
1323 /* No modifiers: toggle the event / select track */
1324 if (toggle_event_select(event, s_v1))
1325 toggle_track_select(event, s_v1);
1327 /* Repaint to get rid of the zoom bar */
1329 /* Fix the cursor and leave. No zoom */
1330 gdk_window_set_cursor (da->window, norm_cursor);
1331 zoom_bar_up = FALSE;
1334 } else { /* mouse moved enough to zoom */
1335 zoom_event(&press1_event, event, s_v1);
1336 gdk_window_set_cursor (da->window, norm_cursor);
1337 zoom_bar_up = FALSE;
1339 } else if (event->button == 4) {
1340 /* scroll wheel up */
1341 scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1);
1342 } else if (event->button == 5) {
1343 /* scroll wheel down */
1344 scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1);
1348 case GDK_MOTION_NOTIFY:
1349 /* Button one followed by motion: draw zoom fence and fix cursor */
1351 /* Fence, cursor already set */
1355 xdelta = (int)(press1_event.x - event->x);
1359 /* Haven't moved enough to declare a zoom sequence yet */
1363 /* Draw the zoom fence, use the key-down X coordinate */
1364 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1366 line((int)(press1_event.x), s_v1->pop_offset,
1367 (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK);
1368 tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset,
1370 gdk_window_set_cursor(da->window, zi_cursor);
1377 gdk_window_set_cursor(da->window, zi_cursor);
1380 * Some filtration is needed on Solaris, or the server will hang
1382 if (event->time - last_truler_time < 75)
1385 last_truler_time = event->time;
1387 line((int)(press3_event.x), s_v1->pop_offset,
1388 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1390 xdelta = (int)(press3_event.x - event->x);
1394 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1395 ((double)(s_v1->total_width - s_v1->pid_ax_width));
1397 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1399 line((int)(press3_event.x), s_v1->pop_offset,
1400 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1402 * Note: use a fixed-width format so it looks like we're
1403 * erasing and redrawing the box.
1405 nsec = ((double)xdelta)*time_per_pixel;
1407 sprintf(tmpbuf, "%8.3f sec ", nsec/1e9);
1408 } else if (nsec > 1e6) {
1409 sprintf(tmpbuf, "%8.3f msec", nsec/1e6);
1410 } else if (nsec > 1e3) {
1411 sprintf(tmpbuf, "%8.3f usec", nsec/1e3);
1413 sprintf(tmpbuf, "%8.0f nsec", nsec);
1415 s_v1->last_time_interval = nsec;
1416 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1424 g_print("button:\ttype = %d\n", event->type);
1425 g_print("\twindow = 0x%x\n", event->window);
1426 g_print("\tsend_event = %d\n", event->send_event);
1427 g_print("\ttime = %d\n", event->time);
1428 g_print("\tx = %6.2f\n", event->x);
1429 g_print("\ty = %6.2f\n", event->y);
1430 g_print("\tpressure = %6.2f\n", event->pressure);
1431 g_print("\txtilt = %6.2f\n", event->xtilt);
1432 g_print("\tytilt = %6.2f\n", event->ytilt);
1433 g_print("\tstate = %d\n", event->state);
1434 g_print("\tbutton = %d\n", event->button);
1435 g_print("\tsource = %d\n", event->source);
1436 g_print("\tdeviceid = %d\n", event->deviceid);
1437 g_print("\tx_root = %6.2f\n", event->x_root);
1438 g_print("\ty_root = %6.2f\n", event->y_root);
1443 view1_display_when_idle();
1448 /****************************************************************************
1450 * Happens when the window manager resizes the viewer's main window.
1451 ****************************************************************************/
1454 configure_event (GtkWidget *widget, GdkEventConfigure *event)
1456 /* Toss the previous drawing area backing store pixmap */
1458 gdk_pixmap_unref(pm);
1460 /* Create a new pixmap, paint it */
1461 pm = gdk_pixmap_new(widget->window,
1462 widget->allocation.width,
1463 widget->allocation.height,
1465 gdk_draw_rectangle (pm,
1466 widget->style->white_gc,
1469 widget->allocation.width,
1470 widget->allocation.height);
1472 /* Reset the view geometry parameters, as required */
1473 s_v1->total_width = widget->allocation.width;
1474 s_v1->total_height = widget->allocation.height;
1475 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
1478 /* Schedule a repaint */
1479 view1_display_when_idle();
1483 /****************************************************************************
1485 * Use backing store to fix the screen.
1486 ****************************************************************************/
1487 static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1489 gdk_draw_pixmap(widget->window,
1490 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1492 event->area.x, event->area.y,
1493 event->area.x, event->area.y,
1494 event->area.width, event->area.height);
1499 /****************************************************************************
1500 * event_search_internal
1501 * This routine searches forward from s_srchindex, looking for s_srchcode;
1502 * wraps at the end of the buffer.
1503 ****************************************************************************/
1505 boolean event_search_internal (void)
1511 boolean full_redisplay = FALSE;
1512 ulonglong current_width;
1515 /* No events yet? Act like the search worked, to avoid a loop */
1519 ep = (g_events + s_srchindex);
1520 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1523 * Assume the user wants to search [plus or minus]
1524 * from where they are.
1527 if (ep->time < s_v1->minvistime)
1528 s_srchindex = find_event_index (s_v1->minvistime);
1531 for (i = 1; i <= g_nevents; i++) {
1532 index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ?
1533 (s_srchindex - i) % g_nevents :
1534 (i + s_srchindex) % g_nevents;
1536 ep = (g_events + index);
1538 if (ep->code == s_srchcode) {
1541 s_srchindex = index;
1542 pid_index = ep->pid->pid_index;
1544 /* Need a vertical scroll? */
1545 if ((pid_index < s_v1->first_pid_index) ||
1546 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1547 if (pid_index > (g_npids - s_v1->npids))
1548 pid_index = (g_npids - s_v1->npids);
1549 s_v1->first_pid_index = pid_index;
1550 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1551 (gdouble)s_v1->first_pid_index;
1552 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1553 full_redisplay = TRUE;
1556 /* Need a horizontal scroll? */
1557 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1558 current_width = (s_v1->maxvistime - s_v1->minvistime);
1559 if (ep->time < ((current_width+1) / 2)) {
1560 s_v1->minvistime = 0ll;
1561 s_v1->maxvistime = current_width;
1563 s_v1->minvistime = ep->time - ((current_width+1)/2);
1564 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1566 recompute_hscrollbar();
1567 full_redisplay = TRUE;
1569 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1570 full_redisplay = TRUE;
1573 if (!full_redisplay){
1576 time_per_pixel = dtime_per_pixel(s_v1);
1578 y = pid_index*s_v1->strip_height + s_v1->event_offset;
1579 x = s_v1->pid_ax_width +
1580 (int)(((double)(ep->time - s_v1->minvistime)) /
1582 sprintf(tmpbuf, "SEARCH RESULT");
1583 tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED);
1584 line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK);
1586 full_redisplay = TRUE;
1592 view1_display_when_idle();
1596 sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode);
1597 message_line(tmpbuf);
1598 s_srchfail_up = TRUE;
1602 /****************************************************************************
1603 * event_search_callback
1604 ****************************************************************************/
1606 boolean event_search_callback (char *s)
1608 /* No events yet? Act like the search worked, to avoid a loop */
1612 s_srchcode = atol(s);
1614 if (s_srchcode == 0)
1617 return(event_search_internal());
1621 /****************************************************************************
1622 * anomaly_statistics_init
1623 ****************************************************************************/
1625 static int anomaly_statistics_init (void)
1636 /* Gather summary statistics... */
1639 vec_reset_length (s_v1->means);
1640 vec_reset_length (s_v1->matches);
1641 vec_reset_length (s_v1->variances);
1642 vec_reset_length (s_v1->two_stddevs);
1644 for (i = 0; i < g_nevents; i++) {
1645 if (ep->code != s_anomalycode) {
1650 vec_validate_init_empty (s_v1->means, pid->pid_index, 0);
1651 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
1652 eep = get_clib_event (ep->datum);
1653 data = clib_mem_unaligned (eep->data, u32);
1655 s_v1->means[pid->pid_index] += fdata;
1656 s_v1->matches[pid->pid_index] += 1;
1659 if (vec_len (s_v1->matches) == 0)
1662 /* Compute s_v1->means */
1663 for (i = 0; i < vec_len (s_v1->means); i++)
1664 s_v1->means[i] = s_v1->matches[i]
1665 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1667 /* Compute s_v1->variances */
1669 for (i = 0; i < g_nevents; i++) {
1670 if (ep->code != s_anomalycode) {
1675 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1676 eep = get_clib_event (ep->datum);
1677 data = clib_mem_unaligned (eep->data, u32);
1679 s_v1->variances[pid->pid_index] +=
1680 (fdata - s_v1->means[pid->pid_index])
1681 * (fdata - s_v1->means[pid->pid_index]);
1685 /* Normalize variances */
1686 for (i = 0; i < vec_len (s_v1->variances); i++)
1687 s_v1->variances[i] = s_v1->matches[i]
1688 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1690 /* Compute the anomaly threshold, by default 2.5*stddev */
1691 for (i = 0; i < vec_len (s_v1->variances); i++)
1692 vec_add1 (s_v1->two_stddevs,
1693 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1697 /****************************************************************************
1698 * anomaly_search_internal
1699 * This routine searches forward from s_srchindex, looking for s_srchcode;
1700 * wraps at the end of the buffer.
1701 ****************************************************************************/
1703 boolean anomaly_search_internal (void)
1712 boolean full_redisplay = FALSE;
1713 ulonglong current_width;
1717 if (vec_len (s_v1->matches) == 0)
1718 anomaly_statistics_init();
1720 ep = (g_events + s_srchindex);
1721 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1724 * If the user rearranged the screen, start from the minimum
1727 if (ep->time < s_v1->minvistime)
1728 s_srchindex = find_event_index (s_v1->minvistime);
1730 for (i = 1; i <= g_nevents; i++) {
1731 index = (i + s_srchindex) % g_nevents;
1733 ep = (g_events + index);
1734 if (ep->code != s_anomalycode)
1738 eep = get_clib_event (ep->datum);
1739 data = clib_mem_unaligned (eep->data, u32);
1743 * Found an anomaly? Define an anomaly as a datum
1744 * greater than 2*stddev above average.
1746 if ((fdata - s_v1->means[pid->pid_index]) >
1747 s_v1->two_stddevs[pid->pid_index]) {
1750 s = format (0, "%.1f*stddev {mean,threshold}: ",
1751 s_v1->anomaly_threshold_stddevs);
1753 for (i = 0; i < vec_len (s_v1->means); i++) {
1754 s = format (s, "{%.0f, %.0f} ",
1756 s_v1->means[i]+s_v1->two_stddevs[i]);
1759 message_line ((char *)s);
1762 s_srchindex = index;
1763 pid_index = ep->pid->pid_index;
1765 /* Need a vertical scroll? */
1766 if ((pid_index < s_v1->first_pid_index) ||
1767 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1768 if (pid_index > (g_npids - s_v1->npids))
1769 pid_index = (g_npids - s_v1->npids);
1770 s_v1->first_pid_index = pid_index;
1771 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1772 (gdouble)s_v1->first_pid_index;
1773 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1774 full_redisplay = TRUE;
1777 /* Need a horizontal scroll? */
1778 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1779 current_width = (s_v1->maxvistime - s_v1->minvistime);
1780 if (ep->time < ((current_width+1) / 2)) {
1781 s_v1->minvistime = 0ll;
1782 s_v1->maxvistime = current_width;
1784 s_v1->minvistime = ep->time - ((current_width+1)/2);
1785 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1787 recompute_hscrollbar();
1788 full_redisplay = TRUE;
1790 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1791 full_redisplay = TRUE;
1794 view1_display_when_idle();
1799 sprintf (tmpbuf, "Search for an anomalous event %ld failed...\n",
1801 message_line(tmpbuf);
1802 s_srchfail_up = TRUE;
1806 /****************************************************************************
1807 * anomaly_search_callback
1808 ****************************************************************************/
1810 boolean anomaly_search_callback (char *s)
1812 ulong new_anomalycode;
1814 /* No events yet? Act like the search worked, to avoid a loop */
1818 new_anomalycode = atol(s);
1820 if (new_anomalycode == 0)
1823 if (new_anomalycode != s_anomalycode ||
1824 vec_len (s_v1->matches) == 0) {
1825 s_anomalycode = new_anomalycode;
1826 if (anomaly_statistics_init()) {
1829 s = format (0, "Search for an anomalous event %ld failed...\n",
1831 message_line ((char *) s);
1836 return(anomaly_search_internal());
1839 /****************************************************************************
1840 * anomaly_threshold_callback
1841 ****************************************************************************/
1843 boolean anomaly_threshold_callback (char *s)
1847 /* No events yet? Act like the search worked, to avoid a loop */
1851 new_threshold = atof (s);
1853 if (new_threshold == 0.0 || new_threshold > 10.0)
1856 s_v1->anomaly_threshold_stddevs = new_threshold;
1858 vec_reset_length (s_v1->means);
1859 vec_reset_length (s_v1->matches);
1860 vec_reset_length (s_v1->variances);
1861 vec_reset_length (s_v1->two_stddevs);
1865 /****************************************************************************
1867 ****************************************************************************/
1869 static void event_search (void)
1871 modal_dialog ("Event Search: Please Enter Event Code",
1872 "Invalid: Please Reenter Event Code", NULL,
1873 event_search_callback);
1876 /****************************************************************************
1878 ****************************************************************************/
1880 static void anomaly_search (void)
1882 modal_dialog ("Anomaly Search: Please Enter Event Code",
1883 "Invalid: Please Reenter Event Code", NULL,
1884 anomaly_search_callback);
1887 /****************************************************************************
1889 ****************************************************************************/
1891 static void anomaly_threshold (void)
1893 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1894 "Invalid: Please Reenter Threshold in Standard Deviations",
1895 NULL, anomaly_threshold_callback);
1898 /****************************************************************************
1900 ****************************************************************************/
1901 static void init_track_colors(void)
1907 gboolean dont_care[g_npids];
1910 * If we've already allocated the colors once, then in theory we should
1911 * just be able to re-order the GCs already created to match the new track
1912 * order; the track -> color mapping doesn't currently change at runtime.
1913 * However, it's easier just to allocate everything from fresh. As a nod in
1914 * the direction of politeness towards our poor abused X server, we at
1915 * least mop up the previously allocated GCs first, although in practice
1916 * even omitting this didn't seem to cause a problem.
1918 if (s_color != NULL ) {
1919 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
1921 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
1924 * First time through: allocate the array to hold the GCs.
1926 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
1930 * Go through and assign a color for each track.
1932 /* Setup entry 0 in the colormap as pure red (for selection) */
1933 s_color[0] = fg_red;
1935 for (i = 1; i < g_npids; i++) {
1937 * We compute the color from a hash of the thread name. That way we get
1938 * a distribution of different colors, and the same thread has the same
1939 * color across multiple data sets. Unfortunately, even though the
1940 * process name and thread id are invariant across data sets, the
1941 * process id isn't, so we want to exclude that from the hash. Since
1942 * the pid appears in parentheses after the process name and tid, we
1943 * can just stop at the '(' character.
1945 * We could create a substring and use the CLIB Jenkins hash, but given
1946 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1947 * just as good, and it's easiest just to compute it inline.
1949 label_char = get_track_label(g_pids[i].pid_value);
1951 while (*label_char != '\0' && *label_char != '(') {
1952 hash = hash * 33 + *label_char++;
1954 hash += hash >> 5; /* even out the lower order bits a touch */
1957 * OK, now we have our hash. We get the color by using the first three
1958 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1959 * and then use the fourth byte to choose one of R, G, B and mask this
1960 * one down. This ensures the color can't be too close to white and
1961 * therefore hard to see.
1963 * We also drop the top bit of the green, since bright green on its own
1964 * is hard to see against white. Generally we err on the side of
1965 * keeping it dark, rather than using the full spectrum of colors. This
1966 * does result in something of a preponderance of muddy colors and a
1967 * bit of a lack of cheery bright ones, but at least you can read
1968 * everything. It would be nice to do better.
1970 RGB[0] = (hash & 0xff000000) >> 16;
1971 RGB[1] = (hash & 0x007f0000) >> 8;
1972 RGB[2] = (hash & 0x0000ff00);
1973 RGB[hash % 3] &= 0x1fff;
1976 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1978 g_pids[i].color_index = i;
1983 * Actually allocate the colors in one bulk operation. We ignore the return
1986 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
1987 s_color, g_npids+1, FALSE, TRUE, dont_care);
1991 /****************************************************************************
1993 * Reorder the pid_index fields so the viewer "chases" the last selected
1995 ****************************************************************************/
1997 static void chase_event_etc(enum chase_mode mode)
1999 pid_sort_t *psp, *new_pidvec;
2003 ulong code_to_chase;
2004 ulong datum_to_chase;
2009 if (!s_last_selected_event) {
2010 infobox("No selected event",
2011 "\nPlease select an event and try again...\n");
2015 /* Clear all index assignments */
2017 for (i = 0; i < g_npids; i++) {
2019 pp->pid_index = 0xFFFFFFFF;
2023 ep = s_last_selected_event;
2024 code_to_chase = ep->code;
2025 datum_to_chase = ep->datum;
2026 pid_to_chase = ep->pid->pid_value;
2028 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
2031 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2032 if (ep >= g_events + g_nevents)
2042 if (ep->code == code_to_chase) {
2048 if (ep->datum == datum_to_chase) {
2054 if (ep->pid->pid_value == pid_to_chase) {
2060 infobox("BUG", "unknown mode in chase_event_etc\n");
2065 if (ep->pid->pid_index == 0xFFFFFFFF) {
2066 ep->pid->pid_index = pids_mapped;
2067 new_pidvec[pids_mapped].pid = ep->pid;
2068 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2069 new_pidvec[pids_mapped].color_index = 0;
2071 if (pids_mapped == g_npids)
2075 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2081 /* Pass 2, first-to-last, to collect stragglers */
2084 while (ep < g_events + g_nevents) {
2085 if (ep->pid->pid_index == 0xFFFFFFFF) {
2086 ep->pid->pid_index = pids_mapped;
2087 new_pidvec[pids_mapped].pid = ep->pid;
2088 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2089 new_pidvec[pids_mapped].color_index = 0;
2091 if (pids_mapped == g_npids)
2097 if (pids_mapped != g_npids) {
2098 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2102 g_pids = new_pidvec;
2105 * The new g_pids vector contains the "chase" sort, so we revert
2106 * the pid_index mapping to an identity map
2110 for (i = 0; i < g_npids; i++) {
2116 /* AutoScroll the PID axis so we show the first "chased" event */
2117 s_v1->first_pid_index = 0;
2118 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2119 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2120 init_track_colors();
2121 view1_display_when_idle();
2124 /****************************************************************************
2126 * Copy g_original_pids to g_pids, revert index mapping
2127 ****************************************************************************/
2128 static void unchase_event_etc(void)
2134 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
2136 /* Fix the pid structure index mappings */
2139 for (i = 0; i < g_npids; i++) {
2145 /* Scroll PID axis to the top */
2146 s_v1->first_pid_index = 0;
2147 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2148 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2149 init_track_colors();
2150 view1_display_when_idle();
2153 /****************************************************************************
2155 * To fit a reasonable-sized landscape mode plot onto letter-size paper,
2156 * scale everything by .75.
2157 ****************************************************************************/
2159 static void print_ps_header (v1_geometry_t *vp, char *filename)
2165 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2166 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2167 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2168 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2169 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2170 fprintf(s_printfp, "%%%%Origin: 0 0\n");
2171 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
2173 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2174 fprintf(s_printfp, "%%%%Pages: 1\n");
2175 fprintf(s_printfp, "%%%%Page: 1 1\n");
2176 fprintf(s_printfp, "%%%%EOF\n");
2177 fprintf(s_printfp, "/Times-Roman findfont\n");
2178 fprintf(s_printfp, "12 scalefont\n");
2179 fprintf(s_printfp, "setfont\n");
2180 fprintf(s_printfp, ".75 .75 scale\n");
2183 /****************************************************************************
2185 * Xcoordinate rotate and translate. We need to emit postscript that
2186 * has a reasonable aspect ratio for printing. To do that, we rotate the
2187 * intended picture by 90 degrees, using the standard 2D rotation
2190 * Xr = x*cos(theta) - y*sin(theta);
2191 * Yr = x*sin(theta) + y*cos(theta);
2193 * If we let theta = 90, this reduces to
2197 * Translate back to the origin in X by adding Ymax, yielding
2199 ****************************************************************************/
2201 static inline int xrt(int x, int y)
2203 return (s_v1->total_height - y);
2206 static inline int yrt(int x, int y)
2211 /****************************************************************************
2212 * print_screen_callback
2213 ****************************************************************************/
2215 static boolean print_screen_callback(char *filename)
2217 s_printfp = fopen (filename, "wt");
2219 if (s_printfp == NULL)
2223 * This variable allows us to magically turn the view1 display
2224 * code into a print-driver, with a minimum of fuss. The idea is to
2225 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2226 * the required value, aka s_print_offset.
2227 * Make sure to fix g2.h if you mess here, or vice versa.
2229 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2231 print_ps_header(s_v1, filename);
2233 display_pid_axis(s_v1);
2234 display_event_data(s_v1);
2235 display_time_axis(s_v1);
2241 /* For tactile feedback */
2242 view1_display_when_idle();
2246 int event_time_cmp (const void *a, const void *b)
2248 const event_t *e1 = a;
2249 const event_t *e2 = b;
2251 if (e1->time < e2->time)
2253 else if (e1->time > e2->time)
2258 /****************************************************************************
2260 ****************************************************************************/
2261 static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2268 delta = (ulonglong) (vp->last_time_interval);
2270 /* Make sure we don't push events to the left of the big bang */
2271 if (which == SLEW_LEFT_BUTTON) {
2272 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2273 pid_index = ep->pid->pid_index;
2274 pp = (g_pids + pid_index);
2277 if (ep->time < delta) {
2278 infobox("Slew Range Error",
2279 "\nCan't slew selected data left that far..."
2280 "\nEvents would preceed the Big Bang (t=0)...");
2287 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2288 pid_index = ep->pid->pid_index;
2289 pp = (g_pids + pid_index);
2292 if (which == SLEW_LEFT_BUTTON)
2299 /* Re-sort the events, to avoid screwing up the event display */
2300 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2302 /* De-select tracks */
2306 view1_display_when_idle();
2309 /****************************************************************************
2310 * view1_button_click_callback
2311 ****************************************************************************/
2313 static void view1_button_click_callback(GtkButton *item, gpointer data)
2315 enum view1_button_click click = (enum view1_button_click) data;
2317 ulonglong event_incdec;
2318 ulonglong current_width;
2319 ulonglong zoom_delta;
2321 current_width = s_v1->maxvistime - s_v1->minvistime;
2322 event_incdec = (current_width) / 3;
2324 if (event_incdec == 0LL)
2327 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2331 /* First PID to top of window */
2332 s_v1->first_pid_index = 0;
2333 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2334 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2338 s_v1->first_pid_index = g_npids - s_v1->npids;
2339 if (s_v1->first_pid_index < 0)
2340 s_v1->first_pid_index = 0;
2341 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2342 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2357 case CHASE_EVENT_BUTTON:
2358 chase_event_etc(CHASE_EVENT);
2361 case CHASE_DATUM_BUTTON:
2362 chase_event_etc(CHASE_DATUM);
2365 case CHASE_TRACK_BUTTON:
2366 chase_event_etc(CHASE_TRACK);
2369 case UNCHASE_BUTTON:
2370 unchase_event_etc();
2375 s_v1->minvistime = 0LL;
2376 s_v1->maxvistime = current_width;
2377 recompute_hscrollbar();
2381 s_v1->minvistime += zoom_delta;
2382 s_v1->maxvistime -= zoom_delta;
2383 recompute_hscrollbar();
2386 case SEARCH_AGAIN_BUTTON:
2388 event_search_internal();
2391 /* NOTE FALLTHROUGH */
2397 case ANOMALY_THRESHOLD_BUTTON:
2398 anomaly_threshold();
2401 case ANOMALY_NEXT_BUTTON:
2402 if (s_anomalycode) {
2403 anomaly_search_internal();
2406 /* NOTE FALLTHROUGH */
2408 case ANOMALY_BUTTON:
2412 case ZOOMOUT_BUTTON:
2413 if (zoom_delta == 0LL)
2416 if (s_v1->minvistime >= zoom_delta) {
2417 s_v1->minvistime -= zoom_delta;
2418 s_v1->maxvistime += zoom_delta;
2420 s_v1->minvistime = 0;
2421 s_v1->maxvistime += zoom_delta*2;
2424 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
2425 g_events[g_nevents-1].time * 9) {
2426 s_v1->minvistime = 0;
2427 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
2428 /* Single event? Make window 1s wide... */
2430 s_v1->maxvistime = 1000000;
2433 recompute_hscrollbar();
2437 ep = (g_events + g_nevents - 1);
2438 s_v1->maxvistime = ep->time + event_incdec/3;
2439 s_v1->minvistime = s_v1->maxvistime - current_width;
2440 if (s_v1->minvistime > s_v1->maxvistime)
2442 recompute_hscrollbar();
2445 case MORE_TRACES_BUTTON:
2446 /* Reduce the strip height to fit more traces on screen */
2447 s_v1->strip_height -= 1;
2449 if (s_v1->strip_height < 1) {
2450 s_v1->strip_height = 1;
2453 /* Recalculate the number of strips on the screen */
2454 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2456 recompute_vscrollbar();
2459 case LESS_TRACES_BUTTON:
2460 /* Increase the strip height to fit fewer on the screen */
2461 s_v1->strip_height += 1;
2462 if (s_v1->strip_height > 80) {
2463 s_v1->strip_height = 80;
2466 /* Recalculate the number of strips on the screen */
2467 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2469 recompute_vscrollbar();
2472 case FORWARD_BUTTON:
2473 srch_chase_dir = SRCH_CHASE_FORWARD;
2474 gtk_widget_hide (s_view1_forward_button);
2475 gtk_widget_show (s_view1_backward_button);
2478 case BACKWARD_BUTTON:
2479 srch_chase_dir = SRCH_CHASE_BACKWARD;
2480 gtk_widget_show (s_view1_forward_button);
2481 gtk_widget_hide (s_view1_backward_button);
2484 case SUMMARY_BUTTON:
2485 summary_mode = TRUE;
2486 gtk_widget_hide (s_view1_summary_button);
2487 gtk_widget_show (s_view1_nosummary_button);
2490 case NOSUMMARY_BUTTON:
2491 summary_mode = FALSE;
2492 gtk_widget_show (s_view1_summary_button);
2493 gtk_widget_hide (s_view1_nosummary_button);
2496 case SLEW_LEFT_BUTTON:
2497 case SLEW_RIGHT_BUTTON:
2498 if (s_v1->last_time_interval < 10e-9) {
2499 infobox("slew", "\nNo time interval set...\n");
2502 slew_tracks (s_v1, click);
2506 view1_display_when_idle();
2509 /****************************************************************************
2510 * view1_print_callback
2511 ****************************************************************************/
2513 void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2515 modal_dialog("Print Screen (PostScript format) to file:",
2516 "Invalid file: Print Screen to file:",
2517 "g2.ps", print_screen_callback);
2520 /****************************************************************************
2522 ****************************************************************************/
2524 static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2526 ulonglong current_width;
2528 current_width = (s_v1->maxvistime - s_v1->minvistime);
2530 s_v1->minvistime = (ulonglong)(adj->value);
2531 s_v1->maxvistime = s_v1->minvistime + current_width;
2533 view1_display_when_idle();
2536 g_print ("adj->lower = %.2f\n", adj->lower);
2537 g_print ("adj->upper = %.2f\n", adj->upper);
2538 g_print ("adj->value = %.2f\n", adj->value);
2539 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2540 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2541 g_print ("adj->page_size = %.2f\n", adj->page_size);
2545 /****************************************************************************
2547 ****************************************************************************/
2549 static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2551 s_v1->first_pid_index = (int)adj->value;
2552 view1_display_when_idle();
2555 void set_pid_ax_width(int width)
2557 s_v1->pid_ax_width = width;
2558 view1_display_when_idle();
2561 /****************************************************************************
2563 ****************************************************************************/
2565 void view1_init(void)
2567 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2568 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2570 s_v1->pid_ax_width = 80;
2571 s_v1->time_ax_height = 80;
2572 s_v1->time_ax_spacing = 100;
2573 s_v1->strip_height = 25;
2574 s_v1->pop_offset = 20;
2575 s_v1->pid_ax_offset = 34;
2576 s_v1->event_offset = 40;
2577 s_v1->total_height = c_view1_draw_height;
2578 s_v1->total_width = c_view1_draw_width;
2579 s_v1->first_pid_index = 0;
2580 s_v1->anomaly_threshold_stddevs =
2581 atof(getprop_default("anomaly_threshold_stddevs", "2.5"));
2582 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2585 s_v1->minvistime = 0;
2586 s_v1->maxvistime = 200;
2588 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2590 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2592 da = gtk_drawing_area_new();
2593 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2594 c_view1_draw_height);
2597 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2598 (GtkSignalFunc) motion_notify_event, NULL);
2601 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2602 (GtkSignalFunc) expose_event, NULL);
2604 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2605 (GtkSignalFunc) configure_event, NULL);
2607 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2608 (GtkSignalFunc) button_press_event, NULL);
2610 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2611 (GtkSignalFunc) button_press_event, NULL);
2613 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2614 (GtkSignalFunc) button_press_event, NULL);
2616 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2617 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2618 | GDK_BUTTON_MOTION_MASK);
2621 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2623 g_font = gdk_font_load ("8x13");
2624 if (g_font == NULL) {
2625 g_error("Couldn't load 8x13 font...\n");
2627 gdk_font_ref(g_font);
2630 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2632 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
2633 0.0 /* minimum value */,
2634 2000.0 /* maximum value */,
2635 0.1 /* step increment */,
2636 10.0/* page increment */,
2637 10.0/* page size */);
2639 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2641 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2642 GTK_SIGNAL_FUNC (view1_vscroll),
2643 (gpointer)s_view1_vscroll);
2645 s_view1_topbutton = gtk_button_new_with_label("Top");
2646 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2648 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2649 GTK_SIGNAL_FUNC(view1_button_click_callback),
2650 (gpointer) TOP_BUTTON);
2652 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2653 GTK_SIGNAL_FUNC(view1_button_click_callback),
2654 (gpointer) BOTTOM_BUTTON);
2656 /* More Traces button and Less Traces button */
2657 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2658 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2659 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
2660 GTK_SIGNAL_FUNC(view1_button_click_callback),
2661 (gpointer) MORE_TRACES_BUTTON);
2662 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
2663 GTK_SIGNAL_FUNC(view1_button_click_callback),
2664 (gpointer) LESS_TRACES_BUTTON);
2667 /* Trick to bottom-justify the menu: */
2668 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2669 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2674 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2677 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2680 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2683 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2686 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2689 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2692 /* Time axis menu */
2694 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2696 s_view1_startbutton = gtk_button_new_with_label("Start");
2698 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2700 s_view1_searchbutton = gtk_button_new_with_label("Search");
2701 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2703 s_view1_anomalybutton = gtk_button_new_with_label("Anomaly");
2704 s_view1_anomalynextbutton = gtk_button_new_with_label("Next Anomaly");
2705 s_view1_anomalythresholdbutton =
2706 gtk_button_new_with_label ("Anomaly Threshold");
2708 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2710 s_view1_endbutton = gtk_button_new_with_label("End");
2712 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2713 GTK_SIGNAL_FUNC(view1_button_click_callback),
2714 (gpointer) START_BUTTON);
2716 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2717 GTK_SIGNAL_FUNC(view1_button_click_callback),
2718 (gpointer) ZOOMIN_BUTTON);
2720 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2721 GTK_SIGNAL_FUNC(view1_button_click_callback),
2722 (gpointer) SEARCH_BUTTON);
2724 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2725 GTK_SIGNAL_FUNC(view1_button_click_callback),
2726 (gpointer) SEARCH_AGAIN_BUTTON);
2728 gtk_signal_connect (GTK_OBJECT(s_view1_anomalybutton), "clicked",
2729 GTK_SIGNAL_FUNC(view1_button_click_callback),
2730 (gpointer) ANOMALY_BUTTON);
2732 gtk_signal_connect (GTK_OBJECT(s_view1_anomalynextbutton), "clicked",
2733 GTK_SIGNAL_FUNC(view1_button_click_callback),
2734 (gpointer) ANOMALY_NEXT_BUTTON);
2736 gtk_signal_connect (GTK_OBJECT(s_view1_anomalythresholdbutton),
2737 "clicked", GTK_SIGNAL_FUNC(view1_button_click_callback),
2738 (gpointer) ANOMALY_THRESHOLD_BUTTON);
2740 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2741 GTK_SIGNAL_FUNC(view1_button_click_callback),
2742 (gpointer) ZOOMOUT_BUTTON);
2744 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2745 GTK_SIGNAL_FUNC(view1_button_click_callback),
2746 (gpointer) END_BUTTON);
2748 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
2749 0.0 /* minimum value */,
2750 2000.0 /* maximum value */,
2751 0.1 /* step increment */,
2752 10.0/* page increment */,
2753 10.0/* page size */);
2755 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2757 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2758 GTK_SIGNAL_FUNC (view1_hscroll),
2759 (gpointer)s_view1_hscroll);
2761 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2764 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2767 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2770 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2773 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalybutton,
2775 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalynextbutton,
2777 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2780 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2783 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2786 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2789 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2793 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2795 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2797 s_view1_nextbutton = gtk_button_new_with_label("Next");
2799 s_view1_delbutton = gtk_button_new_with_label("Del");
2801 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2803 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2805 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2807 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2809 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2810 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2812 s_view1_summary_button = gtk_button_new_with_label("Summary");
2813 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2815 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2816 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2818 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2819 GTK_SIGNAL_FUNC(view1_button_click_callback),
2820 (gpointer) SNAP_BUTTON);
2822 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2823 GTK_SIGNAL_FUNC(view1_button_click_callback),
2824 (gpointer) NEXT_BUTTON);
2826 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2827 GTK_SIGNAL_FUNC(view1_button_click_callback),
2828 (gpointer) DEL_BUTTON);
2830 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
2831 GTK_SIGNAL_FUNC(view1_button_click_callback),
2832 (gpointer) CHASE_EVENT_BUTTON);
2834 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
2835 GTK_SIGNAL_FUNC(view1_button_click_callback),
2836 (gpointer) CHASE_DATUM_BUTTON);
2838 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
2839 GTK_SIGNAL_FUNC(view1_button_click_callback),
2840 (gpointer) CHASE_TRACK_BUTTON);
2842 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2843 GTK_SIGNAL_FUNC(view1_button_click_callback),
2844 (gpointer) UNCHASE_BUTTON);
2846 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2847 GTK_SIGNAL_FUNC(view1_button_click_callback),
2848 (gpointer) FORWARD_BUTTON);
2850 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2851 GTK_SIGNAL_FUNC(view1_button_click_callback),
2852 (gpointer) BACKWARD_BUTTON);
2854 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2855 GTK_SIGNAL_FUNC(view1_button_click_callback),
2856 (gpointer) SUMMARY_BUTTON);
2858 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2859 GTK_SIGNAL_FUNC(view1_button_click_callback),
2860 (gpointer) NOSUMMARY_BUTTON);
2862 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
2863 GTK_SIGNAL_FUNC(view1_button_click_callback),
2864 (gpointer) SLEW_LEFT_BUTTON);
2866 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
2867 GTK_SIGNAL_FUNC(view1_button_click_callback),
2868 (gpointer) SLEW_RIGHT_BUTTON);
2870 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2873 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2876 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2879 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2882 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2885 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2888 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2891 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2894 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2897 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2900 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2903 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2906 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2907 s_view1_time_slew_left_button,
2910 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2911 s_view1_time_slew_right_button,
2914 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2915 s_view1_anomalythresholdbutton,
2918 s_view1_label = gtk_label_new(NULL);
2920 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2923 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2926 gtk_widget_show_all (s_view1_vbox);
2927 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2928 gtk_widget_grab_focus(da);
2930 gtk_widget_hide (s_view1_forward_button);
2931 gtk_widget_hide (summary_mode ? s_view1_summary_button
2932 : s_view1_nosummary_button);
2934 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2936 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2939 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2941 &bg_white, zi_x_hot,
2943 gdk_pixmap_unref (zi_source);
2944 gdk_pixmap_unref (zi_mask);
2946 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2949 /****************************************************************************
2951 ****************************************************************************/
2953 void line_print (int x1, int y1, int x2, int y2)
2955 fprintf(s_printfp, "newpath\n");
2956 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
2957 yrt(x1, s_v1->total_height - y1));
2959 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2960 yrt (x2, s_v1->total_height - y2));
2961 fprintf(s_printfp, "1 setlinewidth\n");
2962 fprintf(s_printfp, "stroke\n");
2965 /****************************************************************************
2967 ****************************************************************************/
2968 GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2971 if (function == TBOX_PRINT_BOXED) {
2975 if ((function == TBOX_PRINT_BOXED) ||
2976 (function == TBOX_PRINT_EVENT)) {
2978 fprintf(s_printfp, "newpath\n");
2979 fprintf(s_printfp, "0 setlinewidth\n");
2980 fprintf(s_printfp, "%d %d moveto\n",
2981 xrt(rp->x, s_v1->total_height - rp->y),
2982 yrt(rp->x, s_v1->total_height - rp->y));
2984 fprintf(s_printfp, "%d %d lineto\n",
2985 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
2986 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
2988 fprintf(s_printfp, "%d %d lineto\n",
2989 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
2990 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
2992 fprintf(s_printfp, "%d %d lineto\n",
2993 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
2994 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
2996 fprintf(s_printfp, "%d %d lineto\n",
2997 xrt(rp->x, s_v1->total_height - rp->y),
2998 yrt(rp->x, s_v1->total_height - rp->y));
3000 fprintf(s_printfp, "stroke\n");
3003 if ((function == TBOX_PRINT_BOXED) ||
3004 (function == TBOX_PRINT_PLAIN)) {
3006 fprintf(s_printfp, "newpath\n");
3007 fprintf(s_printfp, "%d %d moveto\n",
3008 xrt(x, s_v1->total_height - (y-2)),
3009 yrt(x, s_v1->total_height - (y-2)));
3010 fprintf(s_printfp, "gsave\n");
3011 fprintf(s_printfp, "90 rotate\n");
3012 fprintf(s_printfp, "(%s) show\n", s);
3013 fprintf(s_printfp, "grestore\n");
3019 /****************************************************************************
3020 * tbox - draws an optionally boxed string whose lower lefthand
3021 * corner is at (x, y). As usual, Y is backwards.
3022 ****************************************************************************/
3024 GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
3026 static GdkRectangle update_rect;
3027 gint lbearing, rbearing, width, ascent, descent;
3029 gdk_string_extents (g_font, s,
3030 &lbearing, &rbearing,
3031 &width, &ascent, &descent);
3034 * If we have enough room to display full size events, then just
3035 * use the BOXED function instead of the EVENT function.
3037 if (s_v1->strip_height > 9) {
3039 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
3040 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
3041 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
3049 case TBOX_DRAW_BOXED:
3050 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3051 x, y - (ascent+descent+3), width + 2,
3052 ascent + descent + 3);
3054 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3055 x, y - (ascent+descent+3), width + 2,
3056 ascent + descent + 3);
3058 gdk_draw_string (pm, g_font, da->style->black_gc,
3059 x + 1, y - 1, (const gchar *)s);
3060 /* NOTE FALLTHROUGH */
3061 case TBOX_GETRECT_BOXED:
3063 update_rect.y = y -(ascent+descent+3);
3064 update_rect.width = width + 3;
3065 update_rect.height = ascent + descent + 4;
3066 if (function == TBOX_DRAW_BOXED)
3067 gtk_widget_draw (da, &update_rect);
3070 case TBOX_DRAW_EVENT:
3071 /* We have a small event to draw...no text */
3072 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3074 /* NOTE FALLTHROUGH */
3075 case TBOX_GETRECT_EVENT:
3077 update_rect.y = y - 1;
3078 update_rect.width = 4;
3079 update_rect.height = 4;
3080 if (function == TBOX_DRAW_EVENT)
3081 gtk_widget_draw (da, &update_rect);
3085 case TBOX_DRAW_PLAIN:
3087 gdk_draw_string (pm, g_font, da->style->black_gc,
3088 x + 1, y - 1, (const gchar *)s);
3089 /* NOTE FALLTHROUGH */
3090 case TBOX_GETRECT_PLAIN:
3092 update_rect.y = y -(ascent+descent+1);
3093 update_rect.width = width;
3094 update_rect.height = ascent + descent;
3095 if (function == TBOX_DRAW_PLAIN)
3096 gtk_widget_draw (da, &update_rect);
3099 case TBOX_PRINT_BOXED:
3101 update_rect.y = y -(ascent+descent+3);
3102 update_rect.width = width + 3;
3103 update_rect.height = ascent + descent + 4;
3104 /* note fallthrough */
3105 case TBOX_PRINT_PLAIN:
3106 return(tbox_print(s, x, y, function, &update_rect));
3108 case TBOX_PRINT_EVENT:
3109 /* We have a small event box to print...no text */
3111 update_rect.y = y - 1;
3112 update_rect.width = 4;
3113 update_rect.height = 4;
3114 return(tbox_print(s, x, y, function, &update_rect));
3116 return(&update_rect);
3119 /****************************************************************************
3122 * For lines there is a primitive batching facility, that doesn't update
3123 * the drawing area until the batch is complete. This is handy for drawing
3124 * the pid axis and for summary mode.
3126 * line_batch_mode contains the state for this:
3128 * BATCH_OFF: no batching, update for every line
3129 * BATCH_NEW: just entered a batch, so initialize the area to update from
3131 * BATCH_EXISTING: have drawn at least one line in batch mode, so the update
3132 * area should only be expanded from now on to include the
3133 * union of the "rectangular hull" of all lines
3134 ****************************************************************************/
3136 static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
3137 static int line_batch_count;
3138 static int line_minx, line_miny, line_maxx, line_maxy;
3140 void line_batch_start (void)
3142 line_batch_mode = BATCH_NEW;
3143 line_batch_count = 0;
3146 void line_batch_end (void)
3148 GdkRectangle update_rect;
3149 if (line_batch_count > 0) {
3150 update_rect.x = line_minx;
3151 update_rect.y = line_miny;
3152 update_rect.width = (line_maxx - line_minx) + 1;
3153 update_rect.height = (line_maxy - line_miny) + 1;
3154 gtk_widget_draw (da, &update_rect);
3156 line_batch_mode = BATCH_OFF;
3159 void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
3161 GdkRectangle update_rect;
3165 case LINE_DRAW_BLACK:
3166 gc = da->style->black_gc;
3169 case LINE_DRAW_WHITE:
3170 gc = da->style->white_gc;
3174 line_print (x1, y1, x2, y2);
3178 gdk_draw_line (pm, gc, x1, y1, x2, y2);
3180 switch (line_batch_mode) {
3184 update_rect.width = (x2-x1) + 1;
3185 update_rect.height = (y2-y1) + 1;
3186 gtk_widget_draw (da, &update_rect);
3194 line_batch_mode = BATCH_EXISTING;
3195 line_batch_count = 1;
3198 case BATCH_EXISTING:
3213 /****************************************************************************
3215 ****************************************************************************/
3217 static void display_pid_axis(v1_geometry_t *vp)
3219 int y, i, label_tick;
3220 int last_printed_y = -vp->strip_height;
3226 /* No pids yet? Outta here */
3232 for (i = 0; i < vp->npids; i++) {
3233 pid_index = vp->first_pid_index + i;
3234 if (pid_index >= g_npids)
3237 pp = (g_pids + pid_index);
3239 set_color(pid_index);
3241 label_fmt = get_track_label(pp->pid_value);
3242 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
3244 y = i*vp->strip_height + vp->pid_ax_offset;
3247 * Have we incremented enough space to have another label not
3248 * overlap the previous label?
3250 if (y - last_printed_y > 9) {
3252 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
3257 * And let the line stick out a bit more to indicate this label
3258 * relates to the following line.
3266 /* Draw axis line, but only if the lines aren't too close together */
3267 if (vp->strip_height > 4) {
3268 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
3269 vp->total_width, y+4*s_print_offset,
3270 LINE_DRAW_BLACK+s_print_offset);
3274 set_color(COLOR_DEFAULT);
3278 /****************************************************************************
3279 * view1_read_events_callback
3280 * New event data just showed up, reset a few things.
3281 ****************************************************************************/
3283 void view1_read_events_callback(void)
3287 s_v1->first_pid_index = 0;
3289 max_vis_index = 300;
3290 if (max_vis_index > g_nevents)
3291 max_vis_index = g_nevents-1;
3293 s_v1->minvistime = 0LL;
3294 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
3295 /* Single event? Make the initial display 1s wide */
3297 s_v1->maxvistime = 1000000;
3300 s_last_selected_event = 0;
3302 init_track_colors();
3304 recompute_hscrollbar();
3305 recompute_vscrollbar();
3308 /****************************************************************************
3309 * display_event_data
3310 ****************************************************************************/
3312 static void display_event_data(v1_geometry_t *vp)
3319 double time_per_pixel;
3321 GdkRectangle *print_rect;
3324 /* Happens if one loads the event def header first, for example. */
3328 time_per_pixel = dtime_per_pixel(vp);
3330 start_index = find_event_index (vp->minvistime);
3332 /* Scrolled too far right? */
3333 if (start_index >= g_nevents)
3336 ep = (g_events + start_index);
3338 if (s_print_offset || summary_mode) {
3339 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3346 while (ep < (g_events + g_nevents) &&
3347 (ep->time < vp->maxvistime)) {
3348 pid_index = ep->pid->pid_index;
3349 set_color(pid_index);
3351 /* First filter: pid out of range */
3352 if ((pid_index < vp->first_pid_index) ||
3353 (pid_index >= vp->first_pid_index + vp->npids)) {
3358 /* Second filter: event hidden */
3359 edp = find_event_definition (ep->code);
3360 if (!edp->selected) {
3367 pid_index -= vp->first_pid_index;
3369 y = pid_index*vp->strip_height + vp->event_offset;
3371 x = vp->pid_ax_width +
3372 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3374 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3379 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3380 if (ep->flags & EVENT_FLAG_SELECT) {
3381 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3383 sprintf(tmpbuf, edp->name);
3384 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3385 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3388 sprintf(tmpbuf, "SEARCH RESULT");
3390 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3391 TBOX_DRAW_BOXED+s_print_offset);
3392 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3393 if (last_x_used != NULL)
3394 last_x_used[pid_index] = x + print_rect->width;
3397 int delta = vp->strip_height / 3;
3400 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3401 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3402 last_x_used[pid_index] = x + 1;
3404 sprintf(tmpbuf, "%ld", ep->code);
3405 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3406 if (last_x_used != NULL)
3407 last_x_used[pid_index] = x + print_rect->width;
3413 g_free(last_x_used);
3415 set_color(COLOR_DEFAULT);
3418 /****************************************************************************
3420 ****************************************************************************/
3422 static void display_clear(void)
3424 GdkRectangle update_rect;
3426 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3427 0, 0, da->allocation.width,
3428 da->allocation.height);
3432 update_rect.width = da->allocation.width;
3433 update_rect.height = da->allocation.height;
3435 gtk_widget_draw (da, &update_rect);
3438 /****************************************************************************
3440 ****************************************************************************/
3442 static void display_time_axis(v1_geometry_t *vp)
3445 int xoffset, nticks;
3447 double unit_divisor;
3450 double time_per_pixel;
3452 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3454 x = vp->pid_ax_width;
3456 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3458 time_per_pixel = dtime_per_pixel(vp);
3461 unit_divisor = 1.00;
3463 if ((vp->maxvistime / unit_divisor) > 1000) {
3465 unit_divisor = 1000.00;
3468 if ((vp->maxvistime / unit_divisor) > 1000) {
3470 unit_divisor = 1000.00*1000.00;
3472 if ((vp->maxvistime / unit_divisor) > 1000) {
3474 unit_divisor = 1000.00*1000.00*1000.00;
3478 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3482 for (i = 0; i < nticks; i++) {
3484 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3486 time = (double)(x + xoffset - vp->pid_ax_width);
3487 time *= time_per_pixel;
3488 time += (double)(vp->minvistime);
3489 time /= unit_divisor;
3491 sprintf (tmpbuf, "%.2f%s", time, units);
3493 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3495 xoffset += vp->time_ax_spacing;
3499 /****************************************************************************
3501 * Forget about any temporary displays, they're gone now...
3502 ****************************************************************************/
3504 static void clear_scoreboard(void)
3506 s_result_up = FALSE;
3509 /****************************************************************************
3511 ****************************************************************************/
3513 void view1_display(void)
3516 display_pid_axis(s_v1);
3517 display_event_data(s_v1);
3518 display_time_axis(s_v1);
3522 static gint idle_tag;
3524 /****************************************************************************
3525 * view1_display_eventually
3526 ****************************************************************************/
3528 static void view1_display_eventually(void)
3530 gtk_idle_remove(idle_tag);
3536 /****************************************************************************
3537 * view1_display_when_idle
3538 ****************************************************************************/
3540 void view1_display_when_idle(void)
3542 if (idle_tag == 0) {
3543 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3547 /****************************************************************************
3549 ****************************************************************************/
3551 void view1_about (char *tmpbuf)
3556 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3557 s_v1->minvistime, s_v1->maxvistime);
3558 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
3559 s_v1->strip_height);
3561 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3564 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);