2 *------------------------------------------------------------------
3 * Copyright (c) 2005-2016 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>
29 * The main event display view.
31 * Important variables:
33 * "da" -- the drawing area, aka the screen representation of the
36 * "pm" -- the backing pixmap for the drawing area. Note that
37 * all graphics operations target this backing
38 * store, then call gtk_widget_draw to copy a rectangle from
39 * the backing store onto the screen.
41 * "s_v1" -- pointer to the current v1_geometry_t object.
47 * s_view1_topbutton("Top")
48 * s_view1_vscroll (vertical scrollbar)
49 * s_view1_bottombutton("Bottom")
51 * s_view1_startbutton("Start");
52 * s_view1_hscroll(horizontal scrollbar)
53 * s_view1_endbutton("End")
54 * s_view1_zoominbutton("Zoomin")
55 * s_view1_searchbutton("Search")
56 * s_view1_searchagainbutton("Search Again")
57 * s_view1_zoomoutbutton("Zoomout")
65 GdkFont *g_font; /* a fixed-width font to use */
66 /* color format: 0 (for static colors), r (0-64k), g (0-64k), b (0-64k) */
67 GdkColor fg_black = {0, 0, 0, 0};
68 GdkColor fg_red = {0, 65535, 0, 0};
69 GdkColor bg_white = {0, 65535, 65535, 65535};
70 static boolean summary_mode = TRUE; /* start out in summary mode */
71 static boolean color_mode = FALSE; /* start out in monochrome mode */
78 * user_data values passed to view1_button_click_callback,
79 * which is used by the various action buttons noted above
81 enum view1_button_click {
114 SRCH_CHASE_FORWARD = 0,
115 SRCH_CHASE_BACKWARD = 1,
118 static GtkWidget *s_view1_hbox; /* see box heirarchy chart */
119 static GtkWidget *s_view1_vbox; /* see box heirarchy chart */
120 static GtkWidget *da; /* main drawing area */
121 static GdkPixmap *pm; /* and its backing pixmap */
122 static GdkCursor *norm_cursor; /* the "normal" cursor */
125 * view geometry parameters
128 * Y increases down the page.
129 * Strip origin is at the top
131 * Don't put your fingers in your mouth.
133 * Most of these values are in pixels
136 typedef struct v1_geometry {
137 int pid_ax_width; /* Width of the PID axis */
138 int time_ax_height; /* Height of the time axis */
139 int time_ax_spacing; /* TimeAxis: Space between tick-marks */
140 int strip_height; /* Height of a regular PID trace */
141 int pop_offset; /* Vertical offset of the detail box */
142 int pid_ax_offset; /* Vertical offset of the PID axis */
143 int event_offset; /* Vertical offset of the event boxes */
144 int total_height; /* total height of da, see configure_event */
145 int total_width; /* ditto, for width */
146 double last_time_interval; /* last time interval, in f64 seconds */
149 int first_pid_index; /* Index of first displayed PID */
150 int npids; /* Max number of displayed pids */
151 ulonglong minvistime; /* in usec */
152 ulonglong maxvistime; /* in usec */
156 /* The active geometry object */
157 static v1_geometry_t s_v1record;
158 static v1_geometry_t *s_v1 = &s_v1record;
160 /* The color array */
161 static GdkColor *s_color;
164 typedef struct snapshot {
165 struct snapshot *next;
166 /* Screen geometry */
167 v1_geometry_t geometry;
168 boolean show_event[NEVENTS];
171 * Note: not worth recomputing the vertical scrollbar, just save
174 gfloat vscroll_value;
175 boolean summary_mode;
179 static snapshot_t *s_snapshots;
180 static snapshot_t *s_cursnap;
181 static event_t *s_last_selected_event;
184 * various widgets, see the box heirarchy chart above
185 * The toolkit keeps track of these things, we could lose many of
188 static GtkWidget *s_view1_vmenubox;
189 static GtkWidget *s_view1_topbutton;
190 static GtkWidget *s_view1_bottombutton;
191 static GtkWidget *s_view1_more_traces_button;
192 static GtkWidget *s_view1_less_traces_button;
194 static GtkWidget *s_view1_hmenubox;
195 static GtkWidget *s_view1_hmenubox2;
196 static GtkWidget *s_view1_startbutton;
197 static GtkWidget *s_view1_zoominbutton;
198 static GtkWidget *s_view1_searchbutton;
199 static GtkWidget *s_view1_srchagainbutton;
200 static GtkWidget *s_view1_zoomoutbutton;
201 static GtkWidget *s_view1_endbutton;
203 static GtkWidget *s_view1_snapbutton;
204 static GtkWidget *s_view1_nextbutton;
205 static GtkWidget *s_view1_delbutton;
207 static GtkWidget *s_view1_chase_event_button;
208 static GtkWidget *s_view1_chase_datum_button;
209 static GtkWidget *s_view1_chase_track_button;
210 static GtkWidget *s_view1_unchasebutton;
212 static GtkWidget *s_view1_forward_button;
213 static GtkWidget *s_view1_backward_button;
215 static GtkWidget *s_view1_summary_button;
216 static GtkWidget *s_view1_nosummary_button;
218 static GtkWidget *s_view1_time_slew_right_button;
219 static GtkWidget *s_view1_time_slew_left_button;
221 static GtkWidget *s_view1_hscroll;
222 static GtkObject *s_view1_hsadj;
224 static GtkWidget *s_view1_vscroll;
225 static GtkObject *s_view1_vsadj;
227 static GtkWidget *s_view1_label;
232 static ulong s_srchcode; /* search event code */
233 static int s_srchindex; /* last hit was at this event index */
234 static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */
235 static boolean s_srchfail_up; /* The status line "Search Failed" is up */
236 static int srch_chase_dir; /* search/chase dir, 0=>forward */
242 static int s_print_offset; /* Magic offset added to line, tbox fn codes */
243 static FILE *s_printfp;
246 * Forward reference prototypes
248 static void display_pid_axis(v1_geometry_t *vp);
249 static void display_event_data(v1_geometry_t *vp);
250 static void display_time_axis(v1_geometry_t *vp);
251 static void view1_button_click_callback(GtkButton *item, gpointer data);
257 gint c_view1_draw_width;
258 gint c_view1_draw_height;
261 * Zoom-In / Time Ruler cursor
268 static unsigned char zi_bits[] = {
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
270 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
271 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
272 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
273 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
274 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
275 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
276 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
277 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
278 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
281 static unsigned char zi_bkgd[] = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
283 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
284 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
285 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
286 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
287 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
288 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
289 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
290 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
291 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
294 static GdkCursor *zi_cursor;
295 static GdkPixmap *zi_source, *zi_mask;
298 * Frequently-used small computations, best
299 * done correctly once and instantiated.
302 /****************************************************************************
304 ****************************************************************************/
306 static inline double dtime_per_pixel(v1_geometry_t *vp)
308 return ((double)(vp->maxvistime - vp->minvistime)) /
309 ((double)(vp->total_width - vp->pid_ax_width));
312 /****************************************************************************
314 * Changes the status line. Pass "" to clear the status line.
315 ****************************************************************************/
317 void message_line (char *s)
319 gtk_label_set_text (GTK_LABEL(s_view1_label), s);
322 /****************************************************************************
324 * Changes the window title to include the specified filename.
325 ****************************************************************************/
327 void set_window_title (const char *filename)
330 snprintf(title, sizeof(title), "g2 (%s)", filename);
331 gtk_window_set_title(GTK_WINDOW(g_mainwindow), title);
334 /****************************************************************************
335 * recompute_hscrollbar
336 * Adjust the horizontal scrollbar's adjustment object.
338 * GtkAdjustments are really cool, but have to be set up exactly
339 * right or the various client objects screw up completely.
341 * Note: this function is *not* called when the user clicks the scrollbar.
342 ****************************************************************************/
344 static void recompute_hscrollbar (void)
346 ulonglong current_width;
347 ulonglong event_incdec;
354 ep = (g_events + (g_nevents-1));
355 current_width = s_v1->maxvistime - s_v1->minvistime;
356 event_incdec = (current_width) / 6;
358 adj = GTK_ADJUSTMENT(s_view1_hsadj);
361 * Structure member decoder ring
362 * -----------------------------
363 * lower the minimum possible value
364 * value the current value
365 * upper the maximum possible value
366 * step_increment end button click increment
367 * page_increment click in trough increment
368 * page_size size of currently visible area
371 adj->lower = (gfloat)0.00;
372 adj->value = (gfloat)s_v1->minvistime;
374 /* Minor click: move about 1/6 of a page */
375 adj->step_increment = (gfloat)event_incdec;
377 /* Major click: move about 1/3 of a page. */
378 adj->page_increment = (gfloat)(2*event_incdec);
380 /* allow the user to go a bit past the end */
381 adj->upper = adj->page_increment/3 + (gfloat)(ep->time);
382 adj->page_size = (gfloat)(current_width);
385 * Tell all clients (e.g. the visible scrollbar) to
386 * make themselves look right
388 gtk_adjustment_changed(adj);
389 gtk_adjustment_value_changed(adj);
392 /****************************************************************************
393 * recompute_vscrollbar
394 * Ditto, for the vertical scrollbar
395 ****************************************************************************/
397 static void recompute_vscrollbar (void)
401 adj = GTK_ADJUSTMENT(s_view1_vsadj);
403 adj->lower = (gfloat)0.00;
404 adj->upper = (gfloat)g_npids;
405 adj->value = (gfloat)0.00;
406 adj->step_increment = 1.00;
407 adj->page_increment = (gfloat)(s_v1->npids / 3);
408 adj->page_size = (gfloat)s_v1->npids;
409 gtk_adjustment_changed(adj);
410 gtk_adjustment_value_changed(adj);
413 /****************************************************************************
414 * format_popbox_string
415 ****************************************************************************/
417 elog_main_t elog_main;
419 void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp)
424 sprintf(tmpbuf,"%d:", ep->code);
426 if (ep->flags & EVENT_FLAG_CLIB) {
430 eep = get_clib_event (ep->datum);
432 s = format (0, "%U", format_elog_event, &elog_main, eep);
433 memcpy (tmpbuf, s, vec_len(s));
434 tmpbuf[vec_len(s)] = 0;
439 snprintf(tmpbuf, len, "%s", edp->name);
441 /* Make sure there's a real format string. If so, add it */
444 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
445 /* %s only supported for cpel files */
447 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
448 edp->format, strtab_ref(ep->datum));
450 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
451 edp->format, ep->datum);
459 /****************************************************************************
461 ****************************************************************************/
463 static void add_snapshot(void)
466 snapshot_t *new = g_malloc(sizeof(snapshot_t));
468 memcpy(&new->geometry, s_v1, sizeof(new->geometry));
469 for (i = 0; i < NEVENTS; i++) {
470 new->show_event[i] = g_eventdefs[i].selected;
472 new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids);
473 memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids);
474 new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value;
475 new->summary_mode = summary_mode;
476 new->color_mode = color_mode;
479 new->next = s_snapshots;
488 /****************************************************************************
490 ****************************************************************************/
492 static void next_snapshot(void)
500 infobox("No snapshots", "\nNo snapshots in the ring...\n");
504 next = s_cursnap->next;
510 memcpy(s_v1, &next->geometry, sizeof(next->geometry));
511 for (i = 0; i < NEVENTS; i++) {
512 g_eventdefs[i].selected = next->show_event[i];
514 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
515 color_mode = next->color_mode;
517 * Update summary mode via a button push so that the button state is
518 * updated accordingly. (Should ideally clean up the view/controller
519 * separation properly one day.)
521 if (summary_mode != next->summary_mode) {
522 view1_button_click_callback
523 (NULL, (gpointer)(unsigned long long)
524 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
527 /* Fix the pid structure index mappings */
530 for (i = 0; i < g_npids; i++) {
535 GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value;
536 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
537 recompute_hscrollbar();
538 pointsel_next_snapshot();
539 view1_display_when_idle();
543 /****************************************************************************
545 ****************************************************************************/
547 static void del_snapshot(void)
553 infobox("No snapshots", "\nNo snapshots to delete...\n");
560 while (this && this != s_cursnap) {
565 if (this != s_cursnap) {
566 infobox("BUG", "\nSnapshot AWOL!\n");
570 s_cursnap = this->next;
572 /* middle of the list? */
574 prev->next = this->next;
575 g_free(this->pidvec);
577 } else { /* start of the list */
578 s_snapshots = this->next;
579 g_free(this->pidvec);
583 /* Note: both will be NULL after last delete */
584 if (s_cursnap == NULL)
585 s_cursnap = s_snapshots;
588 /****************************************************************************
591 * VERY primitive right now - not endian or version independent, and only
592 * writes to "snapshots.g2" in the current directory
593 ****************************************************************************/
594 static void write_snapshot(void)
601 if (s_snapshots == NULL) {
602 error = "No snapshots defined";
607 file = fopen("snapshots.g2", "w");
609 error = "Unable to open snapshots.g2";
614 * Simply serialize the arch-dependent binary data, without a care in the
615 * world. Don't come running to me if you try to read it and crash.
617 for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) {
618 if (fwrite(&snap->geometry,
619 sizeof(snap->geometry), 1, file) != 1 ||
620 fwrite(&snap->show_event,
621 sizeof(snap->show_event), 1, file) != 1 ||
623 sizeof(pid_sort_t) * g_npids, 1, file) != 1 ||
624 fwrite(&snap->vscroll_value,
625 sizeof(snap->vscroll_value), 1, file) != 1 ||
626 fwrite(&snap->summary_mode,
627 sizeof(snap->summary_mode), 1, file) != 1 ||
628 fwrite(&snap->color_mode,
629 sizeof(snap->color_mode), 1, file) != 1) {
630 error = "Error writing data";
637 error = "Unable to close file";
642 infobox(error, strerror(errno));
645 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
651 /****************************************************************************
654 * VERY primitive right now - not endian or version independent, and only reads
655 * from "snapshots.g2" in the current directory
656 ****************************************************************************/
657 static void read_snapshot(void)
660 snapshot_t *snap, *next_snap;
661 snapshot_t *new_snaps = NULL;
663 int len, i, records = 0;
666 file = fopen("snapshots.g2", "r");
668 error = "Unable to open snapshots.g2";
672 * Read in the snapshots and link them together. We insert them backwards,
673 * but that's tolerable. If the data is in anyway not what we expect, we'll
674 * probably crash. Sorry.
676 while (!error && !feof(file)) {
677 snap = g_malloc(sizeof(*snap));
678 snap->pidvec = NULL; /* so we can free this if there's an error */
680 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
686 /* insert into list straight away */
687 snap->next = new_snaps;
691 error = "Problem reading first item from file";
694 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
695 error = "Problem reading second item from file";
698 len = sizeof(pid_sort_t) * g_npids;
699 snap->pidvec = g_malloc(len);
700 if (fread(snap->pidvec, len, 1, file) != 1) {
701 error = "Problem reading third item from file";
704 if (fread(&snap->vscroll_value,
705 sizeof(snap->vscroll_value), 1, file) != 1 ||
706 fread(&snap->summary_mode,
707 sizeof(snap->summary_mode), 1, file) != 1 ||
708 fread(&snap->color_mode,
709 sizeof(snap->color_mode), 1, file) != 1) {
710 error = "Problem reading final items from file";
715 * Fix up the pointers from the sorted pid vector back into our pid
716 * data objects, by walking the linked list of pid_data_t objects for
717 * every one looking for a match. This is O(n^2) grossness, but in real
718 * life there aren't that many pids, and it seems zippy enough.
720 for (i = 0; i < g_npids; i++) {
721 for (pp = g_pid_data_list; pp != NULL; pp = pp->next) {
722 if (pp->pid_value == snap->pidvec[i].pid_value) {
727 snap->pidvec[i].pid = pp;
729 error = "Snapshot file referenced unknown pids";
739 error = "Unable to close file";
745 * Problem - clear up any detritus
747 infobox(error, strerror(errno));
748 for (snap = new_snaps; snap != NULL; snap = next_snap) {
749 next_snap = snap->next;
751 g_free(snap->pidvec);
755 * Success! trash the old snapshots and replace with the new
757 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
758 next_snap = snap->next;
759 g_free(snap->pidvec);
763 s_cursnap = s_snapshots = new_snaps;
767 infobox(error, strerror(errno));
770 snprintf(buf, sizeof(buf),
771 "Read %d snapshots from snapshots.g2", records);
776 /****************************************************************************
779 * Set the color for the specified pid_index, or COLOR_DEFAULT to return it
780 * to the usual black.
781 ****************************************************************************/
782 #define COLOR_DEFAULT (-1)
783 static void set_color(int pid_index)
787 psp = (g_pids + pid_index);
790 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
791 else if (pid_index == COLOR_DEFAULT || !color_mode) {
792 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
794 gdk_gc_set_foreground(da->style->black_gc,
795 &s_color[g_pids[pid_index].color_index]);
799 /****************************************************************************
800 * toggle_event_select
801 ****************************************************************************/
803 static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
805 int pid_index, start_index;
808 GdkRectangle hit_rect;
813 double time_per_pixel;
818 time_per_pixel = dtime_per_pixel(vp);
820 start_index = find_event_index (vp->minvistime);
823 if (start_index >= g_nevents)
827 * To see if the mouse hit a visible event, use a variant
828 * of the event display loop.
831 hit_rect.x = (int)event->x;
832 hit_rect.y = (int)event->y;
836 ep = (g_events + start_index);
838 while ((ep->time < vp->maxvistime) &&
839 (ep < (g_events + g_nevents))) {
840 pid_index = ep->pid->pid_index;
842 /* First filter: pid out of range */
843 if ((pid_index < vp->first_pid_index) ||
844 (pid_index >= vp->first_pid_index + vp->npids)) {
849 /* Second filter: event hidden */
850 edp = find_event_definition (ep->code);
851 if (!edp->selected) {
857 * At this point, we know that the point is at least on the
858 * screen. See if the mouse hit within the bounding box
862 * $$$$ maybe keep looping until off the edge,
863 * maintain a "best hit", then declare that one the winner?
866 pid_index -= vp->first_pid_index;
868 y = pid_index*vp->strip_height + vp->event_offset;
870 x = vp->pid_ax_width +
871 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
873 /* Perhaps we're trying to toggle the detail box? */
874 if (ep->flags & EVENT_FLAG_SELECT) {
875 /* Figure out the dimensions of the detail box */
876 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
877 rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED);
878 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
879 ep->flags &= ~EVENT_FLAG_SELECT;
880 view1_display_when_idle();
885 sprintf(tmpbuf, "%ld", ep->code);
887 /* Figure out the dimensions of the regular box */
888 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
890 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
891 /* we hit the rectangle. */
892 if (ep->flags & EVENT_FLAG_SELECT) {
893 ep->flags &= ~EVENT_FLAG_SELECT;
894 view1_display_when_idle();
897 set_color(ep->pid->pid_index);
899 /* It wasn't selected, so put up the detail box */
900 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
901 tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED);
902 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK);
903 ep->flags |= EVENT_FLAG_SELECT;
904 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
905 s_last_selected_event = ep;
914 /****************************************************************************
915 * toggle_track_select
916 ****************************************************************************/
918 static void toggle_track_select (GdkEventButton *event,
929 /* Scan pid/track axis locations, looking for a match */
930 for (i = 0; i < vp->npids; i++) {
931 y = i*vp->strip_height + vp->pid_ax_offset;
932 delta_y = y - event->y;
940 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
944 pid_index = i + vp->first_pid_index;
945 psp = (g_pids + pid_index);
947 view1_display_when_idle();
950 /****************************************************************************
952 ****************************************************************************/
953 static void deselect_tracks (void)
957 for (i = 0; i < g_npids; i++)
958 g_pids[i].selected = 0;
963 /****************************************************************************
965 ****************************************************************************/
967 typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
969 static void move_current_track(GdkEventButton *event,
976 pid_sort_t *new_pidvec;
978 pid_sort_t *pold, *pnew;
984 /* Scan pid/track axis locations, looking for a match */
985 for (i = 0; i < vp->npids; i++) {
986 y = i*vp->strip_height + vp->pid_ax_offset;
987 delta_y = y - event->y;
995 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
999 pid_index = i + vp->first_pid_index;
1001 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
1005 if (type == MOVE_TOP) {
1007 *pnew++ = g_pids[pid_index];
1008 for (i = 0; i < pid_index; i++)
1012 for (; i < g_npids; i++)
1015 /* move to bottom */
1016 for (i = 0; i < pid_index; i++)
1020 for (; i < g_npids; i++)
1022 *pnew = g_pids[pid_index];
1026 g_pids = new_pidvec;
1029 * Revert the pid_index mapping to an identity map,
1033 for (i = 0; i < g_npids; i++) {
1038 view1_display_when_idle();
1041 /****************************************************************************
1043 * Process a zoom gesture. The use of doubles is required to avoid
1044 * truncating the various variable values, which in turn would lead to
1045 * some pretty random-looking zoom responses.
1046 ****************************************************************************/
1048 void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1051 double time_per_pixel;
1052 double width_in_pixels;
1053 double center_on_time, width_in_time;
1054 double center_on_pixel;
1057 * Clip the zoom area to the event display area.
1058 * Otherwise, center_on_time - width_in_time is in hyperspace
1059 * to the left of zero
1062 if (e1->x < vp->pid_ax_width)
1063 e1->x = vp->pid_ax_width;
1065 if (e2->x < vp->pid_ax_width)
1066 e2->x = vp->pid_ax_width;
1069 goto loser_zoom_repaint;
1071 xrange = (double) (e2->x - e1->x);
1075 /* Actually, width in pixels of half the zoom area */
1076 width_in_pixels = xrange / 2.00;
1077 time_per_pixel = dtime_per_pixel(vp);
1078 width_in_time = width_in_pixels * time_per_pixel;
1080 /* Center the screen on the center of the zoom area */
1081 center_on_pixel = (double)((e2->x + e1->x) / 2.00) -
1082 (double)vp->pid_ax_width;
1083 center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime;
1086 * Transform back to 64-bit integer microseconds, reset the
1087 * scrollbar, schedule a repaint.
1089 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1090 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1093 recompute_hscrollbar();
1095 view1_display_when_idle();
1098 /****************************************************************************
1101 * Scroll up or down by the specified delta
1103 ****************************************************************************/
1104 static void scroll_y(int delta)
1106 int new_index = s_v1->first_pid_index + delta;
1107 if (new_index + s_v1->npids > g_npids)
1108 new_index = g_npids - s_v1->npids;
1112 if (new_index != s_v1->first_pid_index) {
1113 s_v1->first_pid_index = new_index;
1114 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index;
1115 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1116 view1_display_when_idle();
1120 /****************************************************************************
1121 * view1_handle_key_press_event
1122 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1124 * This routine implements hotkeys for the Quake generation:
1135 * E - toggle summary mode
1136 * C - toggle color mode
1140 * P - persist snapshots to file
1141 * L - load snapshots from file
1145 ****************************************************************************/
1147 view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1151 switch (event->keyval) {
1152 case GDK_w: // zoom in
1153 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1156 case GDK_s: // zoom out
1157 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1160 case GDK_a: // pan left
1161 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1162 if (s_v1->minvistime < delta) {
1163 delta = s_v1->minvistime;
1165 s_v1->minvistime -= delta;
1166 s_v1->maxvistime -= delta;
1167 recompute_hscrollbar();
1170 case GDK_d: // pan right
1171 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1172 if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) {
1174 * @@@ this doesn't seem to quite reach the far right hand
1175 * side correctly - not sure why.
1177 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1179 s_v1->minvistime += delta;
1180 s_v1->maxvistime += delta;
1181 recompute_hscrollbar();
1184 case GDK_r: // pan up
1188 case GDK_f: // pan down
1192 case GDK_t: // fewer tracks
1193 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1196 case GDK_g: // more tracks
1197 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1200 case GDK_e: // toggle summary mode
1201 view1_button_click_callback
1202 (NULL, (gpointer)(unsigned long long)
1203 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
1206 case GDK_c: // toggle color mode
1208 view1_display_when_idle();
1211 case GDK_p: // persist snapshots
1215 case GDK_l: // load snapshots
1219 case GDK_x: // take snapshot
1220 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1223 case GDK_z: // next snapshot
1224 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1227 case GDK_q: // ctrl-q is exit
1228 if (event->state & GDK_CONTROL_MASK) {
1236 /****************************************************************************
1237 * button_press_event
1238 * Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1240 * This routine implements three functions: zoom-to-area, time ruler, and
1241 * show/hide event detail popup.
1243 * The left mouse button (button 1) has two simultaneous functions: event
1244 * detail popup, and zoom-to-area. If the press and release events occur
1245 * within a small delta-x, it's a detail popup event. Otherwise, it's
1248 * The right mouse button (button 3) implements the time ruler.
1249 ****************************************************************************/
1252 button_press_event (GtkWidget *widget, GdkEventButton *event)
1254 static GdkEventButton press1_event;
1255 static boolean press1_valid;
1256 static GdkEventButton press3_event;
1257 static guint32 last_truler_time;
1258 static boolean press3_valid;
1259 static boolean zoom_bar_up;
1260 int time_ax_y, xdelta;
1262 double time_per_pixel;
1266 switch(event->type) {
1267 case GDK_BUTTON_PRESS:
1268 /* Capture the appropriate starting point */
1269 if (event->button == 1) {
1270 press1_valid = TRUE;
1271 press1_event = *event;
1274 if (event->button == 3) {
1275 press3_valid = TRUE;
1276 press3_event = *event;
1281 case GDK_BUTTON_RELEASE:
1284 press3_valid = FALSE;
1285 /* Fix the cursor, and repaint the screen from scratch */
1286 gdk_window_set_cursor (da->window, norm_cursor);
1287 view1_display_when_idle();
1290 /* Event select / zoom-to-area */
1292 press1_valid = FALSE;
1293 xdelta = (int)(press1_event.x - event->x);
1297 /* is the mouse more or less where it started? */
1299 /* Control-left-mouse => sink the track */
1300 /* Shift-left-mouse => raise the track */
1301 if ((press1_event.state & GDK_CONTROL_MASK) ==
1303 move_current_track(event, s_v1, MOVE_BOTTOM);
1304 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1306 move_current_track(event, s_v1, MOVE_TOP);
1308 /* No modifiers: toggle the event / select track */
1309 if (toggle_event_select(event, s_v1))
1310 toggle_track_select(event, s_v1);
1312 /* Repaint to get rid of the zoom bar */
1314 /* Fix the cursor and leave. No zoom */
1315 gdk_window_set_cursor (da->window, norm_cursor);
1316 zoom_bar_up = FALSE;
1319 } else { /* mouse moved enough to zoom */
1320 zoom_event(&press1_event, event, s_v1);
1321 gdk_window_set_cursor (da->window, norm_cursor);
1322 zoom_bar_up = FALSE;
1324 } else if (event->button == 4) {
1325 /* scroll wheel up */
1326 scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1);
1327 } else if (event->button == 5) {
1328 /* scroll wheel down */
1329 scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1);
1333 case GDK_MOTION_NOTIFY:
1334 /* Button one followed by motion: draw zoom fence and fix cursor */
1336 /* Fence, cursor already set */
1340 xdelta = (int)(press1_event.x - event->x);
1344 /* Haven't moved enough to declare a zoom sequence yet */
1348 /* Draw the zoom fence, use the key-down X coordinate */
1349 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1351 line((int)(press1_event.x), s_v1->pop_offset,
1352 (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK);
1353 tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset,
1355 gdk_window_set_cursor(da->window, zi_cursor);
1362 gdk_window_set_cursor(da->window, zi_cursor);
1365 * Some filtration is needed on Solaris, or the server will hang
1367 if (event->time - last_truler_time < 75)
1370 last_truler_time = event->time;
1372 line((int)(press3_event.x), s_v1->pop_offset,
1373 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1375 xdelta = (int)(press3_event.x - event->x);
1379 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1380 ((double)(s_v1->total_width - s_v1->pid_ax_width));
1382 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1384 line((int)(press3_event.x), s_v1->pop_offset,
1385 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1387 * Note: use a fixed-width format so it looks like we're
1388 * erasing and redrawing the box.
1390 nsec = ((double)xdelta)*time_per_pixel;
1392 sprintf(tmpbuf, "%8.3f sec ", nsec/1e9);
1393 } else if (nsec > 1e6) {
1394 sprintf(tmpbuf, "%8.3f msec", nsec/1e6);
1395 } else if (nsec > 1e3) {
1396 sprintf(tmpbuf, "%8.3f usec", nsec/1e3);
1398 sprintf(tmpbuf, "%8.0f nsec", nsec);
1400 s_v1->last_time_interval = nsec;
1401 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1409 g_print("button:\ttype = %d\n", event->type);
1410 g_print("\twindow = 0x%x\n", event->window);
1411 g_print("\tsend_event = %d\n", event->send_event);
1412 g_print("\ttime = %d\n", event->time);
1413 g_print("\tx = %6.2f\n", event->x);
1414 g_print("\ty = %6.2f\n", event->y);
1415 g_print("\tpressure = %6.2f\n", event->pressure);
1416 g_print("\txtilt = %6.2f\n", event->xtilt);
1417 g_print("\tytilt = %6.2f\n", event->ytilt);
1418 g_print("\tstate = %d\n", event->state);
1419 g_print("\tbutton = %d\n", event->button);
1420 g_print("\tsource = %d\n", event->source);
1421 g_print("\tdeviceid = %d\n", event->deviceid);
1422 g_print("\tx_root = %6.2f\n", event->x_root);
1423 g_print("\ty_root = %6.2f\n", event->y_root);
1428 view1_display_when_idle();
1433 /****************************************************************************
1435 * Happens when the window manager resizes the viewer's main window.
1436 ****************************************************************************/
1439 configure_event (GtkWidget *widget, GdkEventConfigure *event)
1441 /* Toss the previous drawing area backing store pixmap */
1443 gdk_pixmap_unref(pm);
1445 /* Create a new pixmap, paint it */
1446 pm = gdk_pixmap_new(widget->window,
1447 widget->allocation.width,
1448 widget->allocation.height,
1450 gdk_draw_rectangle (pm,
1451 widget->style->white_gc,
1454 widget->allocation.width,
1455 widget->allocation.height);
1457 /* Reset the view geometry parameters, as required */
1458 s_v1->total_width = widget->allocation.width;
1459 s_v1->total_height = widget->allocation.height;
1460 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
1463 /* Schedule a repaint */
1464 view1_display_when_idle();
1468 /****************************************************************************
1470 * Use backing store to fix the screen.
1471 ****************************************************************************/
1472 static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1474 gdk_draw_pixmap(widget->window,
1475 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1477 event->area.x, event->area.y,
1478 event->area.x, event->area.y,
1479 event->area.width, event->area.height);
1484 /****************************************************************************
1485 * event_search_internal
1486 * This routine searches forward from s_srchindex, looking for s_srchcode;
1487 * wraps at the end of the buffer.
1488 ****************************************************************************/
1490 boolean event_search_internal (void)
1496 boolean full_redisplay = FALSE;
1497 ulonglong current_width;
1500 /* No events yet? Act like the search worked, to avoid a loop */
1504 ep = (g_events + s_srchindex);
1505 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1508 * Assume the user wants to search [plus or minus]
1509 * from where they are.
1512 if (ep->time < s_v1->minvistime)
1513 s_srchindex = find_event_index (s_v1->minvistime);
1516 for (i = 1; i <= g_nevents; i++) {
1517 index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ?
1518 (s_srchindex - i) % g_nevents :
1519 (i + s_srchindex) % g_nevents;
1521 ep = (g_events + index);
1523 if (ep->code == s_srchcode) {
1526 s_srchindex = index;
1527 pid_index = ep->pid->pid_index;
1529 /* Need a vertical scroll? */
1530 if ((pid_index < s_v1->first_pid_index) ||
1531 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1532 if (pid_index > (g_npids - s_v1->npids))
1533 pid_index = (g_npids - s_v1->npids);
1534 s_v1->first_pid_index = pid_index;
1535 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1536 (gdouble)s_v1->first_pid_index;
1537 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1538 full_redisplay = TRUE;
1541 /* Need a horizontal scroll? */
1542 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1543 current_width = (s_v1->maxvistime - s_v1->minvistime);
1544 if (ep->time < ((current_width+1) / 2)) {
1545 s_v1->minvistime = 0ll;
1546 s_v1->maxvistime = current_width;
1548 s_v1->minvistime = ep->time - ((current_width+1)/2);
1549 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1551 recompute_hscrollbar();
1552 full_redisplay = TRUE;
1554 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1555 full_redisplay = TRUE;
1558 if (!full_redisplay){
1561 time_per_pixel = dtime_per_pixel(s_v1);
1563 y = pid_index*s_v1->strip_height + s_v1->event_offset;
1564 x = s_v1->pid_ax_width +
1565 (int)(((double)(ep->time - s_v1->minvistime)) /
1567 sprintf(tmpbuf, "SEARCH RESULT");
1568 tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED);
1569 line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK);
1571 full_redisplay = TRUE;
1577 view1_display_when_idle();
1581 sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode);
1582 message_line(tmpbuf);
1583 s_srchfail_up = TRUE;
1587 /****************************************************************************
1588 * event_search_callback
1589 ****************************************************************************/
1591 boolean event_search_callback (char *s)
1593 /* No events yet? Act like the search worked, to avoid a loop */
1597 s_srchcode = atol(s);
1599 if (s_srchcode == 0)
1602 return(event_search_internal());
1605 /****************************************************************************
1607 ****************************************************************************/
1609 static void event_search (void)
1611 modal_dialog ("Event Search: Please Enter Event Code",
1612 "Invalid: Please Reenter Event Code", NULL,
1613 event_search_callback);
1616 /****************************************************************************
1618 ****************************************************************************/
1619 static void init_track_colors(void)
1625 gboolean dont_care[g_npids];
1628 * If we've already allocated the colors once, then in theory we should
1629 * just be able to re-order the GCs already created to match the new track
1630 * order; the track -> color mapping doesn't currently change at runtime.
1631 * However, it's easier just to allocate everything from fresh. As a nod in
1632 * the direction of politeness towards our poor abused X server, we at
1633 * least mop up the previously allocated GCs first, although in practice
1634 * even omitting this didn't seem to cause a problem.
1636 if (s_color != NULL ) {
1637 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
1639 memset(s_color, 0, sizeof(GdkColor) * g_npids);
1642 * First time through: allocate the array to hold the GCs.
1644 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
1648 * Go through and assign a color for each track.
1650 /* Setup entry 0 in the colormap as pure red (for selection) */
1651 s_color[0] = fg_red;
1653 for (i = 1; i < g_npids; i++) {
1655 * We compute the color from a hash of the thread name. That way we get
1656 * a distribution of different colors, and the same thread has the same
1657 * color across multiple data sets. Unfortunately, even though the
1658 * process name and thread id are invariant across data sets, the
1659 * process id isn't, so we want to exclude that from the hash. Since
1660 * the pid appears in parentheses after the process name and tid, we
1661 * can just stop at the '(' character.
1663 * We could create a substring and use the CLIB Jenkins hash, but given
1664 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1665 * just as good, and it's easiest just to compute it inline.
1667 label_char = get_track_label(g_pids[i].pid_value);
1669 while (*label_char != '\0' && *label_char != '(') {
1670 hash = hash * 33 + *label_char++;
1672 hash += hash >> 5; /* even out the lower order bits a touch */
1675 * OK, now we have our hash. We get the color by using the first three
1676 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1677 * and then use the fourth byte to choose one of R, G, B and mask this
1678 * one down. This ensures the color can't be too close to white and
1679 * therefore hard to see.
1681 * We also drop the top bit of the green, since bright green on its own
1682 * is hard to see against white. Generally we err on the side of
1683 * keeping it dark, rather than using the full spectrum of colors. This
1684 * does result in something of a preponderance of muddy colors and a
1685 * bit of a lack of cheery bright ones, but at least you can read
1686 * everything. It would be nice to do better.
1688 RGB[0] = (hash & 0xff000000) >> 16;
1689 RGB[1] = (hash & 0x007f0000) >> 8;
1690 RGB[2] = (hash & 0x0000ff00);
1691 RGB[hash % 3] &= 0x1fff;
1694 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1696 g_pids[i].color_index = i;
1701 * Actually allocate the colors in one bulk operation. We ignore the return
1704 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
1705 s_color, g_npids+1, FALSE, TRUE, dont_care);
1709 /****************************************************************************
1711 * Reorder the pid_index fields so the viewer "chases" the last selected
1713 ****************************************************************************/
1715 static void chase_event_etc(enum chase_mode mode)
1717 pid_sort_t *psp, *new_pidvec;
1721 ulong code_to_chase;
1722 ulong datum_to_chase;
1727 if (!s_last_selected_event) {
1728 infobox("No selected event",
1729 "\nPlease select an event and try again...\n");
1733 /* Clear all index assignments */
1735 for (i = 0; i < g_npids; i++) {
1737 pp->pid_index = 0xFFFFFFFF;
1741 ep = s_last_selected_event;
1742 code_to_chase = ep->code;
1743 datum_to_chase = ep->datum;
1744 pid_to_chase = ep->pid->pid_value;
1746 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
1749 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
1750 if (ep >= g_events + g_nevents)
1760 if (ep->code == code_to_chase) {
1766 if (ep->datum == datum_to_chase) {
1772 if (ep->pid->pid_value == pid_to_chase) {
1778 infobox("BUG", "unknown mode in chase_event_etc\n");
1783 if (ep->pid->pid_index == 0xFFFFFFFF) {
1784 ep->pid->pid_index = pids_mapped;
1785 new_pidvec[pids_mapped].pid = ep->pid;
1786 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
1787 new_pidvec[pids_mapped].color_index = 0;
1789 if (pids_mapped == g_npids)
1793 if (srch_chase_dir == SRCH_CHASE_FORWARD)
1799 /* Pass 2, first-to-last, to collect stragglers */
1802 while (ep < g_events + g_nevents) {
1803 if (ep->pid->pid_index == 0xFFFFFFFF) {
1804 ep->pid->pid_index = pids_mapped;
1805 new_pidvec[pids_mapped].pid = ep->pid;
1806 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
1807 new_pidvec[pids_mapped].color_index = 0;
1809 if (pids_mapped == g_npids)
1815 if (pids_mapped != g_npids) {
1816 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
1820 g_pids = new_pidvec;
1823 * The new g_pids vector contains the "chase" sort, so we revert
1824 * the pid_index mapping to an identity map
1828 for (i = 0; i < g_npids; i++) {
1834 /* AutoScroll the PID axis so we show the first "chased" event */
1835 s_v1->first_pid_index = 0;
1836 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
1837 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1838 init_track_colors();
1839 view1_display_when_idle();
1842 /****************************************************************************
1844 * Copy g_original_pids to g_pids, revert index mapping
1845 ****************************************************************************/
1846 static void unchase_event_etc(void)
1852 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
1854 /* Fix the pid structure index mappings */
1857 for (i = 0; i < g_npids; i++) {
1863 /* Scroll PID axis to the top */
1864 s_v1->first_pid_index = 0;
1865 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
1866 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1867 init_track_colors();
1868 view1_display_when_idle();
1871 /****************************************************************************
1873 * To fit a reasonable-sized landscape mode plot onto letter-size paper,
1874 * scale everything by .75.
1875 ****************************************************************************/
1877 static void print_ps_header (v1_geometry_t *vp, char *filename)
1883 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
1884 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
1885 fprintf(s_printfp, "%%%%Title: %s\n", filename);
1886 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
1887 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
1888 fprintf(s_printfp, "%%%%Origin: 0 0\n");
1889 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
1891 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
1892 fprintf(s_printfp, "%%%%Pages: 1\n");
1893 fprintf(s_printfp, "%%%%Page: 1 1\n");
1894 fprintf(s_printfp, "%%%%EOF\n");
1895 fprintf(s_printfp, "/Times-Roman findfont\n");
1896 fprintf(s_printfp, "12 scalefont\n");
1897 fprintf(s_printfp, "setfont\n");
1898 fprintf(s_printfp, ".75 .75 scale\n");
1901 /****************************************************************************
1903 * Xcoordinate rotate and translate. We need to emit postscript that
1904 * has a reasonable aspect ratio for printing. To do that, we rotate the
1905 * intended picture by 90 degrees, using the standard 2D rotation
1908 * Xr = x*cos(theta) - y*sin(theta);
1909 * Yr = x*sin(theta) + y*cos(theta);
1911 * If we let theta = 90, this reduces to
1915 * Translate back to the origin in X by adding Ymax, yielding
1917 ****************************************************************************/
1919 static inline int xrt(int x, int y)
1921 return (s_v1->total_height - y);
1924 static inline int yrt(int x, int y)
1929 /****************************************************************************
1930 * print_screen_callback
1931 ****************************************************************************/
1933 static boolean print_screen_callback(char *filename)
1935 s_printfp = fopen (filename, "wt");
1937 if (s_printfp == NULL)
1941 * This variable allows us to magically turn the view1 display
1942 * code into a print-driver, with a minimum of fuss. The idea is to
1943 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
1944 * the required value, aka s_print_offset.
1945 * Make sure to fix g2.h if you mess here, or vice versa.
1947 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
1949 print_ps_header(s_v1, filename);
1951 display_pid_axis(s_v1);
1952 display_event_data(s_v1);
1953 display_time_axis(s_v1);
1959 /* For tactile feedback */
1960 view1_display_when_idle();
1964 int event_time_cmp (const void *a, const void *b)
1966 const event_t *e1 = a;
1967 const event_t *e2 = b;
1969 if (e1->time < e2->time)
1971 else if (e1->time > e2->time)
1976 /****************************************************************************
1978 ****************************************************************************/
1979 static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
1986 delta = (ulonglong) (vp->last_time_interval);
1988 /* Make sure we don't push events to the left of the big bang */
1989 if (which == SLEW_LEFT_BUTTON) {
1990 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
1991 pid_index = ep->pid->pid_index;
1992 pp = (g_pids + pid_index);
1995 if (ep->time < delta) {
1996 infobox("Slew Range Error",
1997 "\nCan't slew selected data left that far..."
1998 "\nEvents would preceed the Big Bang (t=0)...");
2005 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2006 pid_index = ep->pid->pid_index;
2007 pp = (g_pids + pid_index);
2010 if (which == SLEW_LEFT_BUTTON)
2017 /* Re-sort the events, to avoid screwing up the event display */
2018 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2020 /* De-select tracks */
2024 view1_display_when_idle();
2027 /****************************************************************************
2028 * view1_button_click_callback
2029 ****************************************************************************/
2031 static void view1_button_click_callback(GtkButton *item, gpointer data)
2033 enum view1_button_click click = (enum view1_button_click) data;
2035 ulonglong event_incdec;
2036 ulonglong current_width;
2037 ulonglong zoom_delta;
2039 current_width = s_v1->maxvistime - s_v1->minvistime;
2040 event_incdec = (current_width) / 3;
2042 if (event_incdec == 0LL)
2045 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2049 /* First PID to top of window */
2050 s_v1->first_pid_index = 0;
2051 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2052 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2056 s_v1->first_pid_index = g_npids - s_v1->npids;
2057 if (s_v1->first_pid_index < 0)
2058 s_v1->first_pid_index = 0;
2059 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2060 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2075 case CHASE_EVENT_BUTTON:
2076 chase_event_etc(CHASE_EVENT);
2079 case CHASE_DATUM_BUTTON:
2080 chase_event_etc(CHASE_DATUM);
2083 case CHASE_TRACK_BUTTON:
2084 chase_event_etc(CHASE_TRACK);
2087 case UNCHASE_BUTTON:
2088 unchase_event_etc();
2093 s_v1->minvistime = 0LL;
2094 s_v1->maxvistime = current_width;
2095 recompute_hscrollbar();
2099 s_v1->minvistime += zoom_delta;
2100 s_v1->maxvistime -= zoom_delta;
2101 recompute_hscrollbar();
2104 case SEARCH_AGAIN_BUTTON:
2106 event_search_internal();
2109 /* NOTE FALLTHROUGH */
2115 case ZOOMOUT_BUTTON:
2116 if (zoom_delta == 0LL)
2119 if (s_v1->minvistime >= zoom_delta) {
2120 s_v1->minvistime -= zoom_delta;
2121 s_v1->maxvistime += zoom_delta;
2123 s_v1->minvistime = 0;
2124 s_v1->maxvistime += zoom_delta*2;
2127 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
2128 g_events[g_nevents-1].time * 9) {
2129 s_v1->minvistime = 0;
2130 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
2132 recompute_hscrollbar();
2136 ep = (g_events + g_nevents - 1);
2137 s_v1->maxvistime = ep->time + event_incdec/3;
2138 s_v1->minvistime = s_v1->maxvistime - current_width;
2139 if (s_v1->minvistime > s_v1->maxvistime)
2141 recompute_hscrollbar();
2144 case MORE_TRACES_BUTTON:
2145 /* Reduce the strip height to fit more traces on screen */
2146 s_v1->strip_height -= 1;
2148 if (s_v1->strip_height < 1) {
2149 s_v1->strip_height = 1;
2152 /* Recalculate the number of strips on the screen */
2153 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2155 recompute_vscrollbar();
2158 case LESS_TRACES_BUTTON:
2159 /* Increase the strip height to fit fewer on the screen */
2160 s_v1->strip_height += 1;
2161 if (s_v1->strip_height > 80) {
2162 s_v1->strip_height = 80;
2165 /* Recalculate the number of strips on the screen */
2166 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2168 recompute_vscrollbar();
2171 case FORWARD_BUTTON:
2172 srch_chase_dir = SRCH_CHASE_FORWARD;
2173 gtk_widget_hide (s_view1_forward_button);
2174 gtk_widget_show (s_view1_backward_button);
2177 case BACKWARD_BUTTON:
2178 srch_chase_dir = SRCH_CHASE_BACKWARD;
2179 gtk_widget_show (s_view1_forward_button);
2180 gtk_widget_hide (s_view1_backward_button);
2183 case SUMMARY_BUTTON:
2184 summary_mode = TRUE;
2185 gtk_widget_hide (s_view1_summary_button);
2186 gtk_widget_show (s_view1_nosummary_button);
2189 case NOSUMMARY_BUTTON:
2190 summary_mode = FALSE;
2191 gtk_widget_show (s_view1_summary_button);
2192 gtk_widget_hide (s_view1_nosummary_button);
2195 case SLEW_LEFT_BUTTON:
2196 case SLEW_RIGHT_BUTTON:
2197 if (s_v1->last_time_interval < 10e-9) {
2198 infobox("slew", "\nNo time interval set...\n");
2201 slew_tracks (s_v1, click);
2205 view1_display_when_idle();
2208 /****************************************************************************
2209 * view1_print_callback
2210 ****************************************************************************/
2212 void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2214 modal_dialog("Print Screen (PostScript format) to file:",
2215 "Invalid file: Print Screen to file:",
2216 "g2.ps", print_screen_callback);
2219 /****************************************************************************
2221 ****************************************************************************/
2223 static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2225 ulonglong current_width;
2227 current_width = (s_v1->maxvistime - s_v1->minvistime);
2229 s_v1->minvistime = (ulonglong)(adj->value);
2230 s_v1->maxvistime = s_v1->minvistime + current_width;
2232 view1_display_when_idle();
2235 g_print ("adj->lower = %.2f\n", adj->lower);
2236 g_print ("adj->upper = %.2f\n", adj->upper);
2237 g_print ("adj->value = %.2f\n", adj->value);
2238 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2239 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2240 g_print ("adj->page_size = %.2f\n", adj->page_size);
2244 /****************************************************************************
2246 ****************************************************************************/
2248 static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2250 s_v1->first_pid_index = (int)adj->value;
2251 view1_display_when_idle();
2254 void set_pid_ax_width(int width)
2256 s_v1->pid_ax_width = width;
2257 view1_display_when_idle();
2260 /****************************************************************************
2262 ****************************************************************************/
2264 void view1_init(void)
2267 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2268 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2270 s_v1->pid_ax_width = 80;
2271 s_v1->time_ax_height = 80;
2272 s_v1->time_ax_spacing = 100;
2273 s_v1->strip_height = 25;
2274 s_v1->pop_offset = 20;
2275 s_v1->pid_ax_offset = 34;
2276 s_v1->event_offset = 40;
2277 s_v1->total_height = c_view1_draw_height;
2278 s_v1->total_width = c_view1_draw_width;
2279 s_v1->first_pid_index = 0;
2281 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2284 s_v1->minvistime = 0;
2285 s_v1->maxvistime = 200;
2287 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2289 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2291 da = gtk_drawing_area_new();
2292 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2293 c_view1_draw_height);
2296 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2297 (GtkSignalFunc) motion_notify_event, NULL);
2300 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2301 (GtkSignalFunc) expose_event, NULL);
2303 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2304 (GtkSignalFunc) configure_event, NULL);
2306 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2307 (GtkSignalFunc) button_press_event, NULL);
2309 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2310 (GtkSignalFunc) button_press_event, NULL);
2312 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2313 (GtkSignalFunc) button_press_event, NULL);
2315 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2316 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2317 | GDK_BUTTON_MOTION_MASK);
2320 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2322 g_font = gdk_font_load ("8x13");
2323 if (g_font == NULL) {
2324 g_error("Couldn't load 8x13 font...\n");
2326 gdk_font_ref(g_font);
2329 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2331 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
2332 0.0 /* minimum value */,
2333 2000.0 /* maximum value */,
2334 0.1 /* step increment */,
2335 10.0/* page increment */,
2336 10.0/* page size */);
2338 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2340 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2341 GTK_SIGNAL_FUNC (view1_vscroll),
2342 (gpointer)s_view1_vscroll);
2344 s_view1_topbutton = gtk_button_new_with_label("Top");
2345 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2347 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2348 GTK_SIGNAL_FUNC(view1_button_click_callback),
2349 (gpointer) TOP_BUTTON);
2351 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2352 GTK_SIGNAL_FUNC(view1_button_click_callback),
2353 (gpointer) BOTTOM_BUTTON);
2355 /* More Traces button and Less Traces button */
2356 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2357 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2358 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
2359 GTK_SIGNAL_FUNC(view1_button_click_callback),
2360 (gpointer) MORE_TRACES_BUTTON);
2361 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
2362 GTK_SIGNAL_FUNC(view1_button_click_callback),
2363 (gpointer) LESS_TRACES_BUTTON);
2366 /* Trick to bottom-justify the menu: */
2367 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2368 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2373 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2376 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2379 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2382 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2385 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2388 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2391 /* Time axis menu */
2393 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2395 s_view1_startbutton = gtk_button_new_with_label("Start");
2397 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2399 s_view1_searchbutton = gtk_button_new_with_label("Search");
2401 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2403 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2405 s_view1_endbutton = gtk_button_new_with_label("End");
2407 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2408 GTK_SIGNAL_FUNC(view1_button_click_callback),
2409 (gpointer) START_BUTTON);
2411 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2412 GTK_SIGNAL_FUNC(view1_button_click_callback),
2413 (gpointer) ZOOMIN_BUTTON);
2415 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2416 GTK_SIGNAL_FUNC(view1_button_click_callback),
2417 (gpointer) SEARCH_BUTTON);
2419 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2420 GTK_SIGNAL_FUNC(view1_button_click_callback),
2421 (gpointer) SEARCH_AGAIN_BUTTON);
2423 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2424 GTK_SIGNAL_FUNC(view1_button_click_callback),
2425 (gpointer) ZOOMOUT_BUTTON);
2427 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2428 GTK_SIGNAL_FUNC(view1_button_click_callback),
2429 (gpointer) END_BUTTON);
2431 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
2432 0.0 /* minimum value */,
2433 2000.0 /* maximum value */,
2434 0.1 /* step increment */,
2435 10.0/* page increment */,
2436 10.0/* page size */);
2438 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2440 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2441 GTK_SIGNAL_FUNC (view1_hscroll),
2442 (gpointer)s_view1_hscroll);
2444 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2447 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2450 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2453 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2456 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2459 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2462 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2465 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2468 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2472 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2474 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2476 s_view1_nextbutton = gtk_button_new_with_label("Next");
2478 s_view1_delbutton = gtk_button_new_with_label("Del");
2480 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2482 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2484 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2486 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2488 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2489 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2491 s_view1_summary_button = gtk_button_new_with_label("Summary");
2492 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2494 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2495 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2497 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2498 GTK_SIGNAL_FUNC(view1_button_click_callback),
2499 (gpointer) SNAP_BUTTON);
2501 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2502 GTK_SIGNAL_FUNC(view1_button_click_callback),
2503 (gpointer) NEXT_BUTTON);
2505 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2506 GTK_SIGNAL_FUNC(view1_button_click_callback),
2507 (gpointer) DEL_BUTTON);
2509 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
2510 GTK_SIGNAL_FUNC(view1_button_click_callback),
2511 (gpointer) CHASE_EVENT_BUTTON);
2513 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
2514 GTK_SIGNAL_FUNC(view1_button_click_callback),
2515 (gpointer) CHASE_DATUM_BUTTON);
2517 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
2518 GTK_SIGNAL_FUNC(view1_button_click_callback),
2519 (gpointer) CHASE_TRACK_BUTTON);
2521 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2522 GTK_SIGNAL_FUNC(view1_button_click_callback),
2523 (gpointer) UNCHASE_BUTTON);
2525 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2526 GTK_SIGNAL_FUNC(view1_button_click_callback),
2527 (gpointer) FORWARD_BUTTON);
2529 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2530 GTK_SIGNAL_FUNC(view1_button_click_callback),
2531 (gpointer) BACKWARD_BUTTON);
2533 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2534 GTK_SIGNAL_FUNC(view1_button_click_callback),
2535 (gpointer) SUMMARY_BUTTON);
2537 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2538 GTK_SIGNAL_FUNC(view1_button_click_callback),
2539 (gpointer) NOSUMMARY_BUTTON);
2541 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
2542 GTK_SIGNAL_FUNC(view1_button_click_callback),
2543 (gpointer) SLEW_LEFT_BUTTON);
2545 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
2546 GTK_SIGNAL_FUNC(view1_button_click_callback),
2547 (gpointer) SLEW_RIGHT_BUTTON);
2549 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2552 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2555 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2558 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2561 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2564 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2567 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2570 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2573 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2576 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2579 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2582 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2585 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2586 s_view1_time_slew_left_button,
2589 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2590 s_view1_time_slew_right_button,
2593 s_view1_label = gtk_label_new(NULL);
2595 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2598 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2601 gtk_widget_show_all (s_view1_vbox);
2602 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2603 gtk_widget_grab_focus(da);
2605 gtk_widget_hide (s_view1_forward_button);
2606 gtk_widget_hide (summary_mode ? s_view1_summary_button
2607 : s_view1_nosummary_button);
2609 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2611 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2614 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2616 &bg_white, zi_x_hot,
2618 gdk_pixmap_unref (zi_source);
2619 gdk_pixmap_unref (zi_mask);
2621 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2624 /****************************************************************************
2626 ****************************************************************************/
2628 void line_print (int x1, int y1, int x2, int y2)
2630 fprintf(s_printfp, "newpath\n");
2631 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
2632 yrt(x1, s_v1->total_height - y1));
2634 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2635 yrt (x2, s_v1->total_height - y2));
2636 fprintf(s_printfp, "1 setlinewidth\n");
2637 fprintf(s_printfp, "stroke\n");
2640 /****************************************************************************
2642 ****************************************************************************/
2643 GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2646 if (function == TBOX_PRINT_BOXED) {
2650 if ((function == TBOX_PRINT_BOXED) ||
2651 (function == TBOX_PRINT_EVENT)) {
2653 fprintf(s_printfp, "newpath\n");
2654 fprintf(s_printfp, "0 setlinewidth\n");
2655 fprintf(s_printfp, "%d %d moveto\n",
2656 xrt(rp->x, s_v1->total_height - rp->y),
2657 yrt(rp->x, s_v1->total_height - rp->y));
2659 fprintf(s_printfp, "%d %d lineto\n",
2660 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
2661 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
2663 fprintf(s_printfp, "%d %d lineto\n",
2664 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
2665 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
2667 fprintf(s_printfp, "%d %d lineto\n",
2668 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
2669 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
2671 fprintf(s_printfp, "%d %d lineto\n",
2672 xrt(rp->x, s_v1->total_height - rp->y),
2673 yrt(rp->x, s_v1->total_height - rp->y));
2675 fprintf(s_printfp, "stroke\n");
2678 if ((function == TBOX_PRINT_BOXED) ||
2679 (function == TBOX_PRINT_PLAIN)) {
2681 fprintf(s_printfp, "newpath\n");
2682 fprintf(s_printfp, "%d %d moveto\n",
2683 xrt(x, s_v1->total_height - (y-2)),
2684 yrt(x, s_v1->total_height - (y-2)));
2685 fprintf(s_printfp, "gsave\n");
2686 fprintf(s_printfp, "90 rotate\n");
2687 fprintf(s_printfp, "(%s) show\n", s);
2688 fprintf(s_printfp, "grestore\n");
2694 /****************************************************************************
2695 * tbox - draws an optionally boxed string whose lower lefthand
2696 * corner is at (x, y). As usual, Y is backwards.
2697 ****************************************************************************/
2699 GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
2701 static GdkRectangle update_rect;
2702 gint lbearing, rbearing, width, ascent, descent;
2704 gdk_string_extents (g_font, s,
2705 &lbearing, &rbearing,
2706 &width, &ascent, &descent);
2709 * If we have enough room to display full size events, then just
2710 * use the BOXED function instead of the EVENT function.
2712 if (s_v1->strip_height > 9) {
2714 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
2715 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
2716 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
2724 case TBOX_DRAW_BOXED:
2725 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
2726 x, y - (ascent+descent+3), width + 2,
2727 ascent + descent + 3);
2729 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
2730 x, y - (ascent+descent+3), width + 2,
2731 ascent + descent + 3);
2733 gdk_draw_string (pm, g_font, da->style->black_gc,
2734 x + 1, y - 1, (const gchar *)s);
2735 /* NOTE FALLTHROUGH */
2736 case TBOX_GETRECT_BOXED:
2738 update_rect.y = y -(ascent+descent+3);
2739 update_rect.width = width + 3;
2740 update_rect.height = ascent + descent + 4;
2741 if (function == TBOX_DRAW_BOXED)
2742 gtk_widget_draw (da, &update_rect);
2745 case TBOX_DRAW_EVENT:
2746 /* We have a small event to draw...no text */
2747 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
2749 /* NOTE FALLTHROUGH */
2750 case TBOX_GETRECT_EVENT:
2752 update_rect.y = y - 1;
2753 update_rect.width = 4;
2754 update_rect.height = 4;
2755 if (function == TBOX_DRAW_EVENT)
2756 gtk_widget_draw (da, &update_rect);
2760 case TBOX_DRAW_PLAIN:
2762 gdk_draw_string (pm, g_font, da->style->black_gc,
2763 x + 1, y - 1, (const gchar *)s);
2764 /* NOTE FALLTHROUGH */
2765 case TBOX_GETRECT_PLAIN:
2767 update_rect.y = y -(ascent+descent+1);
2768 update_rect.width = width;
2769 update_rect.height = ascent + descent;
2770 if (function == TBOX_DRAW_PLAIN)
2771 gtk_widget_draw (da, &update_rect);
2774 case TBOX_PRINT_BOXED:
2776 update_rect.y = y -(ascent+descent+3);
2777 update_rect.width = width + 3;
2778 update_rect.height = ascent + descent + 4;
2779 /* note fallthrough */
2780 case TBOX_PRINT_PLAIN:
2781 return(tbox_print(s, x, y, function, &update_rect));
2783 case TBOX_PRINT_EVENT:
2784 /* We have a small event box to print...no text */
2786 update_rect.y = y - 1;
2787 update_rect.width = 4;
2788 update_rect.height = 4;
2789 return(tbox_print(s, x, y, function, &update_rect));
2791 return(&update_rect);
2794 /****************************************************************************
2797 * For lines there is a primitive batching facility, that doesn't update
2798 * the drawing area until the batch is complete. This is handy for drawing
2799 * the pid axis and for summary mode.
2801 * line_batch_mode contains the state for this:
2803 * BATCH_OFF: no batching, update for every line
2804 * BATCH_NEW: just entered a batch, so initialize the area to update from
2806 * BATCH_EXISTING: have drawn at least one line in batch mode, so the update
2807 * area should only be expanded from now on to include the
2808 * union of the "rectangular hull" of all lines
2809 ****************************************************************************/
2811 static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
2812 static int line_batch_count;
2813 static int line_minx, line_miny, line_maxx, line_maxy;
2815 void line_batch_start (void)
2817 line_batch_mode = BATCH_NEW;
2818 line_batch_count = 0;
2821 void line_batch_end (void)
2823 GdkRectangle update_rect;
2824 if (line_batch_count > 0) {
2825 update_rect.x = line_minx;
2826 update_rect.y = line_miny;
2827 update_rect.width = (line_maxx - line_minx) + 1;
2828 update_rect.height = (line_maxy - line_miny) + 1;
2829 gtk_widget_draw (da, &update_rect);
2831 line_batch_mode = BATCH_OFF;
2834 void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
2836 GdkRectangle update_rect;
2840 case LINE_DRAW_BLACK:
2841 gc = da->style->black_gc;
2844 case LINE_DRAW_WHITE:
2845 gc = da->style->white_gc;
2849 line_print (x1, y1, x2, y2);
2853 gdk_draw_line (pm, gc, x1, y1, x2, y2);
2855 switch (line_batch_mode) {
2859 update_rect.width = (x2-x1) + 1;
2860 update_rect.height = (y2-y1) + 1;
2861 gtk_widget_draw (da, &update_rect);
2869 line_batch_mode = BATCH_EXISTING;
2870 line_batch_count = 1;
2873 case BATCH_EXISTING:
2888 /****************************************************************************
2890 ****************************************************************************/
2892 static void display_pid_axis(v1_geometry_t *vp)
2894 int y, i, label_tick;
2895 int last_printed_y = -vp->strip_height;
2901 /* No pids yet? Outta here */
2907 for (i = 0; i < vp->npids; i++) {
2908 pid_index = vp->first_pid_index + i;
2909 if (pid_index >= g_npids)
2912 pp = (g_pids + pid_index);
2914 set_color(pid_index);
2916 label_fmt = get_track_label(pp->pid_value);
2917 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
2919 y = i*vp->strip_height + vp->pid_ax_offset;
2922 * Have we incremented enough space to have another label not
2923 * overlap the previous label?
2925 if (y - last_printed_y > 9) {
2927 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
2932 * And let the line stick out a bit more to indicate this label
2933 * relates to the following line.
2941 /* Draw axis line, but only if the lines aren't too close together */
2942 if (vp->strip_height > 4) {
2943 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
2944 vp->total_width, y+4*s_print_offset,
2945 LINE_DRAW_BLACK+s_print_offset);
2949 set_color(COLOR_DEFAULT);
2953 /****************************************************************************
2954 * view1_read_events_callback
2955 * New event data just showed up, reset a few things.
2956 ****************************************************************************/
2958 void view1_read_events_callback(void)
2962 s_v1->first_pid_index = 0;
2964 max_vis_index = 300;
2965 if (max_vis_index > g_nevents)
2966 max_vis_index = g_nevents-1;
2968 s_v1->minvistime = 0LL;
2969 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
2972 s_last_selected_event = 0;
2974 init_track_colors();
2976 recompute_hscrollbar();
2977 recompute_vscrollbar();
2980 /****************************************************************************
2981 * display_event_data
2982 ****************************************************************************/
2984 static void display_event_data(v1_geometry_t *vp)
2991 double time_per_pixel;
2993 GdkRectangle *print_rect;
2996 /* Happens if one loads the event def header first, for example. */
3000 time_per_pixel = dtime_per_pixel(vp);
3002 start_index = find_event_index (vp->minvistime);
3004 /* Scrolled too far right? */
3005 if (start_index >= g_nevents)
3008 ep = (g_events + start_index);
3010 if (s_print_offset || summary_mode) {
3011 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3018 while (ep < (g_events + g_nevents) &&
3019 (ep->time < vp->maxvistime)) {
3020 pid_index = ep->pid->pid_index;
3021 set_color(pid_index);
3023 /* First filter: pid out of range */
3024 if ((pid_index < vp->first_pid_index) ||
3025 (pid_index >= vp->first_pid_index + vp->npids)) {
3030 /* Second filter: event hidden */
3031 edp = find_event_definition (ep->code);
3032 if (!edp->selected) {
3039 pid_index -= vp->first_pid_index;
3041 y = pid_index*vp->strip_height + vp->event_offset;
3043 x = vp->pid_ax_width +
3044 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3046 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3051 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3052 if (ep->flags & EVENT_FLAG_SELECT) {
3053 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3055 sprintf(tmpbuf, edp->name);
3056 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3057 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3060 sprintf(tmpbuf, "SEARCH RESULT");
3062 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3063 TBOX_DRAW_BOXED+s_print_offset);
3064 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3065 if (last_x_used != NULL)
3066 last_x_used[pid_index] = x + print_rect->width;
3069 int delta = vp->strip_height / 3;
3072 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3073 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3074 last_x_used[pid_index] = x + 1;
3076 sprintf(tmpbuf, "%ld", ep->code);
3077 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3078 if (last_x_used != NULL)
3079 last_x_used[pid_index] = x + print_rect->width;
3085 g_free(last_x_used);
3087 set_color(COLOR_DEFAULT);
3090 /****************************************************************************
3092 ****************************************************************************/
3094 static void display_clear(void)
3096 GdkRectangle update_rect;
3098 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3099 0, 0, da->allocation.width,
3100 da->allocation.height);
3104 update_rect.width = da->allocation.width;
3105 update_rect.height = da->allocation.height;
3107 gtk_widget_draw (da, &update_rect);
3110 /****************************************************************************
3112 ****************************************************************************/
3114 static void display_time_axis(v1_geometry_t *vp)
3117 int xoffset, nticks;
3119 double unit_divisor;
3122 double time_per_pixel;
3124 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3126 x = vp->pid_ax_width;
3128 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3130 time_per_pixel = dtime_per_pixel(vp);
3133 unit_divisor = 1.00;
3135 if ((vp->maxvistime / unit_divisor) > 1000) {
3137 unit_divisor = 1000.00;
3140 if ((vp->maxvistime / unit_divisor) > 1000) {
3142 unit_divisor = 1000.00*1000.00;
3144 if ((vp->maxvistime / unit_divisor) > 1000) {
3146 unit_divisor = 1000.00*1000.00*1000.00;
3150 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3154 for (i = 0; i < nticks; i++) {
3156 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3158 time = (double)(x + xoffset - vp->pid_ax_width);
3159 time *= time_per_pixel;
3160 time += (double)(vp->minvistime);
3161 time /= unit_divisor;
3163 sprintf (tmpbuf, "%.2f%s", time, units);
3165 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3167 xoffset += vp->time_ax_spacing;
3171 /****************************************************************************
3173 * Forget about any temporary displays, they're gone now...
3174 ****************************************************************************/
3176 static void clear_scoreboard(void)
3178 s_result_up = FALSE;
3181 /****************************************************************************
3183 ****************************************************************************/
3185 void view1_display(void)
3188 display_pid_axis(s_v1);
3189 display_event_data(s_v1);
3190 display_time_axis(s_v1);
3194 static gint idle_tag;
3196 /****************************************************************************
3197 * view1_display_eventually
3198 ****************************************************************************/
3200 static void view1_display_eventually(void)
3202 gtk_idle_remove(idle_tag);
3208 /****************************************************************************
3209 * view1_display_when_idle
3210 ****************************************************************************/
3212 void view1_display_when_idle(void)
3214 if (idle_tag == 0) {
3215 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3219 /****************************************************************************
3221 ****************************************************************************/
3223 void view1_about (char *tmpbuf)
3228 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3229 s_v1->minvistime, s_v1->maxvistime);
3230 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
3231 s_v1->strip_height);
3233 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3236 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);