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;
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, &dummy)) {
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, &dummy)) {
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) 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;
2348 /* First PID to top of window */
2349 s_v1->first_pid_index = 0;
2350 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2351 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2355 s_v1->first_pid_index = g_npids - s_v1->npids;
2356 if (s_v1->first_pid_index < 0)
2357 s_v1->first_pid_index = 0;
2358 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2359 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2374 case CHASE_EVENT_BUTTON:
2375 chase_event_etc(CHASE_EVENT);
2378 case CHASE_DATUM_BUTTON:
2379 chase_event_etc(CHASE_DATUM);
2382 case CHASE_TRACK_BUTTON:
2383 chase_event_etc(CHASE_TRACK);
2386 case UNCHASE_BUTTON:
2387 unchase_event_etc();
2392 s_v1->minvistime = 0LL;
2393 s_v1->maxvistime = current_width;
2394 recompute_hscrollbar();
2398 s_v1->minvistime += zoom_delta;
2399 s_v1->maxvistime -= zoom_delta;
2400 recompute_hscrollbar();
2403 case SEARCH_AGAIN_BUTTON:
2405 event_search_internal();
2408 /* NOTE FALLTHROUGH */
2414 case ANOMALY_THRESHOLD_BUTTON:
2415 anomaly_threshold();
2418 case ANOMALY_NEXT_BUTTON:
2419 if (s_anomalycode) {
2420 anomaly_search_internal();
2423 /* NOTE FALLTHROUGH */
2425 case ANOMALY_BUTTON:
2429 case ZOOMOUT_BUTTON:
2430 if (zoom_delta == 0LL)
2433 if (s_v1->minvistime >= zoom_delta) {
2434 s_v1->minvistime -= zoom_delta;
2435 s_v1->maxvistime += zoom_delta;
2437 s_v1->minvistime = 0;
2438 s_v1->maxvistime += zoom_delta*2;
2441 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
2442 g_events[g_nevents-1].time * 9) {
2443 s_v1->minvistime = 0;
2444 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
2445 /* Single event? Make window 1s wide... */
2447 s_v1->maxvistime = 1000000;
2450 recompute_hscrollbar();
2454 ep = (g_events + g_nevents - 1);
2455 s_v1->maxvistime = ep->time + event_incdec/3;
2456 s_v1->minvistime = s_v1->maxvistime - current_width;
2457 if (s_v1->minvistime > s_v1->maxvistime)
2459 recompute_hscrollbar();
2462 case MORE_TRACES_BUTTON:
2463 /* Reduce the strip height to fit more traces on screen */
2464 s_v1->strip_height -= 1;
2466 if (s_v1->strip_height < 1) {
2467 s_v1->strip_height = 1;
2470 /* Recalculate the number of strips on the screen */
2471 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2473 recompute_vscrollbar();
2476 case LESS_TRACES_BUTTON:
2477 /* Increase the strip height to fit fewer on the screen */
2478 s_v1->strip_height += 1;
2479 if (s_v1->strip_height > 80) {
2480 s_v1->strip_height = 80;
2483 /* Recalculate the number of strips on the screen */
2484 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2486 recompute_vscrollbar();
2489 case FORWARD_BUTTON:
2490 srch_chase_dir = SRCH_CHASE_FORWARD;
2491 gtk_widget_hide (s_view1_forward_button);
2492 gtk_widget_show (s_view1_backward_button);
2495 case BACKWARD_BUTTON:
2496 srch_chase_dir = SRCH_CHASE_BACKWARD;
2497 gtk_widget_show (s_view1_forward_button);
2498 gtk_widget_hide (s_view1_backward_button);
2501 case SUMMARY_BUTTON:
2502 summary_mode = TRUE;
2503 gtk_widget_hide (s_view1_summary_button);
2504 gtk_widget_show (s_view1_nosummary_button);
2507 case NOSUMMARY_BUTTON:
2508 summary_mode = FALSE;
2509 gtk_widget_show (s_view1_summary_button);
2510 gtk_widget_hide (s_view1_nosummary_button);
2513 case SLEW_LEFT_BUTTON:
2514 case SLEW_RIGHT_BUTTON:
2515 if (s_v1->last_time_interval < 10e-9) {
2516 infobox("slew", "\nNo time interval set...\n");
2519 slew_tracks (s_v1, click);
2523 view1_display_when_idle();
2526 /****************************************************************************
2527 * view1_print_callback
2528 ****************************************************************************/
2530 void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2532 modal_dialog("Print Screen (PostScript format) to file:",
2533 "Invalid file: Print Screen to file:",
2534 "g2.ps", print_screen_callback);
2537 /****************************************************************************
2539 ****************************************************************************/
2541 static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2543 ulonglong current_width;
2545 current_width = (s_v1->maxvistime - s_v1->minvistime);
2547 s_v1->minvistime = (ulonglong)(adj->value);
2548 s_v1->maxvistime = s_v1->minvistime + current_width;
2550 view1_display_when_idle();
2553 g_print ("adj->lower = %.2f\n", adj->lower);
2554 g_print ("adj->upper = %.2f\n", adj->upper);
2555 g_print ("adj->value = %.2f\n", adj->value);
2556 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2557 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2558 g_print ("adj->page_size = %.2f\n", adj->page_size);
2562 /****************************************************************************
2564 ****************************************************************************/
2566 static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2568 s_v1->first_pid_index = (int)adj->value;
2569 view1_display_when_idle();
2572 void set_pid_ax_width(int width)
2574 s_v1->pid_ax_width = width;
2575 view1_display_when_idle();
2578 /****************************************************************************
2580 ****************************************************************************/
2582 void view1_init(void)
2584 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2585 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2587 s_v1->pid_ax_width = 80;
2588 s_v1->time_ax_height = 80;
2589 s_v1->time_ax_spacing = 100;
2590 s_v1->strip_height = 25;
2591 s_v1->pop_offset = 20;
2592 s_v1->pid_ax_offset = 34;
2593 s_v1->event_offset = 40;
2594 s_v1->total_height = c_view1_draw_height;
2595 s_v1->total_width = c_view1_draw_width;
2596 s_v1->first_pid_index = 0;
2597 s_v1->anomaly_threshold_stddevs =
2598 atof(getprop_default("anomaly_threshold_stddevs", "2.5"));
2599 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2602 s_v1->minvistime = 0;
2603 s_v1->maxvistime = 200;
2605 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2607 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2609 da = gtk_drawing_area_new();
2610 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2611 c_view1_draw_height);
2614 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2615 (GtkSignalFunc) motion_notify_event, NULL);
2618 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2619 (GtkSignalFunc) expose_event, NULL);
2621 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2622 (GtkSignalFunc) configure_event, NULL);
2624 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2625 (GtkSignalFunc) button_press_event, NULL);
2627 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2628 (GtkSignalFunc) button_press_event, NULL);
2630 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2631 (GtkSignalFunc) button_press_event, NULL);
2633 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2634 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2635 | GDK_BUTTON_MOTION_MASK);
2638 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2640 g_font = gdk_font_load ("8x13");
2641 if (g_font == NULL) {
2642 g_error("Couldn't load 8x13 font...\n");
2644 gdk_font_ref(g_font);
2647 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2649 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
2650 0.0 /* minimum value */,
2651 2000.0 /* maximum value */,
2652 0.1 /* step increment */,
2653 10.0/* page increment */,
2654 10.0/* page size */);
2656 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2658 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2659 GTK_SIGNAL_FUNC (view1_vscroll),
2660 (gpointer)s_view1_vscroll);
2662 s_view1_topbutton = gtk_button_new_with_label("Top");
2663 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2665 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2666 GTK_SIGNAL_FUNC(view1_button_click_callback),
2667 (gpointer) TOP_BUTTON);
2669 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2670 GTK_SIGNAL_FUNC(view1_button_click_callback),
2671 (gpointer) BOTTOM_BUTTON);
2673 /* More Traces button and Less Traces button */
2674 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2675 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2676 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
2677 GTK_SIGNAL_FUNC(view1_button_click_callback),
2678 (gpointer) MORE_TRACES_BUTTON);
2679 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
2680 GTK_SIGNAL_FUNC(view1_button_click_callback),
2681 (gpointer) LESS_TRACES_BUTTON);
2684 /* Trick to bottom-justify the menu: */
2685 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2686 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2691 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2694 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2697 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2700 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2703 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2706 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2709 /* Time axis menu */
2711 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2713 s_view1_startbutton = gtk_button_new_with_label("Start");
2715 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2717 s_view1_searchbutton = gtk_button_new_with_label("Search");
2718 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2720 s_view1_anomalybutton = gtk_button_new_with_label("Anomaly");
2721 s_view1_anomalynextbutton = gtk_button_new_with_label("Next Anomaly");
2722 s_view1_anomalythresholdbutton =
2723 gtk_button_new_with_label ("Anomaly Threshold");
2725 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2727 s_view1_endbutton = gtk_button_new_with_label("End");
2729 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2730 GTK_SIGNAL_FUNC(view1_button_click_callback),
2731 (gpointer) START_BUTTON);
2733 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2734 GTK_SIGNAL_FUNC(view1_button_click_callback),
2735 (gpointer) ZOOMIN_BUTTON);
2737 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2738 GTK_SIGNAL_FUNC(view1_button_click_callback),
2739 (gpointer) SEARCH_BUTTON);
2741 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2742 GTK_SIGNAL_FUNC(view1_button_click_callback),
2743 (gpointer) SEARCH_AGAIN_BUTTON);
2745 gtk_signal_connect (GTK_OBJECT(s_view1_anomalybutton), "clicked",
2746 GTK_SIGNAL_FUNC(view1_button_click_callback),
2747 (gpointer) ANOMALY_BUTTON);
2749 gtk_signal_connect (GTK_OBJECT(s_view1_anomalynextbutton), "clicked",
2750 GTK_SIGNAL_FUNC(view1_button_click_callback),
2751 (gpointer) ANOMALY_NEXT_BUTTON);
2753 gtk_signal_connect (GTK_OBJECT(s_view1_anomalythresholdbutton),
2754 "clicked", GTK_SIGNAL_FUNC(view1_button_click_callback),
2755 (gpointer) ANOMALY_THRESHOLD_BUTTON);
2757 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2758 GTK_SIGNAL_FUNC(view1_button_click_callback),
2759 (gpointer) ZOOMOUT_BUTTON);
2761 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2762 GTK_SIGNAL_FUNC(view1_button_click_callback),
2763 (gpointer) END_BUTTON);
2765 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
2766 0.0 /* minimum value */,
2767 2000.0 /* maximum value */,
2768 0.1 /* step increment */,
2769 10.0/* page increment */,
2770 10.0/* page size */);
2772 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2774 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2775 GTK_SIGNAL_FUNC (view1_hscroll),
2776 (gpointer)s_view1_hscroll);
2778 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2781 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2784 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2787 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2790 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalybutton,
2792 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalynextbutton,
2794 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2797 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2800 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2803 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2806 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2810 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2812 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2814 s_view1_nextbutton = gtk_button_new_with_label("Next");
2816 s_view1_delbutton = gtk_button_new_with_label("Del");
2818 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2820 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2822 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2824 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2826 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2827 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2829 s_view1_summary_button = gtk_button_new_with_label("Summary");
2830 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2832 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2833 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2835 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2836 GTK_SIGNAL_FUNC(view1_button_click_callback),
2837 (gpointer) SNAP_BUTTON);
2839 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2840 GTK_SIGNAL_FUNC(view1_button_click_callback),
2841 (gpointer) NEXT_BUTTON);
2843 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2844 GTK_SIGNAL_FUNC(view1_button_click_callback),
2845 (gpointer) DEL_BUTTON);
2847 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
2848 GTK_SIGNAL_FUNC(view1_button_click_callback),
2849 (gpointer) CHASE_EVENT_BUTTON);
2851 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
2852 GTK_SIGNAL_FUNC(view1_button_click_callback),
2853 (gpointer) CHASE_DATUM_BUTTON);
2855 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
2856 GTK_SIGNAL_FUNC(view1_button_click_callback),
2857 (gpointer) CHASE_TRACK_BUTTON);
2859 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2860 GTK_SIGNAL_FUNC(view1_button_click_callback),
2861 (gpointer) UNCHASE_BUTTON);
2863 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2864 GTK_SIGNAL_FUNC(view1_button_click_callback),
2865 (gpointer) FORWARD_BUTTON);
2867 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2868 GTK_SIGNAL_FUNC(view1_button_click_callback),
2869 (gpointer) BACKWARD_BUTTON);
2871 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2872 GTK_SIGNAL_FUNC(view1_button_click_callback),
2873 (gpointer) SUMMARY_BUTTON);
2875 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2876 GTK_SIGNAL_FUNC(view1_button_click_callback),
2877 (gpointer) NOSUMMARY_BUTTON);
2879 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
2880 GTK_SIGNAL_FUNC(view1_button_click_callback),
2881 (gpointer) SLEW_LEFT_BUTTON);
2883 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
2884 GTK_SIGNAL_FUNC(view1_button_click_callback),
2885 (gpointer) SLEW_RIGHT_BUTTON);
2887 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2890 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2893 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2896 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2899 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2902 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2905 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2908 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2911 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2914 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2917 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2920 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2923 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2924 s_view1_time_slew_left_button,
2927 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2928 s_view1_time_slew_right_button,
2931 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2932 s_view1_anomalythresholdbutton,
2935 s_view1_label = gtk_label_new(NULL);
2937 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2940 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2943 gtk_widget_show_all (s_view1_vbox);
2944 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2945 gtk_widget_grab_focus(da);
2947 gtk_widget_hide (s_view1_forward_button);
2948 gtk_widget_hide (summary_mode ? s_view1_summary_button
2949 : s_view1_nosummary_button);
2951 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2953 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2956 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2958 &bg_white, zi_x_hot,
2960 gdk_pixmap_unref (zi_source);
2961 gdk_pixmap_unref (zi_mask);
2963 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2966 /****************************************************************************
2968 ****************************************************************************/
2970 void line_print (int x1, int y1, int x2, int y2)
2972 fprintf(s_printfp, "newpath\n");
2973 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
2974 yrt(x1, s_v1->total_height - y1));
2976 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2977 yrt (x2, s_v1->total_height - y2));
2978 fprintf(s_printfp, "1 setlinewidth\n");
2979 fprintf(s_printfp, "stroke\n");
2982 /****************************************************************************
2984 ****************************************************************************/
2985 GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2988 if (function == TBOX_PRINT_BOXED) {
2992 if ((function == TBOX_PRINT_BOXED) ||
2993 (function == TBOX_PRINT_EVENT)) {
2995 fprintf(s_printfp, "newpath\n");
2996 fprintf(s_printfp, "0 setlinewidth\n");
2997 fprintf(s_printfp, "%d %d moveto\n",
2998 xrt(rp->x, s_v1->total_height - rp->y),
2999 yrt(rp->x, s_v1->total_height - rp->y));
3001 fprintf(s_printfp, "%d %d lineto\n",
3002 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
3003 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
3005 fprintf(s_printfp, "%d %d lineto\n",
3006 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
3007 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
3009 fprintf(s_printfp, "%d %d lineto\n",
3010 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
3011 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
3013 fprintf(s_printfp, "%d %d lineto\n",
3014 xrt(rp->x, s_v1->total_height - rp->y),
3015 yrt(rp->x, s_v1->total_height - rp->y));
3017 fprintf(s_printfp, "stroke\n");
3020 if ((function == TBOX_PRINT_BOXED) ||
3021 (function == TBOX_PRINT_PLAIN)) {
3023 fprintf(s_printfp, "newpath\n");
3024 fprintf(s_printfp, "%d %d moveto\n",
3025 xrt(x, s_v1->total_height - (y-2)),
3026 yrt(x, s_v1->total_height - (y-2)));
3027 fprintf(s_printfp, "gsave\n");
3028 fprintf(s_printfp, "90 rotate\n");
3029 fprintf(s_printfp, "(%s) show\n", s);
3030 fprintf(s_printfp, "grestore\n");
3036 /****************************************************************************
3037 * tbox - draws an optionally boxed string whose lower lefthand
3038 * corner is at (x, y). As usual, Y is backwards.
3039 ****************************************************************************/
3041 GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
3043 static GdkRectangle update_rect;
3044 gint lbearing, rbearing, width, ascent, descent;
3046 gdk_string_extents (g_font, s,
3047 &lbearing, &rbearing,
3048 &width, &ascent, &descent);
3051 * If we have enough room to display full size events, then just
3052 * use the BOXED function instead of the EVENT function.
3054 if (s_v1->strip_height > 9) {
3056 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
3057 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
3058 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
3066 case TBOX_DRAW_BOXED:
3067 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3068 x, y - (ascent+descent+3), width + 2,
3069 ascent + descent + 3);
3071 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3072 x, y - (ascent+descent+3), width + 2,
3073 ascent + descent + 3);
3075 gdk_draw_string (pm, g_font, da->style->black_gc,
3076 x + 1, y - 1, (const gchar *)s);
3077 /* NOTE FALLTHROUGH */
3078 case TBOX_GETRECT_BOXED:
3080 update_rect.y = y -(ascent+descent+3);
3081 update_rect.width = width + 3;
3082 update_rect.height = ascent + descent + 4;
3083 if (function == TBOX_DRAW_BOXED)
3084 gtk_widget_draw (da, &update_rect);
3087 case TBOX_DRAW_EVENT:
3088 /* We have a small event to draw...no text */
3089 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3091 /* NOTE FALLTHROUGH */
3092 case TBOX_GETRECT_EVENT:
3094 update_rect.y = y - 1;
3095 update_rect.width = 4;
3096 update_rect.height = 4;
3097 if (function == TBOX_DRAW_EVENT)
3098 gtk_widget_draw (da, &update_rect);
3102 case TBOX_DRAW_PLAIN:
3104 gdk_draw_string (pm, g_font, da->style->black_gc,
3105 x + 1, y - 1, (const gchar *)s);
3106 /* NOTE FALLTHROUGH */
3107 case TBOX_GETRECT_PLAIN:
3109 update_rect.y = y -(ascent+descent+1);
3110 update_rect.width = width;
3111 update_rect.height = ascent + descent;
3112 if (function == TBOX_DRAW_PLAIN)
3113 gtk_widget_draw (da, &update_rect);
3116 case TBOX_PRINT_BOXED:
3118 update_rect.y = y -(ascent+descent+3);
3119 update_rect.width = width + 3;
3120 update_rect.height = ascent + descent + 4;
3121 /* note fallthrough */
3122 case TBOX_PRINT_PLAIN:
3123 return(tbox_print(s, x, y, function, &update_rect));
3125 case TBOX_PRINT_EVENT:
3126 /* We have a small event box to print...no text */
3128 update_rect.y = y - 1;
3129 update_rect.width = 4;
3130 update_rect.height = 4;
3131 return(tbox_print(s, x, y, function, &update_rect));
3133 return(&update_rect);
3136 /****************************************************************************
3139 * For lines there is a primitive batching facility, that doesn't update
3140 * the drawing area until the batch is complete. This is handy for drawing
3141 * the pid axis and for summary mode.
3143 * line_batch_mode contains the state for this:
3145 * BATCH_OFF: no batching, update for every line
3146 * BATCH_NEW: just entered a batch, so initialize the area to update from
3148 * BATCH_EXISTING: have drawn at least one line in batch mode, so the update
3149 * area should only be expanded from now on to include the
3150 * union of the "rectangular hull" of all lines
3151 ****************************************************************************/
3153 static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
3154 static int line_batch_count;
3155 static int line_minx, line_miny, line_maxx, line_maxy;
3157 void line_batch_start (void)
3159 line_batch_mode = BATCH_NEW;
3160 line_batch_count = 0;
3163 void line_batch_end (void)
3165 GdkRectangle update_rect;
3166 if (line_batch_count > 0) {
3167 update_rect.x = line_minx;
3168 update_rect.y = line_miny;
3169 update_rect.width = (line_maxx - line_minx) + 1;
3170 update_rect.height = (line_maxy - line_miny) + 1;
3171 gtk_widget_draw (da, &update_rect);
3173 line_batch_mode = BATCH_OFF;
3176 void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
3178 GdkRectangle update_rect;
3182 case LINE_DRAW_BLACK:
3183 gc = da->style->black_gc;
3186 case LINE_DRAW_WHITE:
3187 gc = da->style->white_gc;
3191 line_print (x1, y1, x2, y2);
3195 gdk_draw_line (pm, gc, x1, y1, x2, y2);
3197 switch (line_batch_mode) {
3201 update_rect.width = (x2-x1) + 1;
3202 update_rect.height = (y2-y1) + 1;
3203 gtk_widget_draw (da, &update_rect);
3211 line_batch_mode = BATCH_EXISTING;
3212 line_batch_count = 1;
3215 case BATCH_EXISTING:
3230 /****************************************************************************
3232 ****************************************************************************/
3234 static void display_pid_axis(v1_geometry_t *vp)
3236 int y, i, label_tick;
3237 int last_printed_y = -vp->strip_height;
3243 /* No pids yet? Outta here */
3249 for (i = 0; i < vp->npids; i++) {
3250 pid_index = vp->first_pid_index + i;
3251 if (pid_index >= g_npids)
3254 pp = (g_pids + pid_index);
3256 set_color(pid_index);
3258 label_fmt = get_track_label(pp->pid_value);
3259 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
3261 y = i*vp->strip_height + vp->pid_ax_offset;
3264 * Have we incremented enough space to have another label not
3265 * overlap the previous label?
3267 if (y - last_printed_y > 9) {
3269 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
3274 * And let the line stick out a bit more to indicate this label
3275 * relates to the following line.
3283 /* Draw axis line, but only if the lines aren't too close together */
3284 if (vp->strip_height > 4) {
3285 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
3286 vp->total_width, y+4*s_print_offset,
3287 LINE_DRAW_BLACK+s_print_offset);
3291 set_color(COLOR_DEFAULT);
3295 /****************************************************************************
3296 * view1_read_events_callback
3297 * New event data just showed up, reset a few things.
3298 ****************************************************************************/
3300 void view1_read_events_callback(void)
3304 s_v1->first_pid_index = 0;
3306 max_vis_index = 300;
3307 if (max_vis_index > g_nevents)
3308 max_vis_index = g_nevents-1;
3310 s_v1->minvistime = 0LL;
3311 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
3312 /* Single event? Make the initial display 1s wide */
3314 s_v1->maxvistime = 1000000;
3317 s_last_selected_event = 0;
3319 init_track_colors();
3321 recompute_hscrollbar();
3322 recompute_vscrollbar();
3325 /****************************************************************************
3326 * display_event_data
3327 ****************************************************************************/
3329 static void display_event_data(v1_geometry_t *vp)
3336 double time_per_pixel;
3338 GdkRectangle *print_rect;
3341 /* Happens if one loads the event def header first, for example. */
3345 time_per_pixel = dtime_per_pixel(vp);
3347 start_index = find_event_index (vp->minvistime);
3349 /* Scrolled too far right? */
3350 if (start_index >= g_nevents)
3353 ep = (g_events + start_index);
3355 if (s_print_offset || summary_mode) {
3356 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3363 while (ep < (g_events + g_nevents) &&
3364 (ep->time < vp->maxvistime)) {
3365 pid_index = ep->pid->pid_index;
3366 set_color(pid_index);
3368 /* First filter: pid out of range */
3369 if ((pid_index < vp->first_pid_index) ||
3370 (pid_index >= vp->first_pid_index + vp->npids)) {
3375 /* Second filter: event hidden */
3376 edp = find_event_definition (ep->code);
3377 if (!edp->selected) {
3384 pid_index -= vp->first_pid_index;
3386 y = pid_index*vp->strip_height + vp->event_offset;
3388 x = vp->pid_ax_width +
3389 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3391 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3396 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3397 if (ep->flags & EVENT_FLAG_SELECT) {
3398 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3400 snprintf(tmpbuf, sizeof(tmpbuf), "SEARCH RESULT");
3402 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3403 TBOX_DRAW_BOXED+s_print_offset);
3404 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3405 if (last_x_used != NULL)
3406 last_x_used[pid_index] = x + print_rect->width;
3409 int delta = vp->strip_height / 3;
3412 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3413 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3414 last_x_used[pid_index] = x + 1;
3416 snprintf(tmpbuf, sizeof(tmpbuf), "%ld", ep->code);
3417 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3418 if (last_x_used != NULL)
3419 last_x_used[pid_index] = x + print_rect->width;
3425 g_free(last_x_used);
3427 set_color(COLOR_DEFAULT);
3430 /****************************************************************************
3432 ****************************************************************************/
3434 static void display_clear(void)
3436 GdkRectangle update_rect;
3438 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3439 0, 0, da->allocation.width,
3440 da->allocation.height);
3444 update_rect.width = da->allocation.width;
3445 update_rect.height = da->allocation.height;
3447 gtk_widget_draw (da, &update_rect);
3450 /****************************************************************************
3452 ****************************************************************************/
3454 static void display_time_axis(v1_geometry_t *vp)
3457 int xoffset, nticks;
3459 double unit_divisor;
3462 double time_per_pixel;
3464 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3466 x = vp->pid_ax_width;
3468 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3470 time_per_pixel = dtime_per_pixel(vp);
3473 unit_divisor = 1.00;
3475 if ((vp->maxvistime / unit_divisor) > 1000) {
3477 unit_divisor = 1000.00;
3480 if ((vp->maxvistime / unit_divisor) > 1000) {
3482 unit_divisor = 1000.00*1000.00;
3484 if ((vp->maxvistime / unit_divisor) > 1000) {
3486 unit_divisor = 1000.00*1000.00*1000.00;
3490 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3494 for (i = 0; i < nticks; i++) {
3496 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3498 time = (double)(x + xoffset - vp->pid_ax_width);
3499 time *= time_per_pixel;
3500 time += (double)(vp->minvistime);
3501 time /= unit_divisor;
3503 snprintf (tmpbuf, sizeof(tmpbuf), "%.2f%s", time, units);
3505 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3507 xoffset += vp->time_ax_spacing;
3511 /****************************************************************************
3513 * Forget about any temporary displays, they're gone now...
3514 ****************************************************************************/
3516 static void clear_scoreboard(void)
3518 s_result_up = FALSE;
3521 /****************************************************************************
3523 ****************************************************************************/
3525 void view1_display(void)
3528 display_pid_axis(s_v1);
3529 display_event_data(s_v1);
3530 display_time_axis(s_v1);
3534 static gint idle_tag;
3536 /****************************************************************************
3537 * view1_display_eventually
3538 ****************************************************************************/
3540 static void view1_display_eventually(void)
3542 gtk_idle_remove(idle_tag);
3548 /****************************************************************************
3549 * view1_display_when_idle
3550 ****************************************************************************/
3552 void view1_display_when_idle(void)
3554 if (idle_tag == 0) {
3555 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3559 /****************************************************************************
3561 ****************************************************************************/
3563 void view1_about (char *tmpbuf)
3568 snprintf(tmpbuf+strlen(tmpbuf), 128, "Minvistime %lld\nMaxvistime %lld\n",
3569 s_v1->minvistime, s_v1->maxvistime);
3570 snprintf(tmpbuf+strlen(tmpbuf), 128, "Strip Height %d\n",
3571 s_v1->strip_height);
3573 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3576 snprintf(tmpbuf+strlen(tmpbuf), 128, "%d snapshots in the ring\n", nsnaps);