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)
439 if (ep->flags & EVENT_FLAG_CLIB) {
443 eep = get_clib_event (ep->datum);
445 s = format (0, "%U", format_elog_event, &elog_main, eep);
446 memcpy (tmpbuf, s, vec_len(s));
447 tmpbuf[vec_len(s)] = 0;
452 snprintf(tmpbuf, len, "%s", edp->name);
454 /* Make sure there's a real format string. If so, add it */
457 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
458 /* %s only supported for cpel files */
460 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
461 edp->format, strtab_ref(ep->datum));
463 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
464 edp->format, ep->datum);
472 /****************************************************************************
474 ****************************************************************************/
476 static void add_snapshot(void)
479 snapshot_t *new = g_malloc(sizeof(snapshot_t));
481 memcpy(&new->geometry, s_v1, sizeof(new->geometry));
482 for (i = 0; i < NEVENTS; i++) {
483 new->show_event[i] = g_eventdefs[i].selected;
485 new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids);
486 memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids);
487 new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value;
488 new->summary_mode = summary_mode;
489 new->color_mode = color_mode;
492 new->next = s_snapshots;
501 /****************************************************************************
503 ****************************************************************************/
505 static void next_snapshot(void)
513 infobox("No snapshots", "\nNo snapshots in the ring...\n");
517 next = s_cursnap->next;
523 memcpy(s_v1, &next->geometry, sizeof(next->geometry));
524 for (i = 0; i < NEVENTS; i++) {
525 g_eventdefs[i].selected = next->show_event[i];
527 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
528 color_mode = next->color_mode;
530 * Update summary mode via a button push so that the button state is
531 * updated accordingly. (Should ideally clean up the view/controller
532 * separation properly one day.)
534 if (summary_mode != next->summary_mode) {
535 view1_button_click_callback
536 (NULL, (gpointer)(unsigned long long)
537 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
540 /* Fix the pid structure index mappings */
543 for (i = 0; i < g_npids; i++) {
548 GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value;
549 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
550 recompute_hscrollbar();
551 pointsel_next_snapshot();
552 view1_display_when_idle();
556 /****************************************************************************
558 ****************************************************************************/
560 static void del_snapshot(void)
566 infobox("No snapshots", "\nNo snapshots to delete...\n");
573 while (this && this != s_cursnap) {
578 if (this != s_cursnap) {
579 infobox("BUG", "\nSnapshot AWOL!\n");
583 s_cursnap = this->next;
585 /* middle of the list? */
587 prev->next = this->next;
588 g_free(this->pidvec);
590 } else { /* start of the list */
591 s_snapshots = this->next;
592 g_free(this->pidvec);
596 /* Note: both will be NULL after last delete */
597 if (s_cursnap == NULL)
598 s_cursnap = s_snapshots;
601 /****************************************************************************
604 * VERY primitive right now - not endian or version independent, and only
605 * writes to "snapshots.g2" in the current directory
606 ****************************************************************************/
607 static void write_snapshot(void)
614 if (s_snapshots == NULL) {
615 error = "No snapshots defined";
620 file = fopen("snapshots.g2", "w");
622 error = "Unable to open snapshots.g2";
627 * Simply serialize the arch-dependent binary data, without a care in the
628 * world. Don't come running to me if you try to read it and crash.
630 for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) {
631 if (fwrite(&snap->geometry,
632 sizeof(snap->geometry), 1, file) != 1 ||
633 fwrite(&snap->show_event,
634 sizeof(snap->show_event), 1, file) != 1 ||
636 sizeof(pid_sort_t) * g_npids, 1, file) != 1 ||
637 fwrite(&snap->vscroll_value,
638 sizeof(snap->vscroll_value), 1, file) != 1 ||
639 fwrite(&snap->summary_mode,
640 sizeof(snap->summary_mode), 1, file) != 1 ||
641 fwrite(&snap->color_mode,
642 sizeof(snap->color_mode), 1, file) != 1) {
643 error = "Error writing data";
650 error = "Unable to close file";
655 infobox(error, strerror(errno));
658 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
664 /****************************************************************************
667 * VERY primitive right now - not endian or version independent, and only reads
668 * from "snapshots.g2" in the current directory
669 ****************************************************************************/
670 static void read_snapshot(void)
673 snapshot_t *snap, *next_snap;
674 snapshot_t *new_snaps = NULL;
676 int len, i, records = 0;
679 file = fopen("snapshots.g2", "r");
681 error = "Unable to open snapshots.g2";
685 * Read in the snapshots and link them together. We insert them backwards,
686 * but that's tolerable. If the data is in anyway not what we expect, we'll
687 * probably crash. Sorry.
689 while (!error && !feof(file)) {
690 snap = g_malloc(sizeof(*snap));
691 snap->pidvec = NULL; /* so we can free this if there's an error */
693 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
699 /* insert into list straight away */
700 snap->next = new_snaps;
704 error = "Problem reading first item from file";
707 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
708 error = "Problem reading second item from file";
711 len = sizeof(pid_sort_t) * g_npids;
712 snap->pidvec = g_malloc(len);
713 if (fread(snap->pidvec, len, 1, file) != 1) {
714 error = "Problem reading third item from file";
717 if (fread(&snap->vscroll_value,
718 sizeof(snap->vscroll_value), 1, file) != 1 ||
719 fread(&snap->summary_mode,
720 sizeof(snap->summary_mode), 1, file) != 1 ||
721 fread(&snap->color_mode,
722 sizeof(snap->color_mode), 1, file) != 1) {
723 error = "Problem reading final items from file";
728 * Fix up the pointers from the sorted pid vector back into our pid
729 * data objects, by walking the linked list of pid_data_t objects for
730 * every one looking for a match. This is O(n^2) grossness, but in real
731 * life there aren't that many pids, and it seems zippy enough.
733 for (i = 0; i < g_npids; i++) {
734 for (pp = g_pid_data_list; pp != NULL; pp = pp->next) {
735 if (pp->pid_value == snap->pidvec[i].pid_value) {
740 snap->pidvec[i].pid = pp;
742 error = "Snapshot file referenced unknown pids";
752 error = "Unable to close file";
758 * Problem - clear up any detritus
760 infobox(error, strerror(errno));
761 for (snap = new_snaps; snap != NULL; snap = next_snap) {
762 next_snap = snap->next;
764 g_free(snap->pidvec);
768 * Success! trash the old snapshots and replace with the new
770 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
771 next_snap = snap->next;
772 g_free(snap->pidvec);
776 s_cursnap = s_snapshots = new_snaps;
780 infobox(error, strerror(errno));
783 snprintf(buf, sizeof(buf),
784 "Read %d snapshots from snapshots.g2", records);
789 /****************************************************************************
792 * Set the color for the specified pid_index, or COLOR_DEFAULT to return it
793 * to the usual black.
794 ****************************************************************************/
795 #define COLOR_DEFAULT (-1)
796 static void set_color(int pid_index)
800 psp = (g_pids + pid_index);
803 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
804 else if (pid_index == COLOR_DEFAULT || !color_mode) {
805 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
807 gdk_gc_set_foreground(da->style->black_gc,
808 &s_color[g_pids[pid_index].color_index]);
812 /****************************************************************************
813 * toggle_event_select
814 ****************************************************************************/
816 static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
818 int pid_index, start_index;
821 GdkRectangle hit_rect;
822 GdkRectangle placeholder;
826 double time_per_pixel;
831 time_per_pixel = dtime_per_pixel(vp);
833 start_index = find_event_index (vp->minvistime);
836 if (start_index >= g_nevents)
840 * To see if the mouse hit a visible event, use a variant
841 * of the event display loop.
844 hit_rect.x = (int)event->x;
845 hit_rect.y = (int)event->y;
849 ep = (g_events + start_index);
851 while ((ep->time < vp->maxvistime) &&
852 (ep < (g_events + g_nevents))) {
853 pid_index = ep->pid->pid_index;
855 /* First filter: pid out of range */
856 if ((pid_index < vp->first_pid_index) ||
857 (pid_index >= vp->first_pid_index + vp->npids)) {
862 /* Second filter: event hidden */
863 edp = find_event_definition (ep->code);
864 if (!edp->selected) {
870 * At this point, we know that the point is at least on the
871 * screen. See if the mouse hit within the bounding box
875 * $$$$ maybe keep looping until off the edge,
876 * maintain a "best hit", then declare that one the winner?
879 pid_index -= vp->first_pid_index;
881 y = pid_index*vp->strip_height + vp->event_offset;
883 x = vp->pid_ax_width +
884 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
886 /* Perhaps we're trying to toggle the detail box? */
887 if (ep->flags & EVENT_FLAG_SELECT) {
888 /* Figure out the dimensions of the detail box */
889 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
890 rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED);
891 if (gdk_rectangle_intersect(rp, &hit_rect, &placeholder)) {
892 ep->flags &= ~EVENT_FLAG_SELECT;
893 view1_display_when_idle();
898 snprintf(tmpbuf, sizeof(tmpbuf), "%ld", ep->code);
900 /* Figure out the dimensions of the regular box */
901 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
903 if (gdk_rectangle_intersect(rp, &hit_rect, &placeholder)) {
904 /* we hit the rectangle. */
905 if (ep->flags & EVENT_FLAG_SELECT) {
906 ep->flags &= ~EVENT_FLAG_SELECT;
907 view1_display_when_idle();
910 set_color(ep->pid->pid_index);
912 /* It wasn't selected, so put up the detail box */
913 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
914 tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED);
915 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK);
916 ep->flags |= EVENT_FLAG_SELECT;
917 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
918 s_last_selected_event = ep;
927 /****************************************************************************
928 * toggle_track_select
929 ****************************************************************************/
931 static void toggle_track_select (GdkEventButton *event,
942 /* Scan pid/track axis locations, looking for a match */
943 for (i = 0; i < vp->npids; i++) {
944 y = i*vp->strip_height + vp->pid_ax_offset;
945 delta_y = y - event->y;
953 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
957 pid_index = i + vp->first_pid_index;
958 psp = (g_pids + pid_index);
960 view1_display_when_idle();
963 /****************************************************************************
965 ****************************************************************************/
966 static void deselect_tracks (void)
970 for (i = 0; i < g_npids; i++)
971 g_pids[i].selected = 0;
976 /****************************************************************************
978 ****************************************************************************/
980 typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
982 static void move_current_track(GdkEventButton *event,
989 pid_sort_t *new_pidvec;
991 pid_sort_t *pold, *pnew;
997 /* Scan pid/track axis locations, looking for a match */
998 for (i = 0; i < vp->npids; i++) {
999 y = i*vp->strip_height + vp->pid_ax_offset;
1000 delta_y = y - event->y;
1008 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
1012 pid_index = i + vp->first_pid_index;
1014 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
1018 if (type == MOVE_TOP) {
1020 *pnew++ = g_pids[pid_index];
1021 for (i = 0; i < pid_index; i++)
1025 for (; i < g_npids; i++)
1028 /* move to bottom */
1029 for (i = 0; i < pid_index; i++)
1033 for (; i < g_npids; i++)
1035 *pnew = g_pids[pid_index];
1039 g_pids = new_pidvec;
1042 * Revert the pid_index mapping to an identity map,
1046 for (i = 0; i < g_npids; i++) {
1051 view1_display_when_idle();
1054 /****************************************************************************
1056 * Process a zoom gesture. The use of doubles is required to avoid
1057 * truncating the various variable values, which in turn would lead to
1058 * some pretty random-looking zoom responses.
1059 ****************************************************************************/
1061 void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1064 double time_per_pixel;
1065 double width_in_pixels;
1066 double center_on_time, width_in_time;
1067 double center_on_pixel;
1070 * Clip the zoom area to the event display area.
1071 * Otherwise, center_on_time - width_in_time is in hyperspace
1072 * to the left of zero
1075 if (e1->x < vp->pid_ax_width)
1076 e1->x = vp->pid_ax_width;
1078 if (e2->x < vp->pid_ax_width)
1079 e2->x = vp->pid_ax_width;
1082 goto loser_zoom_repaint;
1084 xrange = (double) (e2->x - e1->x);
1088 /* Actually, width in pixels of half the zoom area */
1089 width_in_pixels = xrange / 2.00;
1090 time_per_pixel = dtime_per_pixel(vp);
1091 width_in_time = width_in_pixels * time_per_pixel;
1093 /* Center the screen on the center of the zoom area */
1094 center_on_pixel = (double)((e2->x + e1->x) / 2.00) -
1095 (double)vp->pid_ax_width;
1096 center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime;
1099 * Transform back to 64-bit integer microseconds, reset the
1100 * scrollbar, schedule a repaint.
1102 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1103 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1106 recompute_hscrollbar();
1108 view1_display_when_idle();
1111 /****************************************************************************
1114 * Scroll up or down by the specified delta
1116 ****************************************************************************/
1117 static void scroll_y(int delta)
1119 int new_index = s_v1->first_pid_index + delta;
1120 if (new_index + s_v1->npids > g_npids)
1121 new_index = g_npids - s_v1->npids;
1125 if (new_index != s_v1->first_pid_index) {
1126 s_v1->first_pid_index = new_index;
1127 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index;
1128 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1129 view1_display_when_idle();
1133 /****************************************************************************
1134 * view1_handle_key_press_event
1135 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1137 * This routine implements hotkeys for the Quake generation:
1148 * E - toggle summary mode
1149 * C - toggle color mode
1153 * P - persist snapshots to file
1154 * L - load snapshots from file
1158 ****************************************************************************/
1160 view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1164 switch (event->keyval) {
1165 case GDK_w: // zoom in
1166 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1169 case GDK_s: // zoom out
1170 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1173 case GDK_a: // pan left
1174 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1175 if (s_v1->minvistime < delta) {
1176 delta = s_v1->minvistime;
1178 s_v1->minvistime -= delta;
1179 s_v1->maxvistime -= delta;
1180 recompute_hscrollbar();
1183 case GDK_d: // pan right
1184 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1185 if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) {
1187 * @@@ this doesn't seem to quite reach the far right hand
1188 * side correctly - not sure why.
1190 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1192 s_v1->minvistime += delta;
1193 s_v1->maxvistime += delta;
1194 recompute_hscrollbar();
1197 case GDK_r: // pan up
1201 case GDK_f: // pan down
1205 case GDK_t: // fewer tracks
1206 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1209 case GDK_g: // more tracks
1210 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1213 case GDK_e: // toggle summary mode
1214 view1_button_click_callback
1215 (NULL, (gpointer)(unsigned long long)
1216 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
1219 case GDK_c: // toggle color mode
1221 view1_display_when_idle();
1224 case GDK_p: // persist snapshots
1228 case GDK_l: // load snapshots
1232 case GDK_x: // take snapshot
1233 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1236 case GDK_z: // next snapshot
1237 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1240 case GDK_q: // ctrl-q is exit
1241 if (event->state & GDK_CONTROL_MASK) {
1249 /****************************************************************************
1250 * button_press_event
1251 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1253 * This routine implements three functions: zoom-to-area, time ruler, and
1254 * show/hide event detail popup.
1256 * The left mouse button (button 1) has two simultaneous functions: event
1257 * detail popup, and zoom-to-area. If the press and release events occur
1258 * within a small delta-x, it's a detail popup event. Otherwise, it's
1261 * The right mouse button (button 3) implements the time ruler.
1262 ****************************************************************************/
1265 button_press_event (GtkWidget *widget, GdkEventButton *event)
1267 static GdkEventButton press1_event;
1268 static boolean press1_valid;
1269 static GdkEventButton press3_event;
1270 static guint32 last_truler_time;
1271 static boolean press3_valid;
1272 static boolean zoom_bar_up;
1273 int time_ax_y, xdelta;
1275 double time_per_pixel;
1279 switch(event->type) {
1280 case GDK_BUTTON_PRESS:
1281 /* Capture the appropriate starting point */
1282 if (event->button == 1) {
1283 press1_valid = TRUE;
1284 press1_event = *event;
1287 if (event->button == 3) {
1288 press3_valid = TRUE;
1289 press3_event = *event;
1294 case GDK_BUTTON_RELEASE:
1297 press3_valid = FALSE;
1298 /* Fix the cursor, and repaint the screen from scratch */
1299 gdk_window_set_cursor (da->window, norm_cursor);
1300 view1_display_when_idle();
1303 /* Event select / zoom-to-area */
1305 press1_valid = FALSE;
1306 xdelta = (int)(press1_event.x - event->x);
1310 /* is the mouse more or less where it started? */
1312 /* Control-left-mouse => sink the track */
1313 /* Shift-left-mouse => raise the track */
1314 if ((press1_event.state & GDK_CONTROL_MASK) ==
1316 move_current_track(event, s_v1, MOVE_BOTTOM);
1317 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1319 move_current_track(event, s_v1, MOVE_TOP);
1321 /* No modifiers: toggle the event / select track */
1322 if (toggle_event_select(event, s_v1))
1323 toggle_track_select(event, s_v1);
1325 /* Repaint to get rid of the zoom bar */
1327 /* Fix the cursor and leave. No zoom */
1328 gdk_window_set_cursor (da->window, norm_cursor);
1329 zoom_bar_up = FALSE;
1332 } else { /* mouse moved enough to zoom */
1333 zoom_event(&press1_event, event, s_v1);
1334 gdk_window_set_cursor (da->window, norm_cursor);
1335 zoom_bar_up = FALSE;
1337 } else if (event->button == 4) {
1338 /* scroll wheel up */
1339 scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1);
1340 } else if (event->button == 5) {
1341 /* scroll wheel down */
1342 scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1);
1346 case GDK_MOTION_NOTIFY:
1347 /* Button one followed by motion: draw zoom fence and fix cursor */
1349 /* Fence, cursor already set */
1353 xdelta = (int)(press1_event.x - event->x);
1357 /* Haven't moved enough to declare a zoom sequence yet */
1361 /* Draw the zoom fence, use the key-down X coordinate */
1362 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1364 line((int)(press1_event.x), s_v1->pop_offset,
1365 (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK);
1366 tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset,
1368 gdk_window_set_cursor(da->window, zi_cursor);
1375 gdk_window_set_cursor(da->window, zi_cursor);
1378 * Some filtration is needed on Solaris, or the server will hang
1380 if (event->time - last_truler_time < 75)
1383 last_truler_time = event->time;
1385 line((int)(press3_event.x), s_v1->pop_offset,
1386 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1388 xdelta = (int)(press3_event.x - event->x);
1392 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1393 ((double)(s_v1->total_width - s_v1->pid_ax_width));
1395 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1397 line((int)(press3_event.x), s_v1->pop_offset,
1398 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1400 * Note: use a fixed-width format so it looks like we're
1401 * erasing and redrawing the box.
1403 nsec = ((double)xdelta)*time_per_pixel;
1405 snprintf(tmpbuf, sizeof(tmpbuf), "%8.3f sec ", nsec/1e9);
1406 } else if (nsec > 1e6) {
1407 snprintf(tmpbuf, sizeof(tmpbuf), "%8.3f msec", nsec/1e6);
1408 } else if (nsec > 1e3) {
1409 snprintf(tmpbuf, sizeof(tmpbuf), "%8.3f usec", nsec/1e3);
1411 snprintf(tmpbuf, sizeof(tmpbuf), "%8.0f nsec", nsec);
1413 s_v1->last_time_interval = nsec;
1414 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1422 g_print("button:\ttype = %d\n", event->type);
1423 g_print("\twindow = 0x%x\n", event->window);
1424 g_print("\tsend_event = %d\n", event->send_event);
1425 g_print("\ttime = %d\n", event->time);
1426 g_print("\tx = %6.2f\n", event->x);
1427 g_print("\ty = %6.2f\n", event->y);
1428 g_print("\tpressure = %6.2f\n", event->pressure);
1429 g_print("\txtilt = %6.2f\n", event->xtilt);
1430 g_print("\tytilt = %6.2f\n", event->ytilt);
1431 g_print("\tstate = %d\n", event->state);
1432 g_print("\tbutton = %d\n", event->button);
1433 g_print("\tsource = %d\n", event->source);
1434 g_print("\tdeviceid = %d\n", event->deviceid);
1435 g_print("\tx_root = %6.2f\n", event->x_root);
1436 g_print("\ty_root = %6.2f\n", event->y_root);
1441 view1_display_when_idle();
1446 /****************************************************************************
1448 * Happens when the window manager resizes the viewer's main window.
1449 ****************************************************************************/
1452 configure_event (GtkWidget *widget, GdkEventConfigure *event)
1454 /* Toss the previous drawing area backing store pixmap */
1456 gdk_pixmap_unref(pm);
1458 /* Create a new pixmap, paint it */
1459 pm = gdk_pixmap_new(widget->window,
1460 widget->allocation.width,
1461 widget->allocation.height,
1463 gdk_draw_rectangle (pm,
1464 widget->style->white_gc,
1467 widget->allocation.width,
1468 widget->allocation.height);
1470 /* Reset the view geometry parameters, as required */
1471 s_v1->total_width = widget->allocation.width;
1472 s_v1->total_height = widget->allocation.height;
1473 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
1476 /* Schedule a repaint */
1477 view1_display_when_idle();
1481 /****************************************************************************
1483 * Use backing store to fix the screen.
1484 ****************************************************************************/
1485 static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1487 gdk_draw_pixmap(widget->window,
1488 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1490 event->area.x, event->area.y,
1491 event->area.x, event->area.y,
1492 event->area.width, event->area.height);
1497 /****************************************************************************
1498 * event_search_internal
1499 * This routine searches forward from s_srchindex, looking for s_srchcode;
1500 * wraps at the end of the buffer.
1501 ****************************************************************************/
1503 boolean event_search_internal (void)
1509 boolean full_redisplay = FALSE;
1510 ulonglong current_width;
1513 /* No events yet? Act like the search worked, to avoid a loop */
1517 ep = (g_events + s_srchindex);
1518 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1521 * Assume the user wants to search [plus or minus]
1522 * from where they are.
1525 if (ep->time < s_v1->minvistime)
1526 s_srchindex = find_event_index (s_v1->minvistime);
1529 for (i = 1; i <= g_nevents; i++) {
1530 index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ?
1531 (s_srchindex - i) % g_nevents :
1532 (i + s_srchindex) % g_nevents;
1534 ep = (g_events + index);
1536 if (ep->code == s_srchcode) {
1539 s_srchindex = index;
1540 pid_index = ep->pid->pid_index;
1542 /* Need a vertical scroll? */
1543 if ((pid_index < s_v1->first_pid_index) ||
1544 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1545 if (pid_index > (g_npids - s_v1->npids))
1546 pid_index = (g_npids - s_v1->npids);
1547 s_v1->first_pid_index = pid_index;
1548 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1549 (gdouble)s_v1->first_pid_index;
1550 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1551 full_redisplay = TRUE;
1554 /* Need a horizontal scroll? */
1555 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1556 current_width = (s_v1->maxvistime - s_v1->minvistime);
1557 if (ep->time < ((current_width+1) / 2)) {
1558 s_v1->minvistime = 0ll;
1559 s_v1->maxvistime = current_width;
1561 s_v1->minvistime = ep->time - ((current_width+1)/2);
1562 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1564 recompute_hscrollbar();
1565 full_redisplay = TRUE;
1567 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1568 full_redisplay = TRUE;
1571 if (!full_redisplay){
1574 time_per_pixel = dtime_per_pixel(s_v1);
1576 y = pid_index*s_v1->strip_height + s_v1->event_offset;
1577 x = s_v1->pid_ax_width +
1578 (int)(((double)(ep->time - s_v1->minvistime)) /
1580 snprintf(tmpbuf, sizeof(tmpbuf), "SEARCH RESULT");
1581 tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED);
1582 line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK);
1584 full_redisplay = TRUE;
1590 view1_display_when_idle();
1594 snprintf (tmpbuf, sizeof(tmpbuf),
1595 "Search for event %ld failed...\n", s_srchcode);
1596 message_line(tmpbuf);
1597 s_srchfail_up = TRUE;
1601 /****************************************************************************
1602 * event_search_callback
1603 ****************************************************************************/
1605 boolean event_search_callback (char *s)
1607 /* No events yet? Act like the search worked, to avoid a loop */
1611 s_srchcode = atol(s);
1613 if (s_srchcode == 0)
1616 return(event_search_internal());
1620 /****************************************************************************
1621 * anomaly_statistics_init
1622 ****************************************************************************/
1624 static int anomaly_statistics_init (void)
1633 /* Gather summary statistics... */
1636 vec_reset_length (s_v1->means);
1637 vec_reset_length (s_v1->matches);
1638 vec_reset_length (s_v1->variances);
1639 vec_reset_length (s_v1->two_stddevs);
1640 vec_reset_length (s_v1->mins);
1641 vec_reset_length (s_v1->maxes);
1643 for (i = 0; i < g_nevents; i++) {
1644 if (ep->code != s_anomalycode) {
1649 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
1650 vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
1651 vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
1652 vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
1653 eep = get_clib_event (ep->datum);
1654 data = clib_mem_unaligned (eep->data, u32);
1656 s_v1->means[pid->pid_index] += fdata;
1657 s_v1->matches[pid->pid_index] += 1;
1658 /* First data point? set min, max */
1659 if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
1660 s_v1->mins[pid->pid_index] = fdata;
1661 s_v1->maxes[pid->pid_index] = fdata;
1663 s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
1664 fdata : s_v1->mins[pid->pid_index];
1665 s_v1->maxes[pid->pid_index] =
1666 (fdata > s_v1->maxes[pid->pid_index]) ?
1667 fdata : s_v1->maxes[pid->pid_index];
1671 if (vec_len (s_v1->matches) == 0)
1674 /* Compute s_v1->means */
1675 for (i = 0; i < vec_len (s_v1->means); i++)
1676 s_v1->means[i] = s_v1->matches[i]
1677 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1679 /* Compute s_v1->variances */
1681 for (i = 0; i < g_nevents; i++) {
1682 if (ep->code != s_anomalycode) {
1687 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1688 eep = get_clib_event (ep->datum);
1689 data = clib_mem_unaligned (eep->data, u32);
1691 s_v1->variances[pid->pid_index] +=
1692 (fdata - s_v1->means[pid->pid_index])
1693 * (fdata - s_v1->means[pid->pid_index]);
1697 /* Normalize variances */
1698 for (i = 0; i < vec_len (s_v1->variances); i++)
1699 s_v1->variances[i] = s_v1->matches[i]
1700 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1702 /* Compute the anomaly threshold, by default 2.5*stddev */
1703 for (i = 0; i < vec_len (s_v1->variances); i++)
1704 vec_add1 (s_v1->two_stddevs,
1705 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1709 /****************************************************************************
1710 * anomaly_search_internal
1711 * This routine searches forward from s_srchindex, looking for s_srchcode;
1712 * wraps at the end of the buffer.
1713 ****************************************************************************/
1715 boolean anomaly_search_internal (void)
1724 boolean full_redisplay = FALSE;
1725 ulonglong current_width;
1729 if (vec_len (s_v1->matches) == 0)
1730 anomaly_statistics_init();
1732 ep = (g_events + s_srchindex);
1733 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1736 * If the user rearranged the screen, start from the minimum
1739 if (ep->time < s_v1->minvistime)
1740 s_srchindex = find_event_index (s_v1->minvistime);
1742 for (i = 1; i <= g_nevents; i++) {
1743 index = (i + s_srchindex) % g_nevents;
1745 ep = (g_events + index);
1746 if (ep->code != s_anomalycode)
1750 eep = get_clib_event (ep->datum);
1751 data = clib_mem_unaligned (eep->data, u32);
1755 * Found an anomaly? Define an anomaly as a datum
1756 * greater than 2*stddev above average.
1758 if ((fdata - s_v1->means[pid->pid_index]) >
1759 s_v1->two_stddevs[pid->pid_index]) {
1762 s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
1763 s_v1->anomaly_threshold_stddevs);
1765 for (i = 0; i < vec_len (s_v1->means); i++) {
1766 if (s_v1->matches[i] > 0)
1767 s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
1768 s_v1->mins[i], s_v1->maxes[i],
1770 s_v1->means[i]+s_v1->two_stddevs[i]);
1772 s = format (s, "{no match} ");
1775 message_line ((char *)s);
1778 s_srchindex = index;
1779 pid_index = ep->pid->pid_index;
1781 /* Need a vertical scroll? */
1782 if ((pid_index < s_v1->first_pid_index) ||
1783 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1784 if (pid_index > (g_npids - s_v1->npids))
1785 pid_index = (g_npids - s_v1->npids);
1786 s_v1->first_pid_index = pid_index;
1787 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1788 (gdouble)s_v1->first_pid_index;
1789 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1790 full_redisplay = TRUE;
1793 /* Need a horizontal scroll? */
1794 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1795 current_width = (s_v1->maxvistime - s_v1->minvistime);
1796 if (ep->time < ((current_width+1) / 2)) {
1797 s_v1->minvistime = 0ll;
1798 s_v1->maxvistime = current_width;
1800 s_v1->minvistime = ep->time - ((current_width+1)/2);
1801 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1803 recompute_hscrollbar();
1804 full_redisplay = TRUE;
1806 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1807 full_redisplay = TRUE;
1810 view1_display_when_idle();
1815 snprintf (tmpbuf, sizeof(tmpbuf),
1816 "Search for an anomalous event %ld failed...\n",
1818 message_line(tmpbuf);
1819 s_srchfail_up = TRUE;
1823 /****************************************************************************
1824 * anomaly_search_callback
1825 ****************************************************************************/
1827 boolean anomaly_search_callback (char *s)
1829 ulong new_anomalycode;
1831 /* No events yet? Act like the search worked, to avoid a loop */
1835 new_anomalycode = atol(s);
1837 if (new_anomalycode == 0)
1840 if (new_anomalycode != s_anomalycode ||
1841 vec_len (s_v1->matches) == 0) {
1842 s_anomalycode = new_anomalycode;
1843 if (anomaly_statistics_init()) {
1846 s = format (0, "Search for an anomalous event %ld failed...\n",
1848 message_line ((char *) s);
1853 return(anomaly_search_internal());
1856 /****************************************************************************
1857 * anomaly_threshold_callback
1858 ****************************************************************************/
1860 boolean anomaly_threshold_callback (char *s)
1864 /* No events yet? Act like the search worked, to avoid a loop */
1868 new_threshold = atof (s);
1870 if (new_threshold == 0.0 || new_threshold > 10.0)
1873 s_v1->anomaly_threshold_stddevs = new_threshold;
1875 vec_reset_length (s_v1->means);
1876 vec_reset_length (s_v1->matches);
1877 vec_reset_length (s_v1->variances);
1878 vec_reset_length (s_v1->two_stddevs);
1882 /****************************************************************************
1884 ****************************************************************************/
1886 static void event_search (void)
1888 modal_dialog ("Event Search: Please Enter Event Code",
1889 "Invalid: Please Reenter Event Code", NULL,
1890 event_search_callback);
1893 /****************************************************************************
1895 ****************************************************************************/
1897 static void anomaly_search (void)
1899 modal_dialog ("Anomaly Search: Please Enter Event Code",
1900 "Invalid: Please Reenter Event Code", NULL,
1901 anomaly_search_callback);
1904 /****************************************************************************
1906 ****************************************************************************/
1908 static void anomaly_threshold (void)
1910 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1911 "Invalid: Please Reenter Threshold in Standard Deviations",
1912 NULL, anomaly_threshold_callback);
1915 /****************************************************************************
1917 ****************************************************************************/
1918 static void init_track_colors(void)
1924 gboolean dont_care[g_npids];
1927 * If we've already allocated the colors once, then in theory we should
1928 * just be able to re-order the GCs already created to match the new track
1929 * order; the track -> color mapping doesn't currently change at runtime.
1930 * However, it's easier just to allocate everything from fresh. As a nod in
1931 * the direction of politeness towards our poor abused X server, we at
1932 * least mop up the previously allocated GCs first, although in practice
1933 * even omitting this didn't seem to cause a problem.
1935 if (s_color != NULL ) {
1936 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
1938 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
1941 * First time through: allocate the array to hold the GCs.
1943 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
1947 * Go through and assign a color for each track.
1949 /* Setup entry 0 in the colormap as pure red (for selection) */
1950 s_color[0] = fg_red;
1952 for (i = 1; i < g_npids; i++) {
1954 * We compute the color from a hash of the thread name. That way we get
1955 * a distribution of different colors, and the same thread has the same
1956 * color across multiple data sets. Unfortunately, even though the
1957 * process name and thread id are invariant across data sets, the
1958 * process id isn't, so we want to exclude that from the hash. Since
1959 * the pid appears in parentheses after the process name and tid, we
1960 * can just stop at the '(' character.
1962 * We could create a substring and use the CLIB Jenkins hash, but given
1963 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1964 * just as good, and it's easiest just to compute it inline.
1966 label_char = get_track_label(g_pids[i].pid_value);
1968 while (*label_char != '\0' && *label_char != '(') {
1969 hash = hash * 33 + *label_char++;
1971 hash += hash >> 5; /* even out the lower order bits a touch */
1974 * OK, now we have our hash. We get the color by using the first three
1975 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1976 * and then use the fourth byte to choose one of R, G, B and mask this
1977 * one down. This ensures the color can't be too close to white and
1978 * therefore hard to see.
1980 * We also drop the top bit of the green, since bright green on its own
1981 * is hard to see against white. Generally we err on the side of
1982 * keeping it dark, rather than using the full spectrum of colors. This
1983 * does result in something of a preponderance of muddy colors and a
1984 * bit of a lack of cheery bright ones, but at least you can read
1985 * everything. It would be nice to do better.
1987 RGB[0] = (hash & 0xff000000) >> 16;
1988 RGB[1] = (hash & 0x007f0000) >> 8;
1989 RGB[2] = (hash & 0x0000ff00);
1990 RGB[hash % 3] &= 0x1fff;
1993 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1995 g_pids[i].color_index = i;
2000 * Actually allocate the colors in one bulk operation. We ignore the return
2003 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
2004 s_color, g_npids+1, FALSE, TRUE, dont_care);
2008 /****************************************************************************
2010 * Reorder the pid_index fields so the viewer "chases" the last selected
2012 ****************************************************************************/
2014 static void chase_event_etc(enum chase_mode mode)
2016 pid_sort_t *psp, *new_pidvec;
2020 ulong code_to_chase;
2021 ulong datum_to_chase;
2026 if (!s_last_selected_event) {
2027 infobox("No selected event",
2028 "\nPlease select an event and try again...\n");
2032 /* Clear all index assignments */
2034 for (i = 0; i < g_npids; i++) {
2036 pp->pid_index = 0xFFFFFFFF;
2040 ep = s_last_selected_event;
2041 code_to_chase = ep->code;
2042 datum_to_chase = ep->datum;
2043 pid_to_chase = ep->pid->pid_value;
2045 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
2048 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2049 if (ep >= g_events + g_nevents)
2059 if (ep->code == code_to_chase) {
2065 if (ep->datum == datum_to_chase) {
2071 if (ep->pid->pid_value == pid_to_chase) {
2077 infobox("BUG", "unknown mode in chase_event_etc\n");
2082 if (ep->pid->pid_index == 0xFFFFFFFF) {
2083 ep->pid->pid_index = pids_mapped;
2084 new_pidvec[pids_mapped].pid = ep->pid;
2085 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2086 new_pidvec[pids_mapped].color_index = 0;
2088 if (pids_mapped == g_npids)
2092 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2098 /* Pass 2, first-to-last, to collect stragglers */
2101 while (ep < g_events + g_nevents) {
2102 if (ep->pid->pid_index == 0xFFFFFFFF) {
2103 ep->pid->pid_index = pids_mapped;
2104 new_pidvec[pids_mapped].pid = ep->pid;
2105 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2106 new_pidvec[pids_mapped].color_index = 0;
2108 if (pids_mapped == g_npids)
2114 if (pids_mapped != g_npids) {
2115 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2119 g_pids = new_pidvec;
2122 * The new g_pids vector contains the "chase" sort, so we revert
2123 * the pid_index mapping to an identity map
2127 for (i = 0; i < g_npids; i++) {
2133 /* AutoScroll the PID axis so we show the first "chased" event */
2134 s_v1->first_pid_index = 0;
2135 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2136 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2137 init_track_colors();
2138 view1_display_when_idle();
2141 /****************************************************************************
2143 * Copy g_original_pids to g_pids, revert index mapping
2144 ****************************************************************************/
2145 static void unchase_event_etc(void)
2151 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
2153 /* Fix the pid structure index mappings */
2156 for (i = 0; i < g_npids; i++) {
2162 /* Scroll PID axis to the top */
2163 s_v1->first_pid_index = 0;
2164 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2165 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2166 init_track_colors();
2167 view1_display_when_idle();
2170 /****************************************************************************
2172 * To fit a reasonable-sized landscape mode plot onto letter-size paper,
2173 * scale everything by .75.
2174 ****************************************************************************/
2176 static void print_ps_header (v1_geometry_t *vp, char *filename)
2182 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2183 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2184 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2185 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2186 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2187 fprintf(s_printfp, "%%%%Origin: 0 0\n");
2188 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
2190 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2191 fprintf(s_printfp, "%%%%Pages: 1\n");
2192 fprintf(s_printfp, "%%%%Page: 1 1\n");
2193 fprintf(s_printfp, "%%%%EOF\n");
2194 fprintf(s_printfp, "/Times-Roman findfont\n");
2195 fprintf(s_printfp, "12 scalefont\n");
2196 fprintf(s_printfp, "setfont\n");
2197 fprintf(s_printfp, ".75 .75 scale\n");
2200 /****************************************************************************
2202 * Xcoordinate rotate and translate. We need to emit postscript that
2203 * has a reasonable aspect ratio for printing. To do that, we rotate the
2204 * intended picture by 90 degrees, using the standard 2D rotation
2207 * Xr = x*cos(theta) - y*sin(theta);
2208 * Yr = x*sin(theta) + y*cos(theta);
2210 * If we let theta = 90, this reduces to
2214 * Translate back to the origin in X by adding Ymax, yielding
2216 ****************************************************************************/
2218 static inline int xrt(int x, int y)
2220 return (s_v1->total_height - y);
2223 static inline int yrt(int x, int y)
2228 /****************************************************************************
2229 * print_screen_callback
2230 ****************************************************************************/
2232 static boolean print_screen_callback(char *filename)
2234 s_printfp = fopen (filename, "wt");
2236 if (s_printfp == NULL)
2240 * This variable allows us to magically turn the view1 display
2241 * code into a print-driver, with a minimum of fuss. The idea is to
2242 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2243 * the required value, aka s_print_offset.
2244 * Make sure to fix g2.h if you mess here, or vice versa.
2246 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2248 print_ps_header(s_v1, filename);
2250 display_pid_axis(s_v1);
2251 display_event_data(s_v1);
2252 display_time_axis(s_v1);
2258 /* For tactile feedback */
2259 view1_display_when_idle();
2263 int event_time_cmp (const void *a, const void *b)
2265 const event_t *e1 = a;
2266 const event_t *e2 = b;
2268 if (e1->time < e2->time)
2270 else if (e1->time > e2->time)
2275 /****************************************************************************
2277 ****************************************************************************/
2278 static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2285 delta = (ulonglong) (vp->last_time_interval);
2287 /* Make sure we don't push events to the left of the big bang */
2288 if (which == SLEW_LEFT_BUTTON) {
2289 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2290 pid_index = ep->pid->pid_index;
2291 pp = (g_pids + pid_index);
2294 if (ep->time < delta) {
2295 infobox("Slew Range Error",
2296 "\nCan't slew selected data left that far..."
2297 "\nEvents would preceed the Big Bang (t=0)...");
2304 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2305 pid_index = ep->pid->pid_index;
2306 pp = (g_pids + pid_index);
2309 if (which == SLEW_LEFT_BUTTON)
2316 /* Re-sort the events, to avoid screwing up the event display */
2317 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2319 /* De-select tracks */
2323 view1_display_when_idle();
2326 /****************************************************************************
2327 * view1_button_click_callback
2328 ****************************************************************************/
2330 static void view1_button_click_callback(GtkButton *item, gpointer data)
2332 enum view1_button_click click = (enum view1_button_click) (long int) data;
2334 ulonglong event_incdec;
2335 ulonglong current_width;
2336 ulonglong zoom_delta;
2338 current_width = s_v1->maxvistime - s_v1->minvistime;
2339 event_incdec = (current_width) / 3;
2341 if (event_incdec == 0LL)
2344 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 snprintf(tmpbuf, sizeof(tmpbuf), "SEARCH RESULT");
3403 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3404 TBOX_DRAW_BOXED+s_print_offset);
3405 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3406 if (last_x_used != NULL)
3407 last_x_used[pid_index] = x + print_rect->width;
3410 int delta = vp->strip_height / 3;
3413 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3414 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3415 last_x_used[pid_index] = x + 1;
3417 snprintf(tmpbuf, sizeof(tmpbuf), "%ld", ep->code);
3418 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3419 if (last_x_used != NULL)
3420 last_x_used[pid_index] = x + print_rect->width;
3426 g_free(last_x_used);
3428 set_color(COLOR_DEFAULT);
3431 /****************************************************************************
3433 ****************************************************************************/
3435 static void display_clear(void)
3437 GdkRectangle update_rect;
3439 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3440 0, 0, da->allocation.width,
3441 da->allocation.height);
3445 update_rect.width = da->allocation.width;
3446 update_rect.height = da->allocation.height;
3448 gtk_widget_draw (da, &update_rect);
3451 /****************************************************************************
3453 ****************************************************************************/
3455 static void display_time_axis(v1_geometry_t *vp)
3458 int xoffset, nticks;
3460 double unit_divisor;
3463 double time_per_pixel;
3465 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3467 x = vp->pid_ax_width;
3469 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3471 time_per_pixel = dtime_per_pixel(vp);
3474 unit_divisor = 1.00;
3476 if ((vp->maxvistime / unit_divisor) > 1000) {
3478 unit_divisor = 1000.00;
3481 if ((vp->maxvistime / unit_divisor) > 1000) {
3483 unit_divisor = 1000.00*1000.00;
3485 if ((vp->maxvistime / unit_divisor) > 1000) {
3487 unit_divisor = 1000.00*1000.00*1000.00;
3491 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3495 for (i = 0; i < nticks; i++) {
3497 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3499 time = (double)(x + xoffset - vp->pid_ax_width);
3500 time *= time_per_pixel;
3501 time += (double)(vp->minvistime);
3502 time /= unit_divisor;
3504 snprintf (tmpbuf, sizeof(tmpbuf), "%.2f%s", time, units);
3506 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3508 xoffset += vp->time_ax_spacing;
3512 /****************************************************************************
3514 * Forget about any temporary displays, they're gone now...
3515 ****************************************************************************/
3517 static void clear_scoreboard(void)
3519 s_result_up = FALSE;
3522 /****************************************************************************
3524 ****************************************************************************/
3526 void view1_display(void)
3529 display_pid_axis(s_v1);
3530 display_event_data(s_v1);
3531 display_time_axis(s_v1);
3535 static gint idle_tag;
3537 /****************************************************************************
3538 * view1_display_eventually
3539 ****************************************************************************/
3541 static void view1_display_eventually(void)
3543 gtk_idle_remove(idle_tag);
3549 /****************************************************************************
3550 * view1_display_when_idle
3551 ****************************************************************************/
3553 void view1_display_when_idle(void)
3555 if (idle_tag == 0) {
3556 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3560 /****************************************************************************
3562 ****************************************************************************/
3564 void view1_about (char *tmpbuf)
3569 snprintf(tmpbuf+strlen(tmpbuf), 128, "Minvistime %lld\nMaxvistime %lld\n",
3570 s_v1->minvistime, s_v1->maxvistime);
3571 snprintf(tmpbuf+strlen(tmpbuf), 128, "Strip Height %d\n",
3572 s_v1->strip_height);
3574 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3577 snprintf(tmpbuf+strlen(tmpbuf), 128, "%d snapshots in the ring\n", nsnaps);