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;
167 /* The active geometry object */
168 static v1_geometry_t s_v1record;
169 static v1_geometry_t *s_v1 = &s_v1record;
171 /* The color array */
172 static GdkColor *s_color;
175 typedef struct snapshot {
176 struct snapshot *next;
177 /* Screen geometry */
178 v1_geometry_t geometry;
179 boolean show_event[NEVENTS];
182 * Note: not worth recomputing the vertical scrollbar, just save
185 gfloat vscroll_value;
186 boolean summary_mode;
190 static snapshot_t *s_snapshots;
191 static snapshot_t *s_cursnap;
192 static event_t *s_last_selected_event;
195 * various widgets, see the box heirarchy chart above
196 * The toolkit keeps track of these things, we could lose many of
199 static GtkWidget *s_view1_vmenubox;
200 static GtkWidget *s_view1_topbutton;
201 static GtkWidget *s_view1_bottombutton;
202 static GtkWidget *s_view1_more_traces_button;
203 static GtkWidget *s_view1_less_traces_button;
205 static GtkWidget *s_view1_hmenubox;
206 static GtkWidget *s_view1_hmenubox2;
207 static GtkWidget *s_view1_startbutton;
208 static GtkWidget *s_view1_zoominbutton;
209 static GtkWidget *s_view1_searchbutton;
210 static GtkWidget *s_view1_srchagainbutton;
211 static GtkWidget *s_view1_anomalybutton;
212 static GtkWidget *s_view1_anomalynextbutton;
213 static GtkWidget *s_view1_zoomoutbutton;
214 static GtkWidget *s_view1_endbutton;
216 static GtkWidget *s_view1_snapbutton;
217 static GtkWidget *s_view1_nextbutton;
218 static GtkWidget *s_view1_delbutton;
220 static GtkWidget *s_view1_chase_event_button;
221 static GtkWidget *s_view1_chase_datum_button;
222 static GtkWidget *s_view1_chase_track_button;
223 static GtkWidget *s_view1_unchasebutton;
225 static GtkWidget *s_view1_forward_button;
226 static GtkWidget *s_view1_backward_button;
228 static GtkWidget *s_view1_summary_button;
229 static GtkWidget *s_view1_nosummary_button;
231 static GtkWidget *s_view1_time_slew_right_button;
232 static GtkWidget *s_view1_time_slew_left_button;
234 static GtkWidget *s_view1_anomalythresholdbutton;
236 static GtkWidget *s_view1_hscroll;
237 static GtkObject *s_view1_hsadj;
239 static GtkWidget *s_view1_vscroll;
240 static GtkObject *s_view1_vsadj;
242 static GtkWidget *s_view1_label;
247 static ulong s_srchcode; /* search event code */
248 static ulong s_anomalycode; /* anomaly event code */
249 static int s_srchindex; /* last hit was at this event index */
250 static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */
251 static boolean s_srchfail_up; /* The status line "Search Failed" is up */
252 static int srch_chase_dir; /* search/chase dir, 0=>forward */
258 static int s_print_offset; /* Magic offset added to line, tbox fn codes */
259 static FILE *s_printfp;
262 * Forward reference prototypes
264 static void display_pid_axis(v1_geometry_t *vp);
265 static void display_event_data(v1_geometry_t *vp);
266 static void display_time_axis(v1_geometry_t *vp);
267 static void view1_button_click_callback(GtkButton *item, gpointer data);
273 gint c_view1_draw_width;
274 gint c_view1_draw_height;
277 * Zoom-In / Time Ruler cursor
284 static unsigned char zi_bits[] = {
285 0x00, 0x00, 0x00, 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, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
288 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
289 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
290 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
291 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
292 0x00, 0x00, 0x82, 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, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
297 static unsigned char zi_bkgd[] = {
298 0x00, 0x00, 0x00, 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, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
301 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
302 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
303 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
304 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
305 0x00, 0x00, 0x82, 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, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
310 static GdkCursor *zi_cursor;
311 static GdkPixmap *zi_source, *zi_mask;
314 * Frequently-used small computations, best
315 * done correctly once and instantiated.
318 /****************************************************************************
320 ****************************************************************************/
322 static inline double dtime_per_pixel(v1_geometry_t *vp)
324 return ((double)(vp->maxvistime - vp->minvistime)) /
325 ((double)(vp->total_width - vp->pid_ax_width));
328 /****************************************************************************
330 * Changes the status line. Pass "" to clear the status line.
331 ****************************************************************************/
333 void message_line (char *s)
335 gtk_label_set_text (GTK_LABEL(s_view1_label), s);
338 /****************************************************************************
340 * Changes the window title to include the specified filename.
341 ****************************************************************************/
343 void set_window_title (const char *filename)
346 snprintf(title, sizeof(title), "g2 (%s)", filename);
347 gtk_window_set_title(GTK_WINDOW(g_mainwindow), title);
350 /****************************************************************************
351 * recompute_hscrollbar
352 * Adjust the horizontal scrollbar's adjustment object.
354 * GtkAdjustments are really cool, but have to be set up exactly
355 * right or the various client objects screw up completely.
357 * Note: this function is *not* called when the user clicks the scrollbar.
358 ****************************************************************************/
360 static void recompute_hscrollbar (void)
362 ulonglong current_width;
363 ulonglong event_incdec;
370 ep = (g_events + (g_nevents-1));
371 current_width = s_v1->maxvistime - s_v1->minvistime;
372 event_incdec = (current_width) / 6;
374 adj = GTK_ADJUSTMENT(s_view1_hsadj);
377 * Structure member decoder ring
378 * -----------------------------
379 * lower the minimum possible value
380 * value the current value
381 * upper the maximum possible value
382 * step_increment end button click increment
383 * page_increment click in trough increment
384 * page_size size of currently visible area
387 adj->lower = (gfloat)0.00;
388 adj->value = (gfloat)s_v1->minvistime;
390 /* Minor click: move about 1/6 of a page */
391 adj->step_increment = (gfloat)event_incdec;
393 /* Major click: move about 1/3 of a page. */
394 adj->page_increment = (gfloat)(2*event_incdec);
396 /* allow the user to go a bit past the end */
397 adj->upper = adj->page_increment/3 + (gfloat)(ep->time);
398 adj->page_size = (gfloat)(current_width);
401 * Tell all clients (e.g. the visible scrollbar) to
402 * make themselves look right
404 gtk_adjustment_changed(adj);
405 gtk_adjustment_value_changed(adj);
408 /****************************************************************************
409 * recompute_vscrollbar
410 * Ditto, for the vertical scrollbar
411 ****************************************************************************/
413 static void recompute_vscrollbar (void)
417 adj = GTK_ADJUSTMENT(s_view1_vsadj);
419 adj->lower = (gfloat)0.00;
420 adj->upper = (gfloat)g_npids;
421 adj->value = (gfloat)0.00;
422 adj->step_increment = 1.00;
423 adj->page_increment = (gfloat)(s_v1->npids / 3);
424 adj->page_size = (gfloat)s_v1->npids;
425 gtk_adjustment_changed(adj);
426 gtk_adjustment_value_changed(adj);
429 /****************************************************************************
430 * format_popbox_string
431 ****************************************************************************/
433 elog_main_t elog_main;
435 void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp)
440 sprintf(tmpbuf,"%d:", ep->code);
442 if (ep->flags & EVENT_FLAG_CLIB) {
446 eep = get_clib_event (ep->datum);
448 s = format (0, "%U", format_elog_event, &elog_main, eep);
449 memcpy (tmpbuf, s, vec_len(s));
450 tmpbuf[vec_len(s)] = 0;
455 snprintf(tmpbuf, len, "%s", edp->name);
457 /* Make sure there's a real format string. If so, add it */
460 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
461 /* %s only supported for cpel files */
463 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
464 edp->format, strtab_ref(ep->datum));
466 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
467 edp->format, ep->datum);
475 /****************************************************************************
477 ****************************************************************************/
479 static void add_snapshot(void)
482 snapshot_t *new = g_malloc(sizeof(snapshot_t));
484 memcpy(&new->geometry, s_v1, sizeof(new->geometry));
485 for (i = 0; i < NEVENTS; i++) {
486 new->show_event[i] = g_eventdefs[i].selected;
488 new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids);
489 memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids);
490 new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value;
491 new->summary_mode = summary_mode;
492 new->color_mode = color_mode;
495 new->next = s_snapshots;
504 /****************************************************************************
506 ****************************************************************************/
508 static void next_snapshot(void)
516 infobox("No snapshots", "\nNo snapshots in the ring...\n");
520 next = s_cursnap->next;
526 memcpy(s_v1, &next->geometry, sizeof(next->geometry));
527 for (i = 0; i < NEVENTS; i++) {
528 g_eventdefs[i].selected = next->show_event[i];
530 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
531 color_mode = next->color_mode;
533 * Update summary mode via a button push so that the button state is
534 * updated accordingly. (Should ideally clean up the view/controller
535 * separation properly one day.)
537 if (summary_mode != next->summary_mode) {
538 view1_button_click_callback
539 (NULL, (gpointer)(unsigned long long)
540 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
543 /* Fix the pid structure index mappings */
546 for (i = 0; i < g_npids; i++) {
551 GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value;
552 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
553 recompute_hscrollbar();
554 pointsel_next_snapshot();
555 view1_display_when_idle();
559 /****************************************************************************
561 ****************************************************************************/
563 static void del_snapshot(void)
569 infobox("No snapshots", "\nNo snapshots to delete...\n");
576 while (this && this != s_cursnap) {
581 if (this != s_cursnap) {
582 infobox("BUG", "\nSnapshot AWOL!\n");
586 s_cursnap = this->next;
588 /* middle of the list? */
590 prev->next = this->next;
591 g_free(this->pidvec);
593 } else { /* start of the list */
594 s_snapshots = this->next;
595 g_free(this->pidvec);
599 /* Note: both will be NULL after last delete */
600 if (s_cursnap == NULL)
601 s_cursnap = s_snapshots;
604 /****************************************************************************
607 * VERY primitive right now - not endian or version independent, and only
608 * writes to "snapshots.g2" in the current directory
609 ****************************************************************************/
610 static void write_snapshot(void)
617 if (s_snapshots == NULL) {
618 error = "No snapshots defined";
623 file = fopen("snapshots.g2", "w");
625 error = "Unable to open snapshots.g2";
630 * Simply serialize the arch-dependent binary data, without a care in the
631 * world. Don't come running to me if you try to read it and crash.
633 for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) {
634 if (fwrite(&snap->geometry,
635 sizeof(snap->geometry), 1, file) != 1 ||
636 fwrite(&snap->show_event,
637 sizeof(snap->show_event), 1, file) != 1 ||
639 sizeof(pid_sort_t) * g_npids, 1, file) != 1 ||
640 fwrite(&snap->vscroll_value,
641 sizeof(snap->vscroll_value), 1, file) != 1 ||
642 fwrite(&snap->summary_mode,
643 sizeof(snap->summary_mode), 1, file) != 1 ||
644 fwrite(&snap->color_mode,
645 sizeof(snap->color_mode), 1, file) != 1) {
646 error = "Error writing data";
653 error = "Unable to close file";
658 infobox(error, strerror(errno));
661 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
667 /****************************************************************************
670 * VERY primitive right now - not endian or version independent, and only reads
671 * from "snapshots.g2" in the current directory
672 ****************************************************************************/
673 static void read_snapshot(void)
676 snapshot_t *snap, *next_snap;
677 snapshot_t *new_snaps = NULL;
679 int len, i, records = 0;
682 file = fopen("snapshots.g2", "r");
684 error = "Unable to open snapshots.g2";
688 * Read in the snapshots and link them together. We insert them backwards,
689 * but that's tolerable. If the data is in anyway not what we expect, we'll
690 * probably crash. Sorry.
692 while (!error && !feof(file)) {
693 snap = g_malloc(sizeof(*snap));
694 snap->pidvec = NULL; /* so we can free this if there's an error */
696 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
702 /* insert into list straight away */
703 snap->next = new_snaps;
707 error = "Problem reading first item from file";
710 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
711 error = "Problem reading second item from file";
714 len = sizeof(pid_sort_t) * g_npids;
715 snap->pidvec = g_malloc(len);
716 if (fread(snap->pidvec, len, 1, file) != 1) {
717 error = "Problem reading third item from file";
720 if (fread(&snap->vscroll_value,
721 sizeof(snap->vscroll_value), 1, file) != 1 ||
722 fread(&snap->summary_mode,
723 sizeof(snap->summary_mode), 1, file) != 1 ||
724 fread(&snap->color_mode,
725 sizeof(snap->color_mode), 1, file) != 1) {
726 error = "Problem reading final items from file";
731 * Fix up the pointers from the sorted pid vector back into our pid
732 * data objects, by walking the linked list of pid_data_t objects for
733 * every one looking for a match. This is O(n^2) grossness, but in real
734 * life there aren't that many pids, and it seems zippy enough.
736 for (i = 0; i < g_npids; i++) {
737 for (pp = g_pid_data_list; pp != NULL; pp = pp->next) {
738 if (pp->pid_value == snap->pidvec[i].pid_value) {
743 snap->pidvec[i].pid = pp;
745 error = "Snapshot file referenced unknown pids";
755 error = "Unable to close file";
761 * Problem - clear up any detritus
763 infobox(error, strerror(errno));
764 for (snap = new_snaps; snap != NULL; snap = next_snap) {
765 next_snap = snap->next;
767 g_free(snap->pidvec);
771 * Success! trash the old snapshots and replace with the new
773 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
774 next_snap = snap->next;
775 g_free(snap->pidvec);
779 s_cursnap = s_snapshots = new_snaps;
783 infobox(error, strerror(errno));
786 snprintf(buf, sizeof(buf),
787 "Read %d snapshots from snapshots.g2", records);
792 /****************************************************************************
795 * Set the color for the specified pid_index, or COLOR_DEFAULT to return it
796 * to the usual black.
797 ****************************************************************************/
798 #define COLOR_DEFAULT (-1)
799 static void set_color(int pid_index)
803 psp = (g_pids + pid_index);
806 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
807 else if (pid_index == COLOR_DEFAULT || !color_mode) {
808 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
810 gdk_gc_set_foreground(da->style->black_gc,
811 &s_color[g_pids[pid_index].color_index]);
815 /****************************************************************************
816 * toggle_event_select
817 ****************************************************************************/
819 static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
821 int pid_index, start_index;
824 GdkRectangle hit_rect;
829 double time_per_pixel;
834 time_per_pixel = dtime_per_pixel(vp);
836 start_index = find_event_index (vp->minvistime);
839 if (start_index >= g_nevents)
843 * To see if the mouse hit a visible event, use a variant
844 * of the event display loop.
847 hit_rect.x = (int)event->x;
848 hit_rect.y = (int)event->y;
852 ep = (g_events + start_index);
854 while ((ep->time < vp->maxvistime) &&
855 (ep < (g_events + g_nevents))) {
856 pid_index = ep->pid->pid_index;
858 /* First filter: pid out of range */
859 if ((pid_index < vp->first_pid_index) ||
860 (pid_index >= vp->first_pid_index + vp->npids)) {
865 /* Second filter: event hidden */
866 edp = find_event_definition (ep->code);
867 if (!edp->selected) {
873 * At this point, we know that the point is at least on the
874 * screen. See if the mouse hit within the bounding box
878 * $$$$ maybe keep looping until off the edge,
879 * maintain a "best hit", then declare that one the winner?
882 pid_index -= vp->first_pid_index;
884 y = pid_index*vp->strip_height + vp->event_offset;
886 x = vp->pid_ax_width +
887 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
889 /* Perhaps we're trying to toggle the detail box? */
890 if (ep->flags & EVENT_FLAG_SELECT) {
891 /* Figure out the dimensions of the detail box */
892 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
893 rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED);
894 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
895 ep->flags &= ~EVENT_FLAG_SELECT;
896 view1_display_when_idle();
901 sprintf(tmpbuf, "%ld", ep->code);
903 /* Figure out the dimensions of the regular box */
904 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
906 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
907 /* we hit the rectangle. */
908 if (ep->flags & EVENT_FLAG_SELECT) {
909 ep->flags &= ~EVENT_FLAG_SELECT;
910 view1_display_when_idle();
913 set_color(ep->pid->pid_index);
915 /* It wasn't selected, so put up the detail box */
916 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
917 tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED);
918 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK);
919 ep->flags |= EVENT_FLAG_SELECT;
920 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
921 s_last_selected_event = ep;
930 /****************************************************************************
931 * toggle_track_select
932 ****************************************************************************/
934 static void toggle_track_select (GdkEventButton *event,
945 /* Scan pid/track axis locations, looking for a match */
946 for (i = 0; i < vp->npids; i++) {
947 y = i*vp->strip_height + vp->pid_ax_offset;
948 delta_y = y - event->y;
956 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
960 pid_index = i + vp->first_pid_index;
961 psp = (g_pids + pid_index);
963 view1_display_when_idle();
966 /****************************************************************************
968 ****************************************************************************/
969 static void deselect_tracks (void)
973 for (i = 0; i < g_npids; i++)
974 g_pids[i].selected = 0;
979 /****************************************************************************
981 ****************************************************************************/
983 typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
985 static void move_current_track(GdkEventButton *event,
992 pid_sort_t *new_pidvec;
994 pid_sort_t *pold, *pnew;
1000 /* Scan pid/track axis locations, looking for a match */
1001 for (i = 0; i < vp->npids; i++) {
1002 y = i*vp->strip_height + vp->pid_ax_offset;
1003 delta_y = y - event->y;
1011 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
1015 pid_index = i + vp->first_pid_index;
1017 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
1021 if (type == MOVE_TOP) {
1023 *pnew++ = g_pids[pid_index];
1024 for (i = 0; i < pid_index; i++)
1028 for (; i < g_npids; i++)
1031 /* move to bottom */
1032 for (i = 0; i < pid_index; i++)
1036 for (; i < g_npids; i++)
1038 *pnew = g_pids[pid_index];
1042 g_pids = new_pidvec;
1045 * Revert the pid_index mapping to an identity map,
1049 for (i = 0; i < g_npids; i++) {
1054 view1_display_when_idle();
1057 /****************************************************************************
1059 * Process a zoom gesture. The use of doubles is required to avoid
1060 * truncating the various variable values, which in turn would lead to
1061 * some pretty random-looking zoom responses.
1062 ****************************************************************************/
1064 void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1067 double time_per_pixel;
1068 double width_in_pixels;
1069 double center_on_time, width_in_time;
1070 double center_on_pixel;
1073 * Clip the zoom area to the event display area.
1074 * Otherwise, center_on_time - width_in_time is in hyperspace
1075 * to the left of zero
1078 if (e1->x < vp->pid_ax_width)
1079 e1->x = vp->pid_ax_width;
1081 if (e2->x < vp->pid_ax_width)
1082 e2->x = vp->pid_ax_width;
1085 goto loser_zoom_repaint;
1087 xrange = (double) (e2->x - e1->x);
1091 /* Actually, width in pixels of half the zoom area */
1092 width_in_pixels = xrange / 2.00;
1093 time_per_pixel = dtime_per_pixel(vp);
1094 width_in_time = width_in_pixels * time_per_pixel;
1096 /* Center the screen on the center of the zoom area */
1097 center_on_pixel = (double)((e2->x + e1->x) / 2.00) -
1098 (double)vp->pid_ax_width;
1099 center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime;
1102 * Transform back to 64-bit integer microseconds, reset the
1103 * scrollbar, schedule a repaint.
1105 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1106 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1109 recompute_hscrollbar();
1111 view1_display_when_idle();
1114 /****************************************************************************
1117 * Scroll up or down by the specified delta
1119 ****************************************************************************/
1120 static void scroll_y(int delta)
1122 int new_index = s_v1->first_pid_index + delta;
1123 if (new_index + s_v1->npids > g_npids)
1124 new_index = g_npids - s_v1->npids;
1128 if (new_index != s_v1->first_pid_index) {
1129 s_v1->first_pid_index = new_index;
1130 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index;
1131 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1132 view1_display_when_idle();
1136 /****************************************************************************
1137 * view1_handle_key_press_event
1138 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1140 * This routine implements hotkeys for the Quake generation:
1151 * E - toggle summary mode
1152 * C - toggle color mode
1156 * P - persist snapshots to file
1157 * L - load snapshots from file
1161 ****************************************************************************/
1163 view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1167 switch (event->keyval) {
1168 case GDK_w: // zoom in
1169 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1172 case GDK_s: // zoom out
1173 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1176 case GDK_a: // pan left
1177 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1178 if (s_v1->minvistime < delta) {
1179 delta = s_v1->minvistime;
1181 s_v1->minvistime -= delta;
1182 s_v1->maxvistime -= delta;
1183 recompute_hscrollbar();
1186 case GDK_d: // pan right
1187 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1188 if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) {
1190 * @@@ this doesn't seem to quite reach the far right hand
1191 * side correctly - not sure why.
1193 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1195 s_v1->minvistime += delta;
1196 s_v1->maxvistime += delta;
1197 recompute_hscrollbar();
1200 case GDK_r: // pan up
1204 case GDK_f: // pan down
1208 case GDK_t: // fewer tracks
1209 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1212 case GDK_g: // more tracks
1213 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1216 case GDK_e: // toggle summary mode
1217 view1_button_click_callback
1218 (NULL, (gpointer)(unsigned long long)
1219 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
1222 case GDK_c: // toggle color mode
1224 view1_display_when_idle();
1227 case GDK_p: // persist snapshots
1231 case GDK_l: // load snapshots
1235 case GDK_x: // take snapshot
1236 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1239 case GDK_z: // next snapshot
1240 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1243 case GDK_q: // ctrl-q is exit
1244 if (event->state & GDK_CONTROL_MASK) {
1252 /****************************************************************************
1253 * button_press_event
1254 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1256 * This routine implements three functions: zoom-to-area, time ruler, and
1257 * show/hide event detail popup.
1259 * The left mouse button (button 1) has two simultaneous functions: event
1260 * detail popup, and zoom-to-area. If the press and release events occur
1261 * within a small delta-x, it's a detail popup event. Otherwise, it's
1264 * The right mouse button (button 3) implements the time ruler.
1265 ****************************************************************************/
1268 button_press_event (GtkWidget *widget, GdkEventButton *event)
1270 static GdkEventButton press1_event;
1271 static boolean press1_valid;
1272 static GdkEventButton press3_event;
1273 static guint32 last_truler_time;
1274 static boolean press3_valid;
1275 static boolean zoom_bar_up;
1276 int time_ax_y, xdelta;
1278 double time_per_pixel;
1282 switch(event->type) {
1283 case GDK_BUTTON_PRESS:
1284 /* Capture the appropriate starting point */
1285 if (event->button == 1) {
1286 press1_valid = TRUE;
1287 press1_event = *event;
1290 if (event->button == 3) {
1291 press3_valid = TRUE;
1292 press3_event = *event;
1297 case GDK_BUTTON_RELEASE:
1300 press3_valid = FALSE;
1301 /* Fix the cursor, and repaint the screen from scratch */
1302 gdk_window_set_cursor (da->window, norm_cursor);
1303 view1_display_when_idle();
1306 /* Event select / zoom-to-area */
1308 press1_valid = FALSE;
1309 xdelta = (int)(press1_event.x - event->x);
1313 /* is the mouse more or less where it started? */
1315 /* Control-left-mouse => sink the track */
1316 /* Shift-left-mouse => raise the track */
1317 if ((press1_event.state & GDK_CONTROL_MASK) ==
1319 move_current_track(event, s_v1, MOVE_BOTTOM);
1320 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1322 move_current_track(event, s_v1, MOVE_TOP);
1324 /* No modifiers: toggle the event / select track */
1325 if (toggle_event_select(event, s_v1))
1326 toggle_track_select(event, s_v1);
1328 /* Repaint to get rid of the zoom bar */
1330 /* Fix the cursor and leave. No zoom */
1331 gdk_window_set_cursor (da->window, norm_cursor);
1332 zoom_bar_up = FALSE;
1335 } else { /* mouse moved enough to zoom */
1336 zoom_event(&press1_event, event, s_v1);
1337 gdk_window_set_cursor (da->window, norm_cursor);
1338 zoom_bar_up = FALSE;
1340 } else if (event->button == 4) {
1341 /* scroll wheel up */
1342 scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1);
1343 } else if (event->button == 5) {
1344 /* scroll wheel down */
1345 scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1);
1349 case GDK_MOTION_NOTIFY:
1350 /* Button one followed by motion: draw zoom fence and fix cursor */
1352 /* Fence, cursor already set */
1356 xdelta = (int)(press1_event.x - event->x);
1360 /* Haven't moved enough to declare a zoom sequence yet */
1364 /* Draw the zoom fence, use the key-down X coordinate */
1365 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1367 line((int)(press1_event.x), s_v1->pop_offset,
1368 (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK);
1369 tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset,
1371 gdk_window_set_cursor(da->window, zi_cursor);
1378 gdk_window_set_cursor(da->window, zi_cursor);
1381 * Some filtration is needed on Solaris, or the server will hang
1383 if (event->time - last_truler_time < 75)
1386 last_truler_time = event->time;
1388 line((int)(press3_event.x), s_v1->pop_offset,
1389 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1391 xdelta = (int)(press3_event.x - event->x);
1395 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1396 ((double)(s_v1->total_width - s_v1->pid_ax_width));
1398 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1400 line((int)(press3_event.x), s_v1->pop_offset,
1401 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1403 * Note: use a fixed-width format so it looks like we're
1404 * erasing and redrawing the box.
1406 nsec = ((double)xdelta)*time_per_pixel;
1408 sprintf(tmpbuf, "%8.3f sec ", nsec/1e9);
1409 } else if (nsec > 1e6) {
1410 sprintf(tmpbuf, "%8.3f msec", nsec/1e6);
1411 } else if (nsec > 1e3) {
1412 sprintf(tmpbuf, "%8.3f usec", nsec/1e3);
1414 sprintf(tmpbuf, "%8.0f nsec", nsec);
1416 s_v1->last_time_interval = nsec;
1417 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1425 g_print("button:\ttype = %d\n", event->type);
1426 g_print("\twindow = 0x%x\n", event->window);
1427 g_print("\tsend_event = %d\n", event->send_event);
1428 g_print("\ttime = %d\n", event->time);
1429 g_print("\tx = %6.2f\n", event->x);
1430 g_print("\ty = %6.2f\n", event->y);
1431 g_print("\tpressure = %6.2f\n", event->pressure);
1432 g_print("\txtilt = %6.2f\n", event->xtilt);
1433 g_print("\tytilt = %6.2f\n", event->ytilt);
1434 g_print("\tstate = %d\n", event->state);
1435 g_print("\tbutton = %d\n", event->button);
1436 g_print("\tsource = %d\n", event->source);
1437 g_print("\tdeviceid = %d\n", event->deviceid);
1438 g_print("\tx_root = %6.2f\n", event->x_root);
1439 g_print("\ty_root = %6.2f\n", event->y_root);
1444 view1_display_when_idle();
1449 /****************************************************************************
1451 * Happens when the window manager resizes the viewer's main window.
1452 ****************************************************************************/
1455 configure_event (GtkWidget *widget, GdkEventConfigure *event)
1457 /* Toss the previous drawing area backing store pixmap */
1459 gdk_pixmap_unref(pm);
1461 /* Create a new pixmap, paint it */
1462 pm = gdk_pixmap_new(widget->window,
1463 widget->allocation.width,
1464 widget->allocation.height,
1466 gdk_draw_rectangle (pm,
1467 widget->style->white_gc,
1470 widget->allocation.width,
1471 widget->allocation.height);
1473 /* Reset the view geometry parameters, as required */
1474 s_v1->total_width = widget->allocation.width;
1475 s_v1->total_height = widget->allocation.height;
1476 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
1479 /* Schedule a repaint */
1480 view1_display_when_idle();
1484 /****************************************************************************
1486 * Use backing store to fix the screen.
1487 ****************************************************************************/
1488 static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1490 gdk_draw_pixmap(widget->window,
1491 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1493 event->area.x, event->area.y,
1494 event->area.x, event->area.y,
1495 event->area.width, event->area.height);
1500 /****************************************************************************
1501 * event_search_internal
1502 * This routine searches forward from s_srchindex, looking for s_srchcode;
1503 * wraps at the end of the buffer.
1504 ****************************************************************************/
1506 boolean event_search_internal (void)
1512 boolean full_redisplay = FALSE;
1513 ulonglong current_width;
1516 /* No events yet? Act like the search worked, to avoid a loop */
1520 ep = (g_events + s_srchindex);
1521 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1524 * Assume the user wants to search [plus or minus]
1525 * from where they are.
1528 if (ep->time < s_v1->minvistime)
1529 s_srchindex = find_event_index (s_v1->minvistime);
1532 for (i = 1; i <= g_nevents; i++) {
1533 index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ?
1534 (s_srchindex - i) % g_nevents :
1535 (i + s_srchindex) % g_nevents;
1537 ep = (g_events + index);
1539 if (ep->code == s_srchcode) {
1542 s_srchindex = index;
1543 pid_index = ep->pid->pid_index;
1545 /* Need a vertical scroll? */
1546 if ((pid_index < s_v1->first_pid_index) ||
1547 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1548 if (pid_index > (g_npids - s_v1->npids))
1549 pid_index = (g_npids - s_v1->npids);
1550 s_v1->first_pid_index = pid_index;
1551 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1552 (gdouble)s_v1->first_pid_index;
1553 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1554 full_redisplay = TRUE;
1557 /* Need a horizontal scroll? */
1558 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1559 current_width = (s_v1->maxvistime - s_v1->minvistime);
1560 if (ep->time < ((current_width+1) / 2)) {
1561 s_v1->minvistime = 0ll;
1562 s_v1->maxvistime = current_width;
1564 s_v1->minvistime = ep->time - ((current_width+1)/2);
1565 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1567 recompute_hscrollbar();
1568 full_redisplay = TRUE;
1570 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1571 full_redisplay = TRUE;
1574 if (!full_redisplay){
1577 time_per_pixel = dtime_per_pixel(s_v1);
1579 y = pid_index*s_v1->strip_height + s_v1->event_offset;
1580 x = s_v1->pid_ax_width +
1581 (int)(((double)(ep->time - s_v1->minvistime)) /
1583 sprintf(tmpbuf, "SEARCH RESULT");
1584 tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED);
1585 line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK);
1587 full_redisplay = TRUE;
1593 view1_display_when_idle();
1597 sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode);
1598 message_line(tmpbuf);
1599 s_srchfail_up = TRUE;
1603 /****************************************************************************
1604 * event_search_callback
1605 ****************************************************************************/
1607 boolean event_search_callback (char *s)
1609 /* No events yet? Act like the search worked, to avoid a loop */
1613 s_srchcode = atol(s);
1615 if (s_srchcode == 0)
1618 return(event_search_internal());
1622 /****************************************************************************
1623 * anomaly_statistics_init
1624 ****************************************************************************/
1626 static int anomaly_statistics_init (void)
1637 /* Gather summary statistics... */
1640 vec_reset_length (s_v1->means);
1641 vec_reset_length (s_v1->matches);
1642 vec_reset_length (s_v1->variances);
1643 vec_reset_length (s_v1->two_stddevs);
1644 vec_reset_length (s_v1->mins);
1645 vec_reset_length (s_v1->maxes);
1647 for (i = 0; i < g_nevents; i++) {
1648 if (ep->code != s_anomalycode) {
1653 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
1654 vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
1655 vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
1656 vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
1657 eep = get_clib_event (ep->datum);
1658 data = clib_mem_unaligned (eep->data, u32);
1660 s_v1->means[pid->pid_index] += fdata;
1661 s_v1->matches[pid->pid_index] += 1;
1662 /* First data point? set min, max */
1663 if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
1664 s_v1->mins[pid->pid_index] = fdata;
1665 s_v1->maxes[pid->pid_index] = fdata;
1667 s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
1668 fdata : s_v1->mins[pid->pid_index];
1669 s_v1->maxes[pid->pid_index] =
1670 (fdata > s_v1->maxes[pid->pid_index]) ?
1671 fdata : s_v1->maxes[pid->pid_index];
1675 if (vec_len (s_v1->matches) == 0)
1678 /* Compute s_v1->means */
1679 for (i = 0; i < vec_len (s_v1->means); i++)
1680 s_v1->means[i] = s_v1->matches[i]
1681 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1683 /* Compute s_v1->variances */
1685 for (i = 0; i < g_nevents; i++) {
1686 if (ep->code != s_anomalycode) {
1691 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1692 eep = get_clib_event (ep->datum);
1693 data = clib_mem_unaligned (eep->data, u32);
1695 s_v1->variances[pid->pid_index] +=
1696 (fdata - s_v1->means[pid->pid_index])
1697 * (fdata - s_v1->means[pid->pid_index]);
1701 /* Normalize variances */
1702 for (i = 0; i < vec_len (s_v1->variances); i++)
1703 s_v1->variances[i] = s_v1->matches[i]
1704 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1706 /* Compute the anomaly threshold, by default 2.5*stddev */
1707 for (i = 0; i < vec_len (s_v1->variances); i++)
1708 vec_add1 (s_v1->two_stddevs,
1709 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1713 /****************************************************************************
1714 * anomaly_search_internal
1715 * This routine searches forward from s_srchindex, looking for s_srchcode;
1716 * wraps at the end of the buffer.
1717 ****************************************************************************/
1719 boolean anomaly_search_internal (void)
1728 boolean full_redisplay = FALSE;
1729 ulonglong current_width;
1733 if (vec_len (s_v1->matches) == 0)
1734 anomaly_statistics_init();
1736 ep = (g_events + s_srchindex);
1737 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1740 * If the user rearranged the screen, start from the minimum
1743 if (ep->time < s_v1->minvistime)
1744 s_srchindex = find_event_index (s_v1->minvistime);
1746 for (i = 1; i <= g_nevents; i++) {
1747 index = (i + s_srchindex) % g_nevents;
1749 ep = (g_events + index);
1750 if (ep->code != s_anomalycode)
1754 eep = get_clib_event (ep->datum);
1755 data = clib_mem_unaligned (eep->data, u32);
1759 * Found an anomaly? Define an anomaly as a datum
1760 * greater than 2*stddev above average.
1762 if ((fdata - s_v1->means[pid->pid_index]) >
1763 s_v1->two_stddevs[pid->pid_index]) {
1766 s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
1767 s_v1->anomaly_threshold_stddevs);
1769 for (i = 0; i < vec_len (s_v1->means); i++) {
1770 if (s_v1->matches[i] > 0)
1771 s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
1772 s_v1->mins[i], s_v1->maxes[i],
1774 s_v1->means[i]+s_v1->two_stddevs[i]);
1776 s = format (s, "{no match} ");
1779 message_line ((char *)s);
1782 s_srchindex = index;
1783 pid_index = ep->pid->pid_index;
1785 /* Need a vertical scroll? */
1786 if ((pid_index < s_v1->first_pid_index) ||
1787 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1788 if (pid_index > (g_npids - s_v1->npids))
1789 pid_index = (g_npids - s_v1->npids);
1790 s_v1->first_pid_index = pid_index;
1791 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1792 (gdouble)s_v1->first_pid_index;
1793 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1794 full_redisplay = TRUE;
1797 /* Need a horizontal scroll? */
1798 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1799 current_width = (s_v1->maxvistime - s_v1->minvistime);
1800 if (ep->time < ((current_width+1) / 2)) {
1801 s_v1->minvistime = 0ll;
1802 s_v1->maxvistime = current_width;
1804 s_v1->minvistime = ep->time - ((current_width+1)/2);
1805 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1807 recompute_hscrollbar();
1808 full_redisplay = TRUE;
1810 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1811 full_redisplay = TRUE;
1814 view1_display_when_idle();
1819 sprintf (tmpbuf, "Search for an anomalous event %ld failed...\n",
1821 message_line(tmpbuf);
1822 s_srchfail_up = TRUE;
1826 /****************************************************************************
1827 * anomaly_search_callback
1828 ****************************************************************************/
1830 boolean anomaly_search_callback (char *s)
1832 ulong new_anomalycode;
1834 /* No events yet? Act like the search worked, to avoid a loop */
1838 new_anomalycode = atol(s);
1840 if (new_anomalycode == 0)
1843 if (new_anomalycode != s_anomalycode ||
1844 vec_len (s_v1->matches) == 0) {
1845 s_anomalycode = new_anomalycode;
1846 if (anomaly_statistics_init()) {
1849 s = format (0, "Search for an anomalous event %ld failed...\n",
1851 message_line ((char *) s);
1856 return(anomaly_search_internal());
1859 /****************************************************************************
1860 * anomaly_threshold_callback
1861 ****************************************************************************/
1863 boolean anomaly_threshold_callback (char *s)
1867 /* No events yet? Act like the search worked, to avoid a loop */
1871 new_threshold = atof (s);
1873 if (new_threshold == 0.0 || new_threshold > 10.0)
1876 s_v1->anomaly_threshold_stddevs = new_threshold;
1878 vec_reset_length (s_v1->means);
1879 vec_reset_length (s_v1->matches);
1880 vec_reset_length (s_v1->variances);
1881 vec_reset_length (s_v1->two_stddevs);
1885 /****************************************************************************
1887 ****************************************************************************/
1889 static void event_search (void)
1891 modal_dialog ("Event Search: Please Enter Event Code",
1892 "Invalid: Please Reenter Event Code", NULL,
1893 event_search_callback);
1896 /****************************************************************************
1898 ****************************************************************************/
1900 static void anomaly_search (void)
1902 modal_dialog ("Anomaly Search: Please Enter Event Code",
1903 "Invalid: Please Reenter Event Code", NULL,
1904 anomaly_search_callback);
1907 /****************************************************************************
1909 ****************************************************************************/
1911 static void anomaly_threshold (void)
1913 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1914 "Invalid: Please Reenter Threshold in Standard Deviations",
1915 NULL, anomaly_threshold_callback);
1918 /****************************************************************************
1920 ****************************************************************************/
1921 static void init_track_colors(void)
1927 gboolean dont_care[g_npids];
1930 * If we've already allocated the colors once, then in theory we should
1931 * just be able to re-order the GCs already created to match the new track
1932 * order; the track -> color mapping doesn't currently change at runtime.
1933 * However, it's easier just to allocate everything from fresh. As a nod in
1934 * the direction of politeness towards our poor abused X server, we at
1935 * least mop up the previously allocated GCs first, although in practice
1936 * even omitting this didn't seem to cause a problem.
1938 if (s_color != NULL ) {
1939 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
1941 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
1944 * First time through: allocate the array to hold the GCs.
1946 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
1950 * Go through and assign a color for each track.
1952 /* Setup entry 0 in the colormap as pure red (for selection) */
1953 s_color[0] = fg_red;
1955 for (i = 1; i < g_npids; i++) {
1957 * We compute the color from a hash of the thread name. That way we get
1958 * a distribution of different colors, and the same thread has the same
1959 * color across multiple data sets. Unfortunately, even though the
1960 * process name and thread id are invariant across data sets, the
1961 * process id isn't, so we want to exclude that from the hash. Since
1962 * the pid appears in parentheses after the process name and tid, we
1963 * can just stop at the '(' character.
1965 * We could create a substring and use the CLIB Jenkins hash, but given
1966 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1967 * just as good, and it's easiest just to compute it inline.
1969 label_char = get_track_label(g_pids[i].pid_value);
1971 while (*label_char != '\0' && *label_char != '(') {
1972 hash = hash * 33 + *label_char++;
1974 hash += hash >> 5; /* even out the lower order bits a touch */
1977 * OK, now we have our hash. We get the color by using the first three
1978 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1979 * and then use the fourth byte to choose one of R, G, B and mask this
1980 * one down. This ensures the color can't be too close to white and
1981 * therefore hard to see.
1983 * We also drop the top bit of the green, since bright green on its own
1984 * is hard to see against white. Generally we err on the side of
1985 * keeping it dark, rather than using the full spectrum of colors. This
1986 * does result in something of a preponderance of muddy colors and a
1987 * bit of a lack of cheery bright ones, but at least you can read
1988 * everything. It would be nice to do better.
1990 RGB[0] = (hash & 0xff000000) >> 16;
1991 RGB[1] = (hash & 0x007f0000) >> 8;
1992 RGB[2] = (hash & 0x0000ff00);
1993 RGB[hash % 3] &= 0x1fff;
1996 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1998 g_pids[i].color_index = i;
2003 * Actually allocate the colors in one bulk operation. We ignore the return
2006 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
2007 s_color, g_npids+1, FALSE, TRUE, dont_care);
2011 /****************************************************************************
2013 * Reorder the pid_index fields so the viewer "chases" the last selected
2015 ****************************************************************************/
2017 static void chase_event_etc(enum chase_mode mode)
2019 pid_sort_t *psp, *new_pidvec;
2023 ulong code_to_chase;
2024 ulong datum_to_chase;
2029 if (!s_last_selected_event) {
2030 infobox("No selected event",
2031 "\nPlease select an event and try again...\n");
2035 /* Clear all index assignments */
2037 for (i = 0; i < g_npids; i++) {
2039 pp->pid_index = 0xFFFFFFFF;
2043 ep = s_last_selected_event;
2044 code_to_chase = ep->code;
2045 datum_to_chase = ep->datum;
2046 pid_to_chase = ep->pid->pid_value;
2048 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
2051 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2052 if (ep >= g_events + g_nevents)
2062 if (ep->code == code_to_chase) {
2068 if (ep->datum == datum_to_chase) {
2074 if (ep->pid->pid_value == pid_to_chase) {
2080 infobox("BUG", "unknown mode in chase_event_etc\n");
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)
2095 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2101 /* Pass 2, first-to-last, to collect stragglers */
2104 while (ep < g_events + g_nevents) {
2105 if (ep->pid->pid_index == 0xFFFFFFFF) {
2106 ep->pid->pid_index = pids_mapped;
2107 new_pidvec[pids_mapped].pid = ep->pid;
2108 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2109 new_pidvec[pids_mapped].color_index = 0;
2111 if (pids_mapped == g_npids)
2117 if (pids_mapped != g_npids) {
2118 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2122 g_pids = new_pidvec;
2125 * The new g_pids vector contains the "chase" sort, so we revert
2126 * the pid_index mapping to an identity map
2130 for (i = 0; i < g_npids; i++) {
2136 /* AutoScroll the PID axis so we show the first "chased" event */
2137 s_v1->first_pid_index = 0;
2138 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2139 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2140 init_track_colors();
2141 view1_display_when_idle();
2144 /****************************************************************************
2146 * Copy g_original_pids to g_pids, revert index mapping
2147 ****************************************************************************/
2148 static void unchase_event_etc(void)
2154 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
2156 /* Fix the pid structure index mappings */
2159 for (i = 0; i < g_npids; i++) {
2165 /* Scroll PID axis to the top */
2166 s_v1->first_pid_index = 0;
2167 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2168 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2169 init_track_colors();
2170 view1_display_when_idle();
2173 /****************************************************************************
2175 * To fit a reasonable-sized landscape mode plot onto letter-size paper,
2176 * scale everything by .75.
2177 ****************************************************************************/
2179 static void print_ps_header (v1_geometry_t *vp, char *filename)
2185 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2186 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2187 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2188 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2189 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2190 fprintf(s_printfp, "%%%%Origin: 0 0\n");
2191 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
2193 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2194 fprintf(s_printfp, "%%%%Pages: 1\n");
2195 fprintf(s_printfp, "%%%%Page: 1 1\n");
2196 fprintf(s_printfp, "%%%%EOF\n");
2197 fprintf(s_printfp, "/Times-Roman findfont\n");
2198 fprintf(s_printfp, "12 scalefont\n");
2199 fprintf(s_printfp, "setfont\n");
2200 fprintf(s_printfp, ".75 .75 scale\n");
2203 /****************************************************************************
2205 * Xcoordinate rotate and translate. We need to emit postscript that
2206 * has a reasonable aspect ratio for printing. To do that, we rotate the
2207 * intended picture by 90 degrees, using the standard 2D rotation
2210 * Xr = x*cos(theta) - y*sin(theta);
2211 * Yr = x*sin(theta) + y*cos(theta);
2213 * If we let theta = 90, this reduces to
2217 * Translate back to the origin in X by adding Ymax, yielding
2219 ****************************************************************************/
2221 static inline int xrt(int x, int y)
2223 return (s_v1->total_height - y);
2226 static inline int yrt(int x, int y)
2231 /****************************************************************************
2232 * print_screen_callback
2233 ****************************************************************************/
2235 static boolean print_screen_callback(char *filename)
2237 s_printfp = fopen (filename, "wt");
2239 if (s_printfp == NULL)
2243 * This variable allows us to magically turn the view1 display
2244 * code into a print-driver, with a minimum of fuss. The idea is to
2245 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2246 * the required value, aka s_print_offset.
2247 * Make sure to fix g2.h if you mess here, or vice versa.
2249 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2251 print_ps_header(s_v1, filename);
2253 display_pid_axis(s_v1);
2254 display_event_data(s_v1);
2255 display_time_axis(s_v1);
2261 /* For tactile feedback */
2262 view1_display_when_idle();
2266 int event_time_cmp (const void *a, const void *b)
2268 const event_t *e1 = a;
2269 const event_t *e2 = b;
2271 if (e1->time < e2->time)
2273 else if (e1->time > e2->time)
2278 /****************************************************************************
2280 ****************************************************************************/
2281 static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2288 delta = (ulonglong) (vp->last_time_interval);
2290 /* Make sure we don't push events to the left of the big bang */
2291 if (which == SLEW_LEFT_BUTTON) {
2292 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2293 pid_index = ep->pid->pid_index;
2294 pp = (g_pids + pid_index);
2297 if (ep->time < delta) {
2298 infobox("Slew Range Error",
2299 "\nCan't slew selected data left that far..."
2300 "\nEvents would preceed the Big Bang (t=0)...");
2307 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2308 pid_index = ep->pid->pid_index;
2309 pp = (g_pids + pid_index);
2312 if (which == SLEW_LEFT_BUTTON)
2319 /* Re-sort the events, to avoid screwing up the event display */
2320 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2322 /* De-select tracks */
2326 view1_display_when_idle();
2329 /****************************************************************************
2330 * view1_button_click_callback
2331 ****************************************************************************/
2333 static void view1_button_click_callback(GtkButton *item, gpointer data)
2335 enum view1_button_click click = (enum view1_button_click) data;
2337 ulonglong event_incdec;
2338 ulonglong current_width;
2339 ulonglong zoom_delta;
2341 current_width = s_v1->maxvistime - s_v1->minvistime;
2342 event_incdec = (current_width) / 3;
2344 if (event_incdec == 0LL)
2347 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2351 /* First PID to top of window */
2352 s_v1->first_pid_index = 0;
2353 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2354 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2358 s_v1->first_pid_index = g_npids - s_v1->npids;
2359 if (s_v1->first_pid_index < 0)
2360 s_v1->first_pid_index = 0;
2361 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2362 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2377 case CHASE_EVENT_BUTTON:
2378 chase_event_etc(CHASE_EVENT);
2381 case CHASE_DATUM_BUTTON:
2382 chase_event_etc(CHASE_DATUM);
2385 case CHASE_TRACK_BUTTON:
2386 chase_event_etc(CHASE_TRACK);
2389 case UNCHASE_BUTTON:
2390 unchase_event_etc();
2395 s_v1->minvistime = 0LL;
2396 s_v1->maxvistime = current_width;
2397 recompute_hscrollbar();
2401 s_v1->minvistime += zoom_delta;
2402 s_v1->maxvistime -= zoom_delta;
2403 recompute_hscrollbar();
2406 case SEARCH_AGAIN_BUTTON:
2408 event_search_internal();
2411 /* NOTE FALLTHROUGH */
2417 case ANOMALY_THRESHOLD_BUTTON:
2418 anomaly_threshold();
2421 case ANOMALY_NEXT_BUTTON:
2422 if (s_anomalycode) {
2423 anomaly_search_internal();
2426 /* NOTE FALLTHROUGH */
2428 case ANOMALY_BUTTON:
2432 case ZOOMOUT_BUTTON:
2433 if (zoom_delta == 0LL)
2436 if (s_v1->minvistime >= zoom_delta) {
2437 s_v1->minvistime -= zoom_delta;
2438 s_v1->maxvistime += zoom_delta;
2440 s_v1->minvistime = 0;
2441 s_v1->maxvistime += zoom_delta*2;
2444 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
2445 g_events[g_nevents-1].time * 9) {
2446 s_v1->minvistime = 0;
2447 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
2448 /* Single event? Make window 1s wide... */
2450 s_v1->maxvistime = 1000000;
2453 recompute_hscrollbar();
2457 ep = (g_events + g_nevents - 1);
2458 s_v1->maxvistime = ep->time + event_incdec/3;
2459 s_v1->minvistime = s_v1->maxvistime - current_width;
2460 if (s_v1->minvistime > s_v1->maxvistime)
2462 recompute_hscrollbar();
2465 case MORE_TRACES_BUTTON:
2466 /* Reduce the strip height to fit more traces on screen */
2467 s_v1->strip_height -= 1;
2469 if (s_v1->strip_height < 1) {
2470 s_v1->strip_height = 1;
2473 /* Recalculate the number of strips on the screen */
2474 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2476 recompute_vscrollbar();
2479 case LESS_TRACES_BUTTON:
2480 /* Increase the strip height to fit fewer on the screen */
2481 s_v1->strip_height += 1;
2482 if (s_v1->strip_height > 80) {
2483 s_v1->strip_height = 80;
2486 /* Recalculate the number of strips on the screen */
2487 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2489 recompute_vscrollbar();
2492 case FORWARD_BUTTON:
2493 srch_chase_dir = SRCH_CHASE_FORWARD;
2494 gtk_widget_hide (s_view1_forward_button);
2495 gtk_widget_show (s_view1_backward_button);
2498 case BACKWARD_BUTTON:
2499 srch_chase_dir = SRCH_CHASE_BACKWARD;
2500 gtk_widget_show (s_view1_forward_button);
2501 gtk_widget_hide (s_view1_backward_button);
2504 case SUMMARY_BUTTON:
2505 summary_mode = TRUE;
2506 gtk_widget_hide (s_view1_summary_button);
2507 gtk_widget_show (s_view1_nosummary_button);
2510 case NOSUMMARY_BUTTON:
2511 summary_mode = FALSE;
2512 gtk_widget_show (s_view1_summary_button);
2513 gtk_widget_hide (s_view1_nosummary_button);
2516 case SLEW_LEFT_BUTTON:
2517 case SLEW_RIGHT_BUTTON:
2518 if (s_v1->last_time_interval < 10e-9) {
2519 infobox("slew", "\nNo time interval set...\n");
2522 slew_tracks (s_v1, click);
2526 view1_display_when_idle();
2529 /****************************************************************************
2530 * view1_print_callback
2531 ****************************************************************************/
2533 void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2535 modal_dialog("Print Screen (PostScript format) to file:",
2536 "Invalid file: Print Screen to file:",
2537 "g2.ps", print_screen_callback);
2540 /****************************************************************************
2542 ****************************************************************************/
2544 static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2546 ulonglong current_width;
2548 current_width = (s_v1->maxvistime - s_v1->minvistime);
2550 s_v1->minvistime = (ulonglong)(adj->value);
2551 s_v1->maxvistime = s_v1->minvistime + current_width;
2553 view1_display_when_idle();
2556 g_print ("adj->lower = %.2f\n", adj->lower);
2557 g_print ("adj->upper = %.2f\n", adj->upper);
2558 g_print ("adj->value = %.2f\n", adj->value);
2559 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2560 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2561 g_print ("adj->page_size = %.2f\n", adj->page_size);
2565 /****************************************************************************
2567 ****************************************************************************/
2569 static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2571 s_v1->first_pid_index = (int)adj->value;
2572 view1_display_when_idle();
2575 void set_pid_ax_width(int width)
2577 s_v1->pid_ax_width = width;
2578 view1_display_when_idle();
2581 /****************************************************************************
2583 ****************************************************************************/
2585 void view1_init(void)
2587 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2588 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2590 s_v1->pid_ax_width = 80;
2591 s_v1->time_ax_height = 80;
2592 s_v1->time_ax_spacing = 100;
2593 s_v1->strip_height = 25;
2594 s_v1->pop_offset = 20;
2595 s_v1->pid_ax_offset = 34;
2596 s_v1->event_offset = 40;
2597 s_v1->total_height = c_view1_draw_height;
2598 s_v1->total_width = c_view1_draw_width;
2599 s_v1->first_pid_index = 0;
2600 s_v1->anomaly_threshold_stddevs =
2601 atof(getprop_default("anomaly_threshold_stddevs", "2.5"));
2602 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2605 s_v1->minvistime = 0;
2606 s_v1->maxvistime = 200;
2608 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2610 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2612 da = gtk_drawing_area_new();
2613 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2614 c_view1_draw_height);
2617 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2618 (GtkSignalFunc) motion_notify_event, NULL);
2621 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2622 (GtkSignalFunc) expose_event, NULL);
2624 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2625 (GtkSignalFunc) configure_event, NULL);
2627 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2628 (GtkSignalFunc) button_press_event, NULL);
2630 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2631 (GtkSignalFunc) button_press_event, NULL);
2633 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2634 (GtkSignalFunc) button_press_event, NULL);
2636 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2637 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2638 | GDK_BUTTON_MOTION_MASK);
2641 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2643 g_font = gdk_font_load ("8x13");
2644 if (g_font == NULL) {
2645 g_error("Couldn't load 8x13 font...\n");
2647 gdk_font_ref(g_font);
2650 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2652 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
2653 0.0 /* minimum value */,
2654 2000.0 /* maximum value */,
2655 0.1 /* step increment */,
2656 10.0/* page increment */,
2657 10.0/* page size */);
2659 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2661 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2662 GTK_SIGNAL_FUNC (view1_vscroll),
2663 (gpointer)s_view1_vscroll);
2665 s_view1_topbutton = gtk_button_new_with_label("Top");
2666 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2668 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2669 GTK_SIGNAL_FUNC(view1_button_click_callback),
2670 (gpointer) TOP_BUTTON);
2672 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2673 GTK_SIGNAL_FUNC(view1_button_click_callback),
2674 (gpointer) BOTTOM_BUTTON);
2676 /* More Traces button and Less Traces button */
2677 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2678 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2679 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
2680 GTK_SIGNAL_FUNC(view1_button_click_callback),
2681 (gpointer) MORE_TRACES_BUTTON);
2682 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
2683 GTK_SIGNAL_FUNC(view1_button_click_callback),
2684 (gpointer) LESS_TRACES_BUTTON);
2687 /* Trick to bottom-justify the menu: */
2688 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2689 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2694 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2697 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2700 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2703 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2706 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2709 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2712 /* Time axis menu */
2714 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2716 s_view1_startbutton = gtk_button_new_with_label("Start");
2718 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2720 s_view1_searchbutton = gtk_button_new_with_label("Search");
2721 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2723 s_view1_anomalybutton = gtk_button_new_with_label("Anomaly");
2724 s_view1_anomalynextbutton = gtk_button_new_with_label("Next Anomaly");
2725 s_view1_anomalythresholdbutton =
2726 gtk_button_new_with_label ("Anomaly Threshold");
2728 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2730 s_view1_endbutton = gtk_button_new_with_label("End");
2732 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2733 GTK_SIGNAL_FUNC(view1_button_click_callback),
2734 (gpointer) START_BUTTON);
2736 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2737 GTK_SIGNAL_FUNC(view1_button_click_callback),
2738 (gpointer) ZOOMIN_BUTTON);
2740 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2741 GTK_SIGNAL_FUNC(view1_button_click_callback),
2742 (gpointer) SEARCH_BUTTON);
2744 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2745 GTK_SIGNAL_FUNC(view1_button_click_callback),
2746 (gpointer) SEARCH_AGAIN_BUTTON);
2748 gtk_signal_connect (GTK_OBJECT(s_view1_anomalybutton), "clicked",
2749 GTK_SIGNAL_FUNC(view1_button_click_callback),
2750 (gpointer) ANOMALY_BUTTON);
2752 gtk_signal_connect (GTK_OBJECT(s_view1_anomalynextbutton), "clicked",
2753 GTK_SIGNAL_FUNC(view1_button_click_callback),
2754 (gpointer) ANOMALY_NEXT_BUTTON);
2756 gtk_signal_connect (GTK_OBJECT(s_view1_anomalythresholdbutton),
2757 "clicked", GTK_SIGNAL_FUNC(view1_button_click_callback),
2758 (gpointer) ANOMALY_THRESHOLD_BUTTON);
2760 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2761 GTK_SIGNAL_FUNC(view1_button_click_callback),
2762 (gpointer) ZOOMOUT_BUTTON);
2764 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2765 GTK_SIGNAL_FUNC(view1_button_click_callback),
2766 (gpointer) END_BUTTON);
2768 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
2769 0.0 /* minimum value */,
2770 2000.0 /* maximum value */,
2771 0.1 /* step increment */,
2772 10.0/* page increment */,
2773 10.0/* page size */);
2775 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2777 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2778 GTK_SIGNAL_FUNC (view1_hscroll),
2779 (gpointer)s_view1_hscroll);
2781 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2784 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2787 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2790 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2793 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalybutton,
2795 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalynextbutton,
2797 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2800 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2803 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2806 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2809 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2813 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2815 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2817 s_view1_nextbutton = gtk_button_new_with_label("Next");
2819 s_view1_delbutton = gtk_button_new_with_label("Del");
2821 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2823 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2825 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2827 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2829 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2830 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2832 s_view1_summary_button = gtk_button_new_with_label("Summary");
2833 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2835 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2836 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2838 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2839 GTK_SIGNAL_FUNC(view1_button_click_callback),
2840 (gpointer) SNAP_BUTTON);
2842 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2843 GTK_SIGNAL_FUNC(view1_button_click_callback),
2844 (gpointer) NEXT_BUTTON);
2846 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2847 GTK_SIGNAL_FUNC(view1_button_click_callback),
2848 (gpointer) DEL_BUTTON);
2850 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
2851 GTK_SIGNAL_FUNC(view1_button_click_callback),
2852 (gpointer) CHASE_EVENT_BUTTON);
2854 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
2855 GTK_SIGNAL_FUNC(view1_button_click_callback),
2856 (gpointer) CHASE_DATUM_BUTTON);
2858 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
2859 GTK_SIGNAL_FUNC(view1_button_click_callback),
2860 (gpointer) CHASE_TRACK_BUTTON);
2862 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2863 GTK_SIGNAL_FUNC(view1_button_click_callback),
2864 (gpointer) UNCHASE_BUTTON);
2866 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2867 GTK_SIGNAL_FUNC(view1_button_click_callback),
2868 (gpointer) FORWARD_BUTTON);
2870 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2871 GTK_SIGNAL_FUNC(view1_button_click_callback),
2872 (gpointer) BACKWARD_BUTTON);
2874 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2875 GTK_SIGNAL_FUNC(view1_button_click_callback),
2876 (gpointer) SUMMARY_BUTTON);
2878 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2879 GTK_SIGNAL_FUNC(view1_button_click_callback),
2880 (gpointer) NOSUMMARY_BUTTON);
2882 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
2883 GTK_SIGNAL_FUNC(view1_button_click_callback),
2884 (gpointer) SLEW_LEFT_BUTTON);
2886 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
2887 GTK_SIGNAL_FUNC(view1_button_click_callback),
2888 (gpointer) SLEW_RIGHT_BUTTON);
2890 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2893 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2896 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2899 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2902 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2905 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2908 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2911 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2914 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2917 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2920 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2923 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2926 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2927 s_view1_time_slew_left_button,
2930 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2931 s_view1_time_slew_right_button,
2934 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2935 s_view1_anomalythresholdbutton,
2938 s_view1_label = gtk_label_new(NULL);
2940 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2943 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2946 gtk_widget_show_all (s_view1_vbox);
2947 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2948 gtk_widget_grab_focus(da);
2950 gtk_widget_hide (s_view1_forward_button);
2951 gtk_widget_hide (summary_mode ? s_view1_summary_button
2952 : s_view1_nosummary_button);
2954 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2956 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2959 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2961 &bg_white, zi_x_hot,
2963 gdk_pixmap_unref (zi_source);
2964 gdk_pixmap_unref (zi_mask);
2966 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2969 /****************************************************************************
2971 ****************************************************************************/
2973 void line_print (int x1, int y1, int x2, int y2)
2975 fprintf(s_printfp, "newpath\n");
2976 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
2977 yrt(x1, s_v1->total_height - y1));
2979 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2980 yrt (x2, s_v1->total_height - y2));
2981 fprintf(s_printfp, "1 setlinewidth\n");
2982 fprintf(s_printfp, "stroke\n");
2985 /****************************************************************************
2987 ****************************************************************************/
2988 GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2991 if (function == TBOX_PRINT_BOXED) {
2995 if ((function == TBOX_PRINT_BOXED) ||
2996 (function == TBOX_PRINT_EVENT)) {
2998 fprintf(s_printfp, "newpath\n");
2999 fprintf(s_printfp, "0 setlinewidth\n");
3000 fprintf(s_printfp, "%d %d moveto\n",
3001 xrt(rp->x, s_v1->total_height - rp->y),
3002 yrt(rp->x, s_v1->total_height - rp->y));
3004 fprintf(s_printfp, "%d %d lineto\n",
3005 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
3006 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
3008 fprintf(s_printfp, "%d %d lineto\n",
3009 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
3010 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
3012 fprintf(s_printfp, "%d %d lineto\n",
3013 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
3014 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
3016 fprintf(s_printfp, "%d %d lineto\n",
3017 xrt(rp->x, s_v1->total_height - rp->y),
3018 yrt(rp->x, s_v1->total_height - rp->y));
3020 fprintf(s_printfp, "stroke\n");
3023 if ((function == TBOX_PRINT_BOXED) ||
3024 (function == TBOX_PRINT_PLAIN)) {
3026 fprintf(s_printfp, "newpath\n");
3027 fprintf(s_printfp, "%d %d moveto\n",
3028 xrt(x, s_v1->total_height - (y-2)),
3029 yrt(x, s_v1->total_height - (y-2)));
3030 fprintf(s_printfp, "gsave\n");
3031 fprintf(s_printfp, "90 rotate\n");
3032 fprintf(s_printfp, "(%s) show\n", s);
3033 fprintf(s_printfp, "grestore\n");
3039 /****************************************************************************
3040 * tbox - draws an optionally boxed string whose lower lefthand
3041 * corner is at (x, y). As usual, Y is backwards.
3042 ****************************************************************************/
3044 GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
3046 static GdkRectangle update_rect;
3047 gint lbearing, rbearing, width, ascent, descent;
3049 gdk_string_extents (g_font, s,
3050 &lbearing, &rbearing,
3051 &width, &ascent, &descent);
3054 * If we have enough room to display full size events, then just
3055 * use the BOXED function instead of the EVENT function.
3057 if (s_v1->strip_height > 9) {
3059 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
3060 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
3061 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
3069 case TBOX_DRAW_BOXED:
3070 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3071 x, y - (ascent+descent+3), width + 2,
3072 ascent + descent + 3);
3074 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3075 x, y - (ascent+descent+3), width + 2,
3076 ascent + descent + 3);
3078 gdk_draw_string (pm, g_font, da->style->black_gc,
3079 x + 1, y - 1, (const gchar *)s);
3080 /* NOTE FALLTHROUGH */
3081 case TBOX_GETRECT_BOXED:
3083 update_rect.y = y -(ascent+descent+3);
3084 update_rect.width = width + 3;
3085 update_rect.height = ascent + descent + 4;
3086 if (function == TBOX_DRAW_BOXED)
3087 gtk_widget_draw (da, &update_rect);
3090 case TBOX_DRAW_EVENT:
3091 /* We have a small event to draw...no text */
3092 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3094 /* NOTE FALLTHROUGH */
3095 case TBOX_GETRECT_EVENT:
3097 update_rect.y = y - 1;
3098 update_rect.width = 4;
3099 update_rect.height = 4;
3100 if (function == TBOX_DRAW_EVENT)
3101 gtk_widget_draw (da, &update_rect);
3105 case TBOX_DRAW_PLAIN:
3107 gdk_draw_string (pm, g_font, da->style->black_gc,
3108 x + 1, y - 1, (const gchar *)s);
3109 /* NOTE FALLTHROUGH */
3110 case TBOX_GETRECT_PLAIN:
3112 update_rect.y = y -(ascent+descent+1);
3113 update_rect.width = width;
3114 update_rect.height = ascent + descent;
3115 if (function == TBOX_DRAW_PLAIN)
3116 gtk_widget_draw (da, &update_rect);
3119 case TBOX_PRINT_BOXED:
3121 update_rect.y = y -(ascent+descent+3);
3122 update_rect.width = width + 3;
3123 update_rect.height = ascent + descent + 4;
3124 /* note fallthrough */
3125 case TBOX_PRINT_PLAIN:
3126 return(tbox_print(s, x, y, function, &update_rect));
3128 case TBOX_PRINT_EVENT:
3129 /* We have a small event box to print...no text */
3131 update_rect.y = y - 1;
3132 update_rect.width = 4;
3133 update_rect.height = 4;
3134 return(tbox_print(s, x, y, function, &update_rect));
3136 return(&update_rect);
3139 /****************************************************************************
3142 * For lines there is a primitive batching facility, that doesn't update
3143 * the drawing area until the batch is complete. This is handy for drawing
3144 * the pid axis and for summary mode.
3146 * line_batch_mode contains the state for this:
3148 * BATCH_OFF: no batching, update for every line
3149 * BATCH_NEW: just entered a batch, so initialize the area to update from
3151 * BATCH_EXISTING: have drawn at least one line in batch mode, so the update
3152 * area should only be expanded from now on to include the
3153 * union of the "rectangular hull" of all lines
3154 ****************************************************************************/
3156 static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
3157 static int line_batch_count;
3158 static int line_minx, line_miny, line_maxx, line_maxy;
3160 void line_batch_start (void)
3162 line_batch_mode = BATCH_NEW;
3163 line_batch_count = 0;
3166 void line_batch_end (void)
3168 GdkRectangle update_rect;
3169 if (line_batch_count > 0) {
3170 update_rect.x = line_minx;
3171 update_rect.y = line_miny;
3172 update_rect.width = (line_maxx - line_minx) + 1;
3173 update_rect.height = (line_maxy - line_miny) + 1;
3174 gtk_widget_draw (da, &update_rect);
3176 line_batch_mode = BATCH_OFF;
3179 void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
3181 GdkRectangle update_rect;
3185 case LINE_DRAW_BLACK:
3186 gc = da->style->black_gc;
3189 case LINE_DRAW_WHITE:
3190 gc = da->style->white_gc;
3194 line_print (x1, y1, x2, y2);
3198 gdk_draw_line (pm, gc, x1, y1, x2, y2);
3200 switch (line_batch_mode) {
3204 update_rect.width = (x2-x1) + 1;
3205 update_rect.height = (y2-y1) + 1;
3206 gtk_widget_draw (da, &update_rect);
3214 line_batch_mode = BATCH_EXISTING;
3215 line_batch_count = 1;
3218 case BATCH_EXISTING:
3233 /****************************************************************************
3235 ****************************************************************************/
3237 static void display_pid_axis(v1_geometry_t *vp)
3239 int y, i, label_tick;
3240 int last_printed_y = -vp->strip_height;
3246 /* No pids yet? Outta here */
3252 for (i = 0; i < vp->npids; i++) {
3253 pid_index = vp->first_pid_index + i;
3254 if (pid_index >= g_npids)
3257 pp = (g_pids + pid_index);
3259 set_color(pid_index);
3261 label_fmt = get_track_label(pp->pid_value);
3262 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
3264 y = i*vp->strip_height + vp->pid_ax_offset;
3267 * Have we incremented enough space to have another label not
3268 * overlap the previous label?
3270 if (y - last_printed_y > 9) {
3272 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
3277 * And let the line stick out a bit more to indicate this label
3278 * relates to the following line.
3286 /* Draw axis line, but only if the lines aren't too close together */
3287 if (vp->strip_height > 4) {
3288 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
3289 vp->total_width, y+4*s_print_offset,
3290 LINE_DRAW_BLACK+s_print_offset);
3294 set_color(COLOR_DEFAULT);
3298 /****************************************************************************
3299 * view1_read_events_callback
3300 * New event data just showed up, reset a few things.
3301 ****************************************************************************/
3303 void view1_read_events_callback(void)
3307 s_v1->first_pid_index = 0;
3309 max_vis_index = 300;
3310 if (max_vis_index > g_nevents)
3311 max_vis_index = g_nevents-1;
3313 s_v1->minvistime = 0LL;
3314 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
3315 /* Single event? Make the initial display 1s wide */
3317 s_v1->maxvistime = 1000000;
3320 s_last_selected_event = 0;
3322 init_track_colors();
3324 recompute_hscrollbar();
3325 recompute_vscrollbar();
3328 /****************************************************************************
3329 * display_event_data
3330 ****************************************************************************/
3332 static void display_event_data(v1_geometry_t *vp)
3339 double time_per_pixel;
3341 GdkRectangle *print_rect;
3344 /* Happens if one loads the event def header first, for example. */
3348 time_per_pixel = dtime_per_pixel(vp);
3350 start_index = find_event_index (vp->minvistime);
3352 /* Scrolled too far right? */
3353 if (start_index >= g_nevents)
3356 ep = (g_events + start_index);
3358 if (s_print_offset || summary_mode) {
3359 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3366 while (ep < (g_events + g_nevents) &&
3367 (ep->time < vp->maxvistime)) {
3368 pid_index = ep->pid->pid_index;
3369 set_color(pid_index);
3371 /* First filter: pid out of range */
3372 if ((pid_index < vp->first_pid_index) ||
3373 (pid_index >= vp->first_pid_index + vp->npids)) {
3378 /* Second filter: event hidden */
3379 edp = find_event_definition (ep->code);
3380 if (!edp->selected) {
3387 pid_index -= vp->first_pid_index;
3389 y = pid_index*vp->strip_height + vp->event_offset;
3391 x = vp->pid_ax_width +
3392 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3394 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3399 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3400 if (ep->flags & EVENT_FLAG_SELECT) {
3401 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3403 sprintf(tmpbuf, edp->name);
3404 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3405 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3408 sprintf(tmpbuf, "SEARCH RESULT");
3410 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3411 TBOX_DRAW_BOXED+s_print_offset);
3412 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3413 if (last_x_used != NULL)
3414 last_x_used[pid_index] = x + print_rect->width;
3417 int delta = vp->strip_height / 3;
3420 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3421 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3422 last_x_used[pid_index] = x + 1;
3424 sprintf(tmpbuf, "%ld", ep->code);
3425 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3426 if (last_x_used != NULL)
3427 last_x_used[pid_index] = x + print_rect->width;
3433 g_free(last_x_used);
3435 set_color(COLOR_DEFAULT);
3438 /****************************************************************************
3440 ****************************************************************************/
3442 static void display_clear(void)
3444 GdkRectangle update_rect;
3446 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3447 0, 0, da->allocation.width,
3448 da->allocation.height);
3452 update_rect.width = da->allocation.width;
3453 update_rect.height = da->allocation.height;
3455 gtk_widget_draw (da, &update_rect);
3458 /****************************************************************************
3460 ****************************************************************************/
3462 static void display_time_axis(v1_geometry_t *vp)
3465 int xoffset, nticks;
3467 double unit_divisor;
3470 double time_per_pixel;
3472 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3474 x = vp->pid_ax_width;
3476 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3478 time_per_pixel = dtime_per_pixel(vp);
3481 unit_divisor = 1.00;
3483 if ((vp->maxvistime / unit_divisor) > 1000) {
3485 unit_divisor = 1000.00;
3488 if ((vp->maxvistime / unit_divisor) > 1000) {
3490 unit_divisor = 1000.00*1000.00;
3492 if ((vp->maxvistime / unit_divisor) > 1000) {
3494 unit_divisor = 1000.00*1000.00*1000.00;
3498 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3502 for (i = 0; i < nticks; i++) {
3504 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3506 time = (double)(x + xoffset - vp->pid_ax_width);
3507 time *= time_per_pixel;
3508 time += (double)(vp->minvistime);
3509 time /= unit_divisor;
3511 sprintf (tmpbuf, "%.2f%s", time, units);
3513 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3515 xoffset += vp->time_ax_spacing;
3519 /****************************************************************************
3521 * Forget about any temporary displays, they're gone now...
3522 ****************************************************************************/
3524 static void clear_scoreboard(void)
3526 s_result_up = FALSE;
3529 /****************************************************************************
3531 ****************************************************************************/
3533 void view1_display(void)
3536 display_pid_axis(s_v1);
3537 display_event_data(s_v1);
3538 display_time_axis(s_v1);
3542 static gint idle_tag;
3544 /****************************************************************************
3545 * view1_display_eventually
3546 ****************************************************************************/
3548 static void view1_display_eventually(void)
3550 gtk_idle_remove(idle_tag);
3556 /****************************************************************************
3557 * view1_display_when_idle
3558 ****************************************************************************/
3560 void view1_display_when_idle(void)
3562 if (idle_tag == 0) {
3563 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3567 /****************************************************************************
3569 ****************************************************************************/
3571 void view1_about (char *tmpbuf)
3576 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3577 s_v1->minvistime, s_v1->maxvistime);
3578 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
3579 s_v1->strip_height);
3581 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3584 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);