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)
1635 /* Gather summary statistics... */
1638 vec_reset_length (s_v1->means);
1639 vec_reset_length (s_v1->matches);
1640 vec_reset_length (s_v1->variances);
1641 vec_reset_length (s_v1->two_stddevs);
1642 vec_reset_length (s_v1->mins);
1643 vec_reset_length (s_v1->maxes);
1645 for (i = 0; i < g_nevents; i++) {
1646 if (ep->code != s_anomalycode) {
1651 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
1652 vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
1653 vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
1654 vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
1655 eep = get_clib_event (ep->datum);
1656 data = clib_mem_unaligned (eep->data, u32);
1658 s_v1->means[pid->pid_index] += fdata;
1659 s_v1->matches[pid->pid_index] += 1;
1660 /* First data point? set min, max */
1661 if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
1662 s_v1->mins[pid->pid_index] = fdata;
1663 s_v1->maxes[pid->pid_index] = fdata;
1665 s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
1666 fdata : s_v1->mins[pid->pid_index];
1667 s_v1->maxes[pid->pid_index] =
1668 (fdata > s_v1->maxes[pid->pid_index]) ?
1669 fdata : s_v1->maxes[pid->pid_index];
1673 if (vec_len (s_v1->matches) == 0)
1676 /* Compute s_v1->means */
1677 for (i = 0; i < vec_len (s_v1->means); i++)
1678 s_v1->means[i] = s_v1->matches[i]
1679 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1681 /* Compute s_v1->variances */
1683 for (i = 0; i < g_nevents; i++) {
1684 if (ep->code != s_anomalycode) {
1689 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1690 eep = get_clib_event (ep->datum);
1691 data = clib_mem_unaligned (eep->data, u32);
1693 s_v1->variances[pid->pid_index] +=
1694 (fdata - s_v1->means[pid->pid_index])
1695 * (fdata - s_v1->means[pid->pid_index]);
1699 /* Normalize variances */
1700 for (i = 0; i < vec_len (s_v1->variances); i++)
1701 s_v1->variances[i] = s_v1->matches[i]
1702 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1704 /* Compute the anomaly threshold, by default 2.5*stddev */
1705 for (i = 0; i < vec_len (s_v1->variances); i++)
1706 vec_add1 (s_v1->two_stddevs,
1707 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1711 /****************************************************************************
1712 * anomaly_search_internal
1713 * This routine searches forward from s_srchindex, looking for s_srchcode;
1714 * wraps at the end of the buffer.
1715 ****************************************************************************/
1717 boolean anomaly_search_internal (void)
1726 boolean full_redisplay = FALSE;
1727 ulonglong current_width;
1731 if (vec_len (s_v1->matches) == 0)
1732 anomaly_statistics_init();
1734 ep = (g_events + s_srchindex);
1735 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1738 * If the user rearranged the screen, start from the minimum
1741 if (ep->time < s_v1->minvistime)
1742 s_srchindex = find_event_index (s_v1->minvistime);
1744 for (i = 1; i <= g_nevents; i++) {
1745 index = (i + s_srchindex) % g_nevents;
1747 ep = (g_events + index);
1748 if (ep->code != s_anomalycode)
1752 eep = get_clib_event (ep->datum);
1753 data = clib_mem_unaligned (eep->data, u32);
1757 * Found an anomaly? Define an anomaly as a datum
1758 * greater than 2*stddev above average.
1760 if ((fdata - s_v1->means[pid->pid_index]) >
1761 s_v1->two_stddevs[pid->pid_index]) {
1764 s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
1765 s_v1->anomaly_threshold_stddevs);
1767 for (i = 0; i < vec_len (s_v1->means); i++) {
1768 if (s_v1->matches[i] > 0)
1769 s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
1770 s_v1->mins[i], s_v1->maxes[i],
1772 s_v1->means[i]+s_v1->two_stddevs[i]);
1774 s = format (s, "{no match} ");
1777 message_line ((char *)s);
1780 s_srchindex = index;
1781 pid_index = ep->pid->pid_index;
1783 /* Need a vertical scroll? */
1784 if ((pid_index < s_v1->first_pid_index) ||
1785 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1786 if (pid_index > (g_npids - s_v1->npids))
1787 pid_index = (g_npids - s_v1->npids);
1788 s_v1->first_pid_index = pid_index;
1789 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1790 (gdouble)s_v1->first_pid_index;
1791 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1792 full_redisplay = TRUE;
1795 /* Need a horizontal scroll? */
1796 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1797 current_width = (s_v1->maxvistime - s_v1->minvistime);
1798 if (ep->time < ((current_width+1) / 2)) {
1799 s_v1->minvistime = 0ll;
1800 s_v1->maxvistime = current_width;
1802 s_v1->minvistime = ep->time - ((current_width+1)/2);
1803 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1805 recompute_hscrollbar();
1806 full_redisplay = TRUE;
1808 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1809 full_redisplay = TRUE;
1812 view1_display_when_idle();
1817 sprintf (tmpbuf, "Search for an anomalous event %ld failed...\n",
1819 message_line(tmpbuf);
1820 s_srchfail_up = TRUE;
1824 /****************************************************************************
1825 * anomaly_search_callback
1826 ****************************************************************************/
1828 boolean anomaly_search_callback (char *s)
1830 ulong new_anomalycode;
1832 /* No events yet? Act like the search worked, to avoid a loop */
1836 new_anomalycode = atol(s);
1838 if (new_anomalycode == 0)
1841 if (new_anomalycode != s_anomalycode ||
1842 vec_len (s_v1->matches) == 0) {
1843 s_anomalycode = new_anomalycode;
1844 if (anomaly_statistics_init()) {
1847 s = format (0, "Search for an anomalous event %ld failed...\n",
1849 message_line ((char *) s);
1854 return(anomaly_search_internal());
1857 /****************************************************************************
1858 * anomaly_threshold_callback
1859 ****************************************************************************/
1861 boolean anomaly_threshold_callback (char *s)
1865 /* No events yet? Act like the search worked, to avoid a loop */
1869 new_threshold = atof (s);
1871 if (new_threshold == 0.0 || new_threshold > 10.0)
1874 s_v1->anomaly_threshold_stddevs = new_threshold;
1876 vec_reset_length (s_v1->means);
1877 vec_reset_length (s_v1->matches);
1878 vec_reset_length (s_v1->variances);
1879 vec_reset_length (s_v1->two_stddevs);
1883 /****************************************************************************
1885 ****************************************************************************/
1887 static void event_search (void)
1889 modal_dialog ("Event Search: Please Enter Event Code",
1890 "Invalid: Please Reenter Event Code", NULL,
1891 event_search_callback);
1894 /****************************************************************************
1896 ****************************************************************************/
1898 static void anomaly_search (void)
1900 modal_dialog ("Anomaly Search: Please Enter Event Code",
1901 "Invalid: Please Reenter Event Code", NULL,
1902 anomaly_search_callback);
1905 /****************************************************************************
1907 ****************************************************************************/
1909 static void anomaly_threshold (void)
1911 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1912 "Invalid: Please Reenter Threshold in Standard Deviations",
1913 NULL, anomaly_threshold_callback);
1916 /****************************************************************************
1918 ****************************************************************************/
1919 static void init_track_colors(void)
1925 gboolean dont_care[g_npids];
1928 * If we've already allocated the colors once, then in theory we should
1929 * just be able to re-order the GCs already created to match the new track
1930 * order; the track -> color mapping doesn't currently change at runtime.
1931 * However, it's easier just to allocate everything from fresh. As a nod in
1932 * the direction of politeness towards our poor abused X server, we at
1933 * least mop up the previously allocated GCs first, although in practice
1934 * even omitting this didn't seem to cause a problem.
1936 if (s_color != NULL ) {
1937 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
1939 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
1942 * First time through: allocate the array to hold the GCs.
1944 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
1948 * Go through and assign a color for each track.
1950 /* Setup entry 0 in the colormap as pure red (for selection) */
1951 s_color[0] = fg_red;
1953 for (i = 1; i < g_npids; i++) {
1955 * We compute the color from a hash of the thread name. That way we get
1956 * a distribution of different colors, and the same thread has the same
1957 * color across multiple data sets. Unfortunately, even though the
1958 * process name and thread id are invariant across data sets, the
1959 * process id isn't, so we want to exclude that from the hash. Since
1960 * the pid appears in parentheses after the process name and tid, we
1961 * can just stop at the '(' character.
1963 * We could create a substring and use the CLIB Jenkins hash, but given
1964 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1965 * just as good, and it's easiest just to compute it inline.
1967 label_char = get_track_label(g_pids[i].pid_value);
1969 while (*label_char != '\0' && *label_char != '(') {
1970 hash = hash * 33 + *label_char++;
1972 hash += hash >> 5; /* even out the lower order bits a touch */
1975 * OK, now we have our hash. We get the color by using the first three
1976 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1977 * and then use the fourth byte to choose one of R, G, B and mask this
1978 * one down. This ensures the color can't be too close to white and
1979 * therefore hard to see.
1981 * We also drop the top bit of the green, since bright green on its own
1982 * is hard to see against white. Generally we err on the side of
1983 * keeping it dark, rather than using the full spectrum of colors. This
1984 * does result in something of a preponderance of muddy colors and a
1985 * bit of a lack of cheery bright ones, but at least you can read
1986 * everything. It would be nice to do better.
1988 RGB[0] = (hash & 0xff000000) >> 16;
1989 RGB[1] = (hash & 0x007f0000) >> 8;
1990 RGB[2] = (hash & 0x0000ff00);
1991 RGB[hash % 3] &= 0x1fff;
1994 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1996 g_pids[i].color_index = i;
2001 * Actually allocate the colors in one bulk operation. We ignore the return
2004 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
2005 s_color, g_npids+1, FALSE, TRUE, dont_care);
2009 /****************************************************************************
2011 * Reorder the pid_index fields so the viewer "chases" the last selected
2013 ****************************************************************************/
2015 static void chase_event_etc(enum chase_mode mode)
2017 pid_sort_t *psp, *new_pidvec;
2021 ulong code_to_chase;
2022 ulong datum_to_chase;
2027 if (!s_last_selected_event) {
2028 infobox("No selected event",
2029 "\nPlease select an event and try again...\n");
2033 /* Clear all index assignments */
2035 for (i = 0; i < g_npids; i++) {
2037 pp->pid_index = 0xFFFFFFFF;
2041 ep = s_last_selected_event;
2042 code_to_chase = ep->code;
2043 datum_to_chase = ep->datum;
2044 pid_to_chase = ep->pid->pid_value;
2046 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
2049 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2050 if (ep >= g_events + g_nevents)
2060 if (ep->code == code_to_chase) {
2066 if (ep->datum == datum_to_chase) {
2072 if (ep->pid->pid_value == pid_to_chase) {
2078 infobox("BUG", "unknown mode in chase_event_etc\n");
2083 if (ep->pid->pid_index == 0xFFFFFFFF) {
2084 ep->pid->pid_index = pids_mapped;
2085 new_pidvec[pids_mapped].pid = ep->pid;
2086 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2087 new_pidvec[pids_mapped].color_index = 0;
2089 if (pids_mapped == g_npids)
2093 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2099 /* Pass 2, first-to-last, to collect stragglers */
2102 while (ep < g_events + g_nevents) {
2103 if (ep->pid->pid_index == 0xFFFFFFFF) {
2104 ep->pid->pid_index = pids_mapped;
2105 new_pidvec[pids_mapped].pid = ep->pid;
2106 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2107 new_pidvec[pids_mapped].color_index = 0;
2109 if (pids_mapped == g_npids)
2115 if (pids_mapped != g_npids) {
2116 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2120 g_pids = new_pidvec;
2123 * The new g_pids vector contains the "chase" sort, so we revert
2124 * the pid_index mapping to an identity map
2128 for (i = 0; i < g_npids; i++) {
2134 /* AutoScroll the PID axis so we show the first "chased" event */
2135 s_v1->first_pid_index = 0;
2136 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2137 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2138 init_track_colors();
2139 view1_display_when_idle();
2142 /****************************************************************************
2144 * Copy g_original_pids to g_pids, revert index mapping
2145 ****************************************************************************/
2146 static void unchase_event_etc(void)
2152 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
2154 /* Fix the pid structure index mappings */
2157 for (i = 0; i < g_npids; i++) {
2163 /* Scroll PID axis to the top */
2164 s_v1->first_pid_index = 0;
2165 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2166 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2167 init_track_colors();
2168 view1_display_when_idle();
2171 /****************************************************************************
2173 * To fit a reasonable-sized landscape mode plot onto letter-size paper,
2174 * scale everything by .75.
2175 ****************************************************************************/
2177 static void print_ps_header (v1_geometry_t *vp, char *filename)
2183 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2184 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2185 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2186 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2187 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2188 fprintf(s_printfp, "%%%%Origin: 0 0\n");
2189 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
2191 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2192 fprintf(s_printfp, "%%%%Pages: 1\n");
2193 fprintf(s_printfp, "%%%%Page: 1 1\n");
2194 fprintf(s_printfp, "%%%%EOF\n");
2195 fprintf(s_printfp, "/Times-Roman findfont\n");
2196 fprintf(s_printfp, "12 scalefont\n");
2197 fprintf(s_printfp, "setfont\n");
2198 fprintf(s_printfp, ".75 .75 scale\n");
2201 /****************************************************************************
2203 * Xcoordinate rotate and translate. We need to emit postscript that
2204 * has a reasonable aspect ratio for printing. To do that, we rotate the
2205 * intended picture by 90 degrees, using the standard 2D rotation
2208 * Xr = x*cos(theta) - y*sin(theta);
2209 * Yr = x*sin(theta) + y*cos(theta);
2211 * If we let theta = 90, this reduces to
2215 * Translate back to the origin in X by adding Ymax, yielding
2217 ****************************************************************************/
2219 static inline int xrt(int x, int y)
2221 return (s_v1->total_height - y);
2224 static inline int yrt(int x, int y)
2229 /****************************************************************************
2230 * print_screen_callback
2231 ****************************************************************************/
2233 static boolean print_screen_callback(char *filename)
2235 s_printfp = fopen (filename, "wt");
2237 if (s_printfp == NULL)
2241 * This variable allows us to magically turn the view1 display
2242 * code into a print-driver, with a minimum of fuss. The idea is to
2243 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2244 * the required value, aka s_print_offset.
2245 * Make sure to fix g2.h if you mess here, or vice versa.
2247 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2249 print_ps_header(s_v1, filename);
2251 display_pid_axis(s_v1);
2252 display_event_data(s_v1);
2253 display_time_axis(s_v1);
2259 /* For tactile feedback */
2260 view1_display_when_idle();
2264 int event_time_cmp (const void *a, const void *b)
2266 const event_t *e1 = a;
2267 const event_t *e2 = b;
2269 if (e1->time < e2->time)
2271 else if (e1->time > e2->time)
2276 /****************************************************************************
2278 ****************************************************************************/
2279 static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2286 delta = (ulonglong) (vp->last_time_interval);
2288 /* Make sure we don't push events to the left of the big bang */
2289 if (which == SLEW_LEFT_BUTTON) {
2290 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2291 pid_index = ep->pid->pid_index;
2292 pp = (g_pids + pid_index);
2295 if (ep->time < delta) {
2296 infobox("Slew Range Error",
2297 "\nCan't slew selected data left that far..."
2298 "\nEvents would preceed the Big Bang (t=0)...");
2305 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2306 pid_index = ep->pid->pid_index;
2307 pp = (g_pids + pid_index);
2310 if (which == SLEW_LEFT_BUTTON)
2317 /* Re-sort the events, to avoid screwing up the event display */
2318 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2320 /* De-select tracks */
2324 view1_display_when_idle();
2327 /****************************************************************************
2328 * view1_button_click_callback
2329 ****************************************************************************/
2331 static void view1_button_click_callback(GtkButton *item, gpointer data)
2333 enum view1_button_click click = (enum view1_button_click) data;
2335 ulonglong event_incdec;
2336 ulonglong current_width;
2337 ulonglong zoom_delta;
2339 current_width = s_v1->maxvistime - s_v1->minvistime;
2340 event_incdec = (current_width) / 3;
2342 if (event_incdec == 0LL)
2345 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2349 /* First PID to top of window */
2350 s_v1->first_pid_index = 0;
2351 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2352 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2356 s_v1->first_pid_index = g_npids - s_v1->npids;
2357 if (s_v1->first_pid_index < 0)
2358 s_v1->first_pid_index = 0;
2359 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2360 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2375 case CHASE_EVENT_BUTTON:
2376 chase_event_etc(CHASE_EVENT);
2379 case CHASE_DATUM_BUTTON:
2380 chase_event_etc(CHASE_DATUM);
2383 case CHASE_TRACK_BUTTON:
2384 chase_event_etc(CHASE_TRACK);
2387 case UNCHASE_BUTTON:
2388 unchase_event_etc();
2393 s_v1->minvistime = 0LL;
2394 s_v1->maxvistime = current_width;
2395 recompute_hscrollbar();
2399 s_v1->minvistime += zoom_delta;
2400 s_v1->maxvistime -= zoom_delta;
2401 recompute_hscrollbar();
2404 case SEARCH_AGAIN_BUTTON:
2406 event_search_internal();
2409 /* NOTE FALLTHROUGH */
2415 case ANOMALY_THRESHOLD_BUTTON:
2416 anomaly_threshold();
2419 case ANOMALY_NEXT_BUTTON:
2420 if (s_anomalycode) {
2421 anomaly_search_internal();
2424 /* NOTE FALLTHROUGH */
2426 case ANOMALY_BUTTON:
2430 case ZOOMOUT_BUTTON:
2431 if (zoom_delta == 0LL)
2434 if (s_v1->minvistime >= zoom_delta) {
2435 s_v1->minvistime -= zoom_delta;
2436 s_v1->maxvistime += zoom_delta;
2438 s_v1->minvistime = 0;
2439 s_v1->maxvistime += zoom_delta*2;
2442 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
2443 g_events[g_nevents-1].time * 9) {
2444 s_v1->minvistime = 0;
2445 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
2446 /* Single event? Make window 1s wide... */
2448 s_v1->maxvistime = 1000000;
2451 recompute_hscrollbar();
2455 ep = (g_events + g_nevents - 1);
2456 s_v1->maxvistime = ep->time + event_incdec/3;
2457 s_v1->minvistime = s_v1->maxvistime - current_width;
2458 if (s_v1->minvistime > s_v1->maxvistime)
2460 recompute_hscrollbar();
2463 case MORE_TRACES_BUTTON:
2464 /* Reduce the strip height to fit more traces on screen */
2465 s_v1->strip_height -= 1;
2467 if (s_v1->strip_height < 1) {
2468 s_v1->strip_height = 1;
2471 /* Recalculate the number of strips on the screen */
2472 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2474 recompute_vscrollbar();
2477 case LESS_TRACES_BUTTON:
2478 /* Increase the strip height to fit fewer on the screen */
2479 s_v1->strip_height += 1;
2480 if (s_v1->strip_height > 80) {
2481 s_v1->strip_height = 80;
2484 /* Recalculate the number of strips on the screen */
2485 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2487 recompute_vscrollbar();
2490 case FORWARD_BUTTON:
2491 srch_chase_dir = SRCH_CHASE_FORWARD;
2492 gtk_widget_hide (s_view1_forward_button);
2493 gtk_widget_show (s_view1_backward_button);
2496 case BACKWARD_BUTTON:
2497 srch_chase_dir = SRCH_CHASE_BACKWARD;
2498 gtk_widget_show (s_view1_forward_button);
2499 gtk_widget_hide (s_view1_backward_button);
2502 case SUMMARY_BUTTON:
2503 summary_mode = TRUE;
2504 gtk_widget_hide (s_view1_summary_button);
2505 gtk_widget_show (s_view1_nosummary_button);
2508 case NOSUMMARY_BUTTON:
2509 summary_mode = FALSE;
2510 gtk_widget_show (s_view1_summary_button);
2511 gtk_widget_hide (s_view1_nosummary_button);
2514 case SLEW_LEFT_BUTTON:
2515 case SLEW_RIGHT_BUTTON:
2516 if (s_v1->last_time_interval < 10e-9) {
2517 infobox("slew", "\nNo time interval set...\n");
2520 slew_tracks (s_v1, click);
2524 view1_display_when_idle();
2527 /****************************************************************************
2528 * view1_print_callback
2529 ****************************************************************************/
2531 void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2533 modal_dialog("Print Screen (PostScript format) to file:",
2534 "Invalid file: Print Screen to file:",
2535 "g2.ps", print_screen_callback);
2538 /****************************************************************************
2540 ****************************************************************************/
2542 static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2544 ulonglong current_width;
2546 current_width = (s_v1->maxvistime - s_v1->minvistime);
2548 s_v1->minvistime = (ulonglong)(adj->value);
2549 s_v1->maxvistime = s_v1->minvistime + current_width;
2551 view1_display_when_idle();
2554 g_print ("adj->lower = %.2f\n", adj->lower);
2555 g_print ("adj->upper = %.2f\n", adj->upper);
2556 g_print ("adj->value = %.2f\n", adj->value);
2557 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2558 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2559 g_print ("adj->page_size = %.2f\n", adj->page_size);
2563 /****************************************************************************
2565 ****************************************************************************/
2567 static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2569 s_v1->first_pid_index = (int)adj->value;
2570 view1_display_when_idle();
2573 void set_pid_ax_width(int width)
2575 s_v1->pid_ax_width = width;
2576 view1_display_when_idle();
2579 /****************************************************************************
2581 ****************************************************************************/
2583 void view1_init(void)
2585 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2586 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2588 s_v1->pid_ax_width = 80;
2589 s_v1->time_ax_height = 80;
2590 s_v1->time_ax_spacing = 100;
2591 s_v1->strip_height = 25;
2592 s_v1->pop_offset = 20;
2593 s_v1->pid_ax_offset = 34;
2594 s_v1->event_offset = 40;
2595 s_v1->total_height = c_view1_draw_height;
2596 s_v1->total_width = c_view1_draw_width;
2597 s_v1->first_pid_index = 0;
2598 s_v1->anomaly_threshold_stddevs =
2599 atof(getprop_default("anomaly_threshold_stddevs", "2.5"));
2600 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2603 s_v1->minvistime = 0;
2604 s_v1->maxvistime = 200;
2606 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2608 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2610 da = gtk_drawing_area_new();
2611 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2612 c_view1_draw_height);
2615 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2616 (GtkSignalFunc) motion_notify_event, NULL);
2619 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2620 (GtkSignalFunc) expose_event, NULL);
2622 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2623 (GtkSignalFunc) configure_event, NULL);
2625 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2626 (GtkSignalFunc) button_press_event, NULL);
2628 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2629 (GtkSignalFunc) button_press_event, NULL);
2631 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2632 (GtkSignalFunc) button_press_event, NULL);
2634 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2635 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2636 | GDK_BUTTON_MOTION_MASK);
2639 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2641 g_font = gdk_font_load ("8x13");
2642 if (g_font == NULL) {
2643 g_error("Couldn't load 8x13 font...\n");
2645 gdk_font_ref(g_font);
2648 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2650 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
2651 0.0 /* minimum value */,
2652 2000.0 /* maximum value */,
2653 0.1 /* step increment */,
2654 10.0/* page increment */,
2655 10.0/* page size */);
2657 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2659 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2660 GTK_SIGNAL_FUNC (view1_vscroll),
2661 (gpointer)s_view1_vscroll);
2663 s_view1_topbutton = gtk_button_new_with_label("Top");
2664 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2666 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2667 GTK_SIGNAL_FUNC(view1_button_click_callback),
2668 (gpointer) TOP_BUTTON);
2670 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2671 GTK_SIGNAL_FUNC(view1_button_click_callback),
2672 (gpointer) BOTTOM_BUTTON);
2674 /* More Traces button and Less Traces button */
2675 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2676 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2677 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
2678 GTK_SIGNAL_FUNC(view1_button_click_callback),
2679 (gpointer) MORE_TRACES_BUTTON);
2680 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
2681 GTK_SIGNAL_FUNC(view1_button_click_callback),
2682 (gpointer) LESS_TRACES_BUTTON);
2685 /* Trick to bottom-justify the menu: */
2686 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2687 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2692 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2695 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2698 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2701 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2704 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2707 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2710 /* Time axis menu */
2712 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2714 s_view1_startbutton = gtk_button_new_with_label("Start");
2716 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2718 s_view1_searchbutton = gtk_button_new_with_label("Search");
2719 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2721 s_view1_anomalybutton = gtk_button_new_with_label("Anomaly");
2722 s_view1_anomalynextbutton = gtk_button_new_with_label("Next Anomaly");
2723 s_view1_anomalythresholdbutton =
2724 gtk_button_new_with_label ("Anomaly Threshold");
2726 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2728 s_view1_endbutton = gtk_button_new_with_label("End");
2730 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2731 GTK_SIGNAL_FUNC(view1_button_click_callback),
2732 (gpointer) START_BUTTON);
2734 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2735 GTK_SIGNAL_FUNC(view1_button_click_callback),
2736 (gpointer) ZOOMIN_BUTTON);
2738 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2739 GTK_SIGNAL_FUNC(view1_button_click_callback),
2740 (gpointer) SEARCH_BUTTON);
2742 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2743 GTK_SIGNAL_FUNC(view1_button_click_callback),
2744 (gpointer) SEARCH_AGAIN_BUTTON);
2746 gtk_signal_connect (GTK_OBJECT(s_view1_anomalybutton), "clicked",
2747 GTK_SIGNAL_FUNC(view1_button_click_callback),
2748 (gpointer) ANOMALY_BUTTON);
2750 gtk_signal_connect (GTK_OBJECT(s_view1_anomalynextbutton), "clicked",
2751 GTK_SIGNAL_FUNC(view1_button_click_callback),
2752 (gpointer) ANOMALY_NEXT_BUTTON);
2754 gtk_signal_connect (GTK_OBJECT(s_view1_anomalythresholdbutton),
2755 "clicked", GTK_SIGNAL_FUNC(view1_button_click_callback),
2756 (gpointer) ANOMALY_THRESHOLD_BUTTON);
2758 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2759 GTK_SIGNAL_FUNC(view1_button_click_callback),
2760 (gpointer) ZOOMOUT_BUTTON);
2762 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2763 GTK_SIGNAL_FUNC(view1_button_click_callback),
2764 (gpointer) END_BUTTON);
2766 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
2767 0.0 /* minimum value */,
2768 2000.0 /* maximum value */,
2769 0.1 /* step increment */,
2770 10.0/* page increment */,
2771 10.0/* page size */);
2773 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2775 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2776 GTK_SIGNAL_FUNC (view1_hscroll),
2777 (gpointer)s_view1_hscroll);
2779 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2782 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2785 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2788 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2791 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalybutton,
2793 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalynextbutton,
2795 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2798 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2801 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2804 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2807 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2811 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2813 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2815 s_view1_nextbutton = gtk_button_new_with_label("Next");
2817 s_view1_delbutton = gtk_button_new_with_label("Del");
2819 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2821 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2823 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2825 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2827 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2828 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2830 s_view1_summary_button = gtk_button_new_with_label("Summary");
2831 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2833 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2834 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2836 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2837 GTK_SIGNAL_FUNC(view1_button_click_callback),
2838 (gpointer) SNAP_BUTTON);
2840 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2841 GTK_SIGNAL_FUNC(view1_button_click_callback),
2842 (gpointer) NEXT_BUTTON);
2844 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2845 GTK_SIGNAL_FUNC(view1_button_click_callback),
2846 (gpointer) DEL_BUTTON);
2848 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
2849 GTK_SIGNAL_FUNC(view1_button_click_callback),
2850 (gpointer) CHASE_EVENT_BUTTON);
2852 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
2853 GTK_SIGNAL_FUNC(view1_button_click_callback),
2854 (gpointer) CHASE_DATUM_BUTTON);
2856 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
2857 GTK_SIGNAL_FUNC(view1_button_click_callback),
2858 (gpointer) CHASE_TRACK_BUTTON);
2860 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2861 GTK_SIGNAL_FUNC(view1_button_click_callback),
2862 (gpointer) UNCHASE_BUTTON);
2864 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2865 GTK_SIGNAL_FUNC(view1_button_click_callback),
2866 (gpointer) FORWARD_BUTTON);
2868 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2869 GTK_SIGNAL_FUNC(view1_button_click_callback),
2870 (gpointer) BACKWARD_BUTTON);
2872 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2873 GTK_SIGNAL_FUNC(view1_button_click_callback),
2874 (gpointer) SUMMARY_BUTTON);
2876 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2877 GTK_SIGNAL_FUNC(view1_button_click_callback),
2878 (gpointer) NOSUMMARY_BUTTON);
2880 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
2881 GTK_SIGNAL_FUNC(view1_button_click_callback),
2882 (gpointer) SLEW_LEFT_BUTTON);
2884 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
2885 GTK_SIGNAL_FUNC(view1_button_click_callback),
2886 (gpointer) SLEW_RIGHT_BUTTON);
2888 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2891 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2894 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2897 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2900 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2903 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2906 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2909 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2912 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2915 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2918 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2921 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2924 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2925 s_view1_time_slew_left_button,
2928 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2929 s_view1_time_slew_right_button,
2932 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2933 s_view1_anomalythresholdbutton,
2936 s_view1_label = gtk_label_new(NULL);
2938 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2941 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2944 gtk_widget_show_all (s_view1_vbox);
2945 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2946 gtk_widget_grab_focus(da);
2948 gtk_widget_hide (s_view1_forward_button);
2949 gtk_widget_hide (summary_mode ? s_view1_summary_button
2950 : s_view1_nosummary_button);
2952 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2954 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2957 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2959 &bg_white, zi_x_hot,
2961 gdk_pixmap_unref (zi_source);
2962 gdk_pixmap_unref (zi_mask);
2964 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2967 /****************************************************************************
2969 ****************************************************************************/
2971 void line_print (int x1, int y1, int x2, int y2)
2973 fprintf(s_printfp, "newpath\n");
2974 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
2975 yrt(x1, s_v1->total_height - y1));
2977 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2978 yrt (x2, s_v1->total_height - y2));
2979 fprintf(s_printfp, "1 setlinewidth\n");
2980 fprintf(s_printfp, "stroke\n");
2983 /****************************************************************************
2985 ****************************************************************************/
2986 GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2989 if (function == TBOX_PRINT_BOXED) {
2993 if ((function == TBOX_PRINT_BOXED) ||
2994 (function == TBOX_PRINT_EVENT)) {
2996 fprintf(s_printfp, "newpath\n");
2997 fprintf(s_printfp, "0 setlinewidth\n");
2998 fprintf(s_printfp, "%d %d moveto\n",
2999 xrt(rp->x, s_v1->total_height - rp->y),
3000 yrt(rp->x, s_v1->total_height - rp->y));
3002 fprintf(s_printfp, "%d %d lineto\n",
3003 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
3004 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
3006 fprintf(s_printfp, "%d %d lineto\n",
3007 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
3008 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
3010 fprintf(s_printfp, "%d %d lineto\n",
3011 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
3012 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
3014 fprintf(s_printfp, "%d %d lineto\n",
3015 xrt(rp->x, s_v1->total_height - rp->y),
3016 yrt(rp->x, s_v1->total_height - rp->y));
3018 fprintf(s_printfp, "stroke\n");
3021 if ((function == TBOX_PRINT_BOXED) ||
3022 (function == TBOX_PRINT_PLAIN)) {
3024 fprintf(s_printfp, "newpath\n");
3025 fprintf(s_printfp, "%d %d moveto\n",
3026 xrt(x, s_v1->total_height - (y-2)),
3027 yrt(x, s_v1->total_height - (y-2)));
3028 fprintf(s_printfp, "gsave\n");
3029 fprintf(s_printfp, "90 rotate\n");
3030 fprintf(s_printfp, "(%s) show\n", s);
3031 fprintf(s_printfp, "grestore\n");
3037 /****************************************************************************
3038 * tbox - draws an optionally boxed string whose lower lefthand
3039 * corner is at (x, y). As usual, Y is backwards.
3040 ****************************************************************************/
3042 GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
3044 static GdkRectangle update_rect;
3045 gint lbearing, rbearing, width, ascent, descent;
3047 gdk_string_extents (g_font, s,
3048 &lbearing, &rbearing,
3049 &width, &ascent, &descent);
3052 * If we have enough room to display full size events, then just
3053 * use the BOXED function instead of the EVENT function.
3055 if (s_v1->strip_height > 9) {
3057 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
3058 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
3059 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
3067 case TBOX_DRAW_BOXED:
3068 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3069 x, y - (ascent+descent+3), width + 2,
3070 ascent + descent + 3);
3072 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3073 x, y - (ascent+descent+3), width + 2,
3074 ascent + descent + 3);
3076 gdk_draw_string (pm, g_font, da->style->black_gc,
3077 x + 1, y - 1, (const gchar *)s);
3078 /* NOTE FALLTHROUGH */
3079 case TBOX_GETRECT_BOXED:
3081 update_rect.y = y -(ascent+descent+3);
3082 update_rect.width = width + 3;
3083 update_rect.height = ascent + descent + 4;
3084 if (function == TBOX_DRAW_BOXED)
3085 gtk_widget_draw (da, &update_rect);
3088 case TBOX_DRAW_EVENT:
3089 /* We have a small event to draw...no text */
3090 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3092 /* NOTE FALLTHROUGH */
3093 case TBOX_GETRECT_EVENT:
3095 update_rect.y = y - 1;
3096 update_rect.width = 4;
3097 update_rect.height = 4;
3098 if (function == TBOX_DRAW_EVENT)
3099 gtk_widget_draw (da, &update_rect);
3103 case TBOX_DRAW_PLAIN:
3105 gdk_draw_string (pm, g_font, da->style->black_gc,
3106 x + 1, y - 1, (const gchar *)s);
3107 /* NOTE FALLTHROUGH */
3108 case TBOX_GETRECT_PLAIN:
3110 update_rect.y = y -(ascent+descent+1);
3111 update_rect.width = width;
3112 update_rect.height = ascent + descent;
3113 if (function == TBOX_DRAW_PLAIN)
3114 gtk_widget_draw (da, &update_rect);
3117 case TBOX_PRINT_BOXED:
3119 update_rect.y = y -(ascent+descent+3);
3120 update_rect.width = width + 3;
3121 update_rect.height = ascent + descent + 4;
3122 /* note fallthrough */
3123 case TBOX_PRINT_PLAIN:
3124 return(tbox_print(s, x, y, function, &update_rect));
3126 case TBOX_PRINT_EVENT:
3127 /* We have a small event box to print...no text */
3129 update_rect.y = y - 1;
3130 update_rect.width = 4;
3131 update_rect.height = 4;
3132 return(tbox_print(s, x, y, function, &update_rect));
3134 return(&update_rect);
3137 /****************************************************************************
3140 * For lines there is a primitive batching facility, that doesn't update
3141 * the drawing area until the batch is complete. This is handy for drawing
3142 * the pid axis and for summary mode.
3144 * line_batch_mode contains the state for this:
3146 * BATCH_OFF: no batching, update for every line
3147 * BATCH_NEW: just entered a batch, so initialize the area to update from
3149 * BATCH_EXISTING: have drawn at least one line in batch mode, so the update
3150 * area should only be expanded from now on to include the
3151 * union of the "rectangular hull" of all lines
3152 ****************************************************************************/
3154 static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
3155 static int line_batch_count;
3156 static int line_minx, line_miny, line_maxx, line_maxy;
3158 void line_batch_start (void)
3160 line_batch_mode = BATCH_NEW;
3161 line_batch_count = 0;
3164 void line_batch_end (void)
3166 GdkRectangle update_rect;
3167 if (line_batch_count > 0) {
3168 update_rect.x = line_minx;
3169 update_rect.y = line_miny;
3170 update_rect.width = (line_maxx - line_minx) + 1;
3171 update_rect.height = (line_maxy - line_miny) + 1;
3172 gtk_widget_draw (da, &update_rect);
3174 line_batch_mode = BATCH_OFF;
3177 void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
3179 GdkRectangle update_rect;
3183 case LINE_DRAW_BLACK:
3184 gc = da->style->black_gc;
3187 case LINE_DRAW_WHITE:
3188 gc = da->style->white_gc;
3192 line_print (x1, y1, x2, y2);
3196 gdk_draw_line (pm, gc, x1, y1, x2, y2);
3198 switch (line_batch_mode) {
3202 update_rect.width = (x2-x1) + 1;
3203 update_rect.height = (y2-y1) + 1;
3204 gtk_widget_draw (da, &update_rect);
3212 line_batch_mode = BATCH_EXISTING;
3213 line_batch_count = 1;
3216 case BATCH_EXISTING:
3231 /****************************************************************************
3233 ****************************************************************************/
3235 static void display_pid_axis(v1_geometry_t *vp)
3237 int y, i, label_tick;
3238 int last_printed_y = -vp->strip_height;
3244 /* No pids yet? Outta here */
3250 for (i = 0; i < vp->npids; i++) {
3251 pid_index = vp->first_pid_index + i;
3252 if (pid_index >= g_npids)
3255 pp = (g_pids + pid_index);
3257 set_color(pid_index);
3259 label_fmt = get_track_label(pp->pid_value);
3260 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
3262 y = i*vp->strip_height + vp->pid_ax_offset;
3265 * Have we incremented enough space to have another label not
3266 * overlap the previous label?
3268 if (y - last_printed_y > 9) {
3270 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
3275 * And let the line stick out a bit more to indicate this label
3276 * relates to the following line.
3284 /* Draw axis line, but only if the lines aren't too close together */
3285 if (vp->strip_height > 4) {
3286 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
3287 vp->total_width, y+4*s_print_offset,
3288 LINE_DRAW_BLACK+s_print_offset);
3292 set_color(COLOR_DEFAULT);
3296 /****************************************************************************
3297 * view1_read_events_callback
3298 * New event data just showed up, reset a few things.
3299 ****************************************************************************/
3301 void view1_read_events_callback(void)
3305 s_v1->first_pid_index = 0;
3307 max_vis_index = 300;
3308 if (max_vis_index > g_nevents)
3309 max_vis_index = g_nevents-1;
3311 s_v1->minvistime = 0LL;
3312 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
3313 /* Single event? Make the initial display 1s wide */
3315 s_v1->maxvistime = 1000000;
3318 s_last_selected_event = 0;
3320 init_track_colors();
3322 recompute_hscrollbar();
3323 recompute_vscrollbar();
3326 /****************************************************************************
3327 * display_event_data
3328 ****************************************************************************/
3330 static void display_event_data(v1_geometry_t *vp)
3337 double time_per_pixel;
3339 GdkRectangle *print_rect;
3342 /* Happens if one loads the event def header first, for example. */
3346 time_per_pixel = dtime_per_pixel(vp);
3348 start_index = find_event_index (vp->minvistime);
3350 /* Scrolled too far right? */
3351 if (start_index >= g_nevents)
3354 ep = (g_events + start_index);
3356 if (s_print_offset || summary_mode) {
3357 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3364 while (ep < (g_events + g_nevents) &&
3365 (ep->time < vp->maxvistime)) {
3366 pid_index = ep->pid->pid_index;
3367 set_color(pid_index);
3369 /* First filter: pid out of range */
3370 if ((pid_index < vp->first_pid_index) ||
3371 (pid_index >= vp->first_pid_index + vp->npids)) {
3376 /* Second filter: event hidden */
3377 edp = find_event_definition (ep->code);
3378 if (!edp->selected) {
3385 pid_index -= vp->first_pid_index;
3387 y = pid_index*vp->strip_height + vp->event_offset;
3389 x = vp->pid_ax_width +
3390 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3392 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3397 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3398 if (ep->flags & EVENT_FLAG_SELECT) {
3399 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3401 sprintf(tmpbuf, edp->name);
3402 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3403 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3406 sprintf(tmpbuf, "SEARCH RESULT");
3408 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3409 TBOX_DRAW_BOXED+s_print_offset);
3410 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3411 if (last_x_used != NULL)
3412 last_x_used[pid_index] = x + print_rect->width;
3415 int delta = vp->strip_height / 3;
3418 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3419 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3420 last_x_used[pid_index] = x + 1;
3422 sprintf(tmpbuf, "%ld", ep->code);
3423 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3424 if (last_x_used != NULL)
3425 last_x_used[pid_index] = x + print_rect->width;
3431 g_free(last_x_used);
3433 set_color(COLOR_DEFAULT);
3436 /****************************************************************************
3438 ****************************************************************************/
3440 static void display_clear(void)
3442 GdkRectangle update_rect;
3444 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3445 0, 0, da->allocation.width,
3446 da->allocation.height);
3450 update_rect.width = da->allocation.width;
3451 update_rect.height = da->allocation.height;
3453 gtk_widget_draw (da, &update_rect);
3456 /****************************************************************************
3458 ****************************************************************************/
3460 static void display_time_axis(v1_geometry_t *vp)
3463 int xoffset, nticks;
3465 double unit_divisor;
3468 double time_per_pixel;
3470 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3472 x = vp->pid_ax_width;
3474 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3476 time_per_pixel = dtime_per_pixel(vp);
3479 unit_divisor = 1.00;
3481 if ((vp->maxvistime / unit_divisor) > 1000) {
3483 unit_divisor = 1000.00;
3486 if ((vp->maxvistime / unit_divisor) > 1000) {
3488 unit_divisor = 1000.00*1000.00;
3490 if ((vp->maxvistime / unit_divisor) > 1000) {
3492 unit_divisor = 1000.00*1000.00*1000.00;
3496 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3500 for (i = 0; i < nticks; i++) {
3502 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3504 time = (double)(x + xoffset - vp->pid_ax_width);
3505 time *= time_per_pixel;
3506 time += (double)(vp->minvistime);
3507 time /= unit_divisor;
3509 sprintf (tmpbuf, "%.2f%s", time, units);
3511 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3513 xoffset += vp->time_ax_spacing;
3517 /****************************************************************************
3519 * Forget about any temporary displays, they're gone now...
3520 ****************************************************************************/
3522 static void clear_scoreboard(void)
3524 s_result_up = FALSE;
3527 /****************************************************************************
3529 ****************************************************************************/
3531 void view1_display(void)
3534 display_pid_axis(s_v1);
3535 display_event_data(s_v1);
3536 display_time_axis(s_v1);
3540 static gint idle_tag;
3542 /****************************************************************************
3543 * view1_display_eventually
3544 ****************************************************************************/
3546 static void view1_display_eventually(void)
3548 gtk_idle_remove(idle_tag);
3554 /****************************************************************************
3555 * view1_display_when_idle
3556 ****************************************************************************/
3558 void view1_display_when_idle(void)
3560 if (idle_tag == 0) {
3561 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3565 /****************************************************************************
3567 ****************************************************************************/
3569 void view1_about (char *tmpbuf)
3574 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3575 s_v1->minvistime, s_v1->maxvistime);
3576 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
3577 s_v1->strip_height);
3579 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3582 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);