blob: c5f799dc0bca0a24658a1b50a2aadc551f705399 [file] [log] [blame]
Dave Barach52642c32016-02-11 19:28:19 -05001/*
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <errno.h>
20#include <gtk/gtk.h>
21#include <gdk/gdkkeysyms.h>
22#include "g2.h"
23#include <time.h>
24#include <string.h>
25#include <vppinfra/format.h>
26#include <vppinfra/elog.h>
27
28/*
29 * The main event display view.
30 *
31 * Important variables:
32 *
33 * "da" -- the drawing area, aka the screen representation of the
34 * event view.
35 *
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.
40 *
41 * "s_v1" -- pointer to the current v1_geometry_t object.
42 *
43 * Box heirarchy:
44 * s_view1_vbox
45 * s_view1_hbox
46 * da s_view1_vmenubox
47 * s_view1_topbutton("Top")
48 * s_view1_vscroll (vertical scrollbar)
49 * s_view1_bottombutton("Bottom")
50 * s_view1_hmenubox
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")
58 * s_view1_label
59 */
60
61/*
62 * Globals
63 */
64
65GdkFont *g_font; /* a fixed-width font to use */
Dave Barach2c35e582017-04-03 10:22:17 -040066/* color format: 0 (for static colors), r (0-64k), g (0-64k), b (0-64k) */
Dave Barach52642c32016-02-11 19:28:19 -050067GdkColor fg_black = {0, 0, 0, 0};
Dave Barach2c35e582017-04-03 10:22:17 -040068GdkColor fg_red = {0, 65535, 0, 0};
Dave Barach52642c32016-02-11 19:28:19 -050069GdkColor bg_white = {0, 65535, 65535, 65535};
70static boolean summary_mode = TRUE; /* start out in summary mode */
Dave Barach2c35e582017-04-03 10:22:17 -040071static boolean color_mode = FALSE; /* start out in monochrome mode */
Dave Barach52642c32016-02-11 19:28:19 -050072
73/*
74 * Locals
75 */
76
77/*
78 * user_data values passed to view1_button_click_callback,
79 * which is used by the various action buttons noted above
80 */
81enum view1_button_click {
82 TOP_BUTTON=1,
83 BOTTOM_BUTTON,
84 START_BUTTON,
85 ZOOMIN_BUTTON,
86 SEARCH_BUTTON,
87 SEARCH_AGAIN_BUTTON,
88 ZOOMOUT_BUTTON,
89 END_BUTTON,
90 MORE_TRACES_BUTTON,
91 LESS_TRACES_BUTTON,
92 SNAP_BUTTON,
93 NEXT_BUTTON,
94 DEL_BUTTON,
95 CHASE_EVENT_BUTTON,
96 CHASE_DATUM_BUTTON,
97 CHASE_TRACK_BUTTON,
98 UNCHASE_BUTTON,
99 FORWARD_BUTTON,
100 BACKWARD_BUTTON,
101 SUMMARY_BUTTON,
102 NOSUMMARY_BUTTON,
Dave Barach2c35e582017-04-03 10:22:17 -0400103 SLEW_LEFT_BUTTON,
104 SLEW_RIGHT_BUTTON,
Dave Barach52642c32016-02-11 19:28:19 -0500105};
106
107enum chase_mode {
108 CHASE_EVENT=1,
109 CHASE_DATUM,
110 CHASE_TRACK,
111};
112
113enum sc_dir {
114 SRCH_CHASE_FORWARD = 0,
115 SRCH_CHASE_BACKWARD = 1,
116};
117
118static GtkWidget *s_view1_hbox; /* see box heirarchy chart */
119static GtkWidget *s_view1_vbox; /* see box heirarchy chart */
120static GtkWidget *da; /* main drawing area */
121static GdkPixmap *pm; /* and its backing pixmap */
122static GdkCursor *norm_cursor; /* the "normal" cursor */
123
124/*
125 * view geometry parameters
126 *
127 * Remember:
128 * Y increases down the page.
129 * Strip origin is at the top
130 * Payday is Friday
131 * Don't put your fingers in your mouth.
132 *
133 * Most of these values are in pixels
134 */
135
136typedef 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 */
Dave Barach2c35e582017-04-03 10:22:17 -0400146 double last_time_interval; /* last time interval, in f64 seconds */
Dave Barach52642c32016-02-11 19:28:19 -0500147
148 /* Derived values */
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 */
153} v1_geometry_t;
154
155
156/* The active geometry object */
157static v1_geometry_t s_v1record;
158static v1_geometry_t *s_v1 = &s_v1record;
159
160/* The color array */
161static GdkColor *s_color;
162
163/* Snapshot ring */
164typedef struct snapshot {
165 struct snapshot *next;
166 /* Screen geometry */
167 v1_geometry_t geometry;
168 boolean show_event[NEVENTS];
169 pid_sort_t *pidvec;
170 /*
171 * Note: not worth recomputing the vertical scrollbar, just save
172 * its value here
173 */
174 gfloat vscroll_value;
175 boolean summary_mode;
176 boolean color_mode;
177} snapshot_t;
178
179static snapshot_t *s_snapshots;
180static snapshot_t *s_cursnap;
181static event_t *s_last_selected_event;
182
183/*
184 * various widgets, see the box heirarchy chart above
185 * The toolkit keeps track of these things, we could lose many of
186 * these pointers.
187 */
188static GtkWidget *s_view1_vmenubox;
189static GtkWidget *s_view1_topbutton;
190static GtkWidget *s_view1_bottombutton;
191static GtkWidget *s_view1_more_traces_button;
192static GtkWidget *s_view1_less_traces_button;
193
194static GtkWidget *s_view1_hmenubox;
195static GtkWidget *s_view1_hmenubox2;
196static GtkWidget *s_view1_startbutton;
197static GtkWidget *s_view1_zoominbutton;
198static GtkWidget *s_view1_searchbutton;
199static GtkWidget *s_view1_srchagainbutton;
200static GtkWidget *s_view1_zoomoutbutton;
201static GtkWidget *s_view1_endbutton;
202
203static GtkWidget *s_view1_snapbutton;
204static GtkWidget *s_view1_nextbutton;
205static GtkWidget *s_view1_delbutton;
206
207static GtkWidget *s_view1_chase_event_button;
208static GtkWidget *s_view1_chase_datum_button;
209static GtkWidget *s_view1_chase_track_button;
210static GtkWidget *s_view1_unchasebutton;
211
212static GtkWidget *s_view1_forward_button;
213static GtkWidget *s_view1_backward_button;
214
215static GtkWidget *s_view1_summary_button;
216static GtkWidget *s_view1_nosummary_button;
217
Dave Barach2c35e582017-04-03 10:22:17 -0400218static GtkWidget *s_view1_time_slew_right_button;
219static GtkWidget *s_view1_time_slew_left_button;
220
Dave Barach52642c32016-02-11 19:28:19 -0500221static GtkWidget *s_view1_hscroll;
222static GtkObject *s_view1_hsadj;
223
224static GtkWidget *s_view1_vscroll;
225static GtkObject *s_view1_vsadj;
226
227static GtkWidget *s_view1_label;
228
229/*
230 * Search context
231 */
232static ulong s_srchcode; /* search event code */
233static int s_srchindex; /* last hit was at this event index */
234static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */
235static boolean s_srchfail_up; /* The status line "Search Failed" is up */
236static int srch_chase_dir; /* search/chase dir, 0=>forward */
237
238
239/*
240 * Print context
241 */
242static int s_print_offset; /* Magic offset added to line, tbox fn codes */
243static FILE *s_printfp;
244
245/*
246 * Forward reference prototypes
247 */
248static void display_pid_axis(v1_geometry_t *vp);
249static void display_event_data(v1_geometry_t *vp);
250static void display_time_axis(v1_geometry_t *vp);
251static void view1_button_click_callback(GtkButton *item, gpointer data);
252
253/*
254 * config params
255 */
256
257gint c_view1_draw_width;
258gint c_view1_draw_height;
259
260/*
261 * Zoom-In / Time Ruler cursor
262 */
263
264#define zi_width 32
265#define zi_height 32
266#define zi_x_hot 22
267#define zi_y_hot 14
268static 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};
280
281static 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};
293
294static GdkCursor *zi_cursor;
295static GdkPixmap *zi_source, *zi_mask;
296
297/*
298 * Frequently-used small computations, best
299 * done correctly once and instantiated.
300 */
301
302/****************************************************************************
303* dtime_per_pixel
304****************************************************************************/
305
306static inline double dtime_per_pixel(v1_geometry_t *vp)
307{
308 return ((double)(vp->maxvistime - vp->minvistime)) /
309 ((double)(vp->total_width - vp->pid_ax_width));
310}
311
312/****************************************************************************
313* message_line
314* Changes the status line. Pass "" to clear the status line.
315****************************************************************************/
316
317void message_line (char *s)
318{
319 gtk_label_set_text (GTK_LABEL(s_view1_label), s);
320}
321
322/****************************************************************************
323* set_window_title
324* Changes the window title to include the specified filename.
325****************************************************************************/
326
327void set_window_title (const char *filename)
328{
329 char title[128];
330 snprintf(title, sizeof(title), "g2 (%s)", filename);
331 gtk_window_set_title(GTK_WINDOW(g_mainwindow), title);
332}
333
334/****************************************************************************
335* recompute_hscrollbar
336* Adjust the horizontal scrollbar's adjustment object.
337*
338* GtkAdjustments are really cool, but have to be set up exactly
339* right or the various client objects screw up completely.
340*
341* Note: this function is *not* called when the user clicks the scrollbar.
342****************************************************************************/
343
344static void recompute_hscrollbar (void)
345{
346 ulonglong current_width;
347 ulonglong event_incdec;
348 GtkAdjustment *adj;
349 event_t *ep;
350
351 if (g_nevents == 0)
352 return;
353
354 ep = (g_events + (g_nevents-1));
355 current_width = s_v1->maxvistime - s_v1->minvistime;
356 event_incdec = (current_width) / 6;
357
358 adj = GTK_ADJUSTMENT(s_view1_hsadj);
359
360 /*
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
369 */
370
371 adj->lower = (gfloat)0.00;
372 adj->value = (gfloat)s_v1->minvistime;
373
374 /* Minor click: move about 1/6 of a page */
375 adj->step_increment = (gfloat)event_incdec;
376
377 /* Major click: move about 1/3 of a page. */
378 adj->page_increment = (gfloat)(2*event_incdec);
379
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);
383
384 /*
385 * Tell all clients (e.g. the visible scrollbar) to
386 * make themselves look right
387 */
388 gtk_adjustment_changed(adj);
389 gtk_adjustment_value_changed(adj);
390}
391
392/****************************************************************************
393* recompute_vscrollbar
394* Ditto, for the vertical scrollbar
395****************************************************************************/
396
397static void recompute_vscrollbar (void)
398{
399 GtkAdjustment *adj;
400
401 adj = GTK_ADJUSTMENT(s_view1_vsadj);
402
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);
411}
412
413/****************************************************************************
414* format_popbox_string
415****************************************************************************/
416
417elog_main_t elog_main;
418
419void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp)
420{
421 char *fp;
422
423#ifdef NOTDEF
424 sprintf(tmpbuf,"%d:", ep->code);
425#endif
426 if (ep->flags & EVENT_FLAG_CLIB) {
427 elog_event_t *eep;
428 u8 *s;
429
430 eep = get_clib_event (ep->datum);
431
432 s = format (0, "%U", format_elog_event, &elog_main, eep);
433 memcpy (tmpbuf, s, vec_len(s));
434 tmpbuf[vec_len(s)] = 0;
435 vec_free(s);
436 return;
437 }
438
439 snprintf(tmpbuf, len, "%s", edp->name);
440 fp = edp->format;
441 /* Make sure there's a real format string. If so, add it */
442 while (fp && *fp) {
443 if (*fp != ' ') {
444 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
445 /* %s only supported for cpel files */
446 if (fp[1] == 's') {
447 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
448 edp->format, strtab_ref(ep->datum));
449 } else {
450 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
451 edp->format, ep->datum);
452 }
453 return;
454 }
455 fp++;
456 }
457}
458
459/****************************************************************************
460 * add_snapshot
461 ****************************************************************************/
462
463static void add_snapshot(void)
464{
465 int i;
466 snapshot_t *new = g_malloc(sizeof(snapshot_t));
467
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;
471 }
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;
477
478 if (s_snapshots) {
479 new->next = s_snapshots;
480 s_snapshots = new;
481 } else {
482 new->next = 0;
483 s_snapshots = new;
484 }
485 s_cursnap = new;
486}
487
488/****************************************************************************
489 * next_snapshot
490 ****************************************************************************/
491
492static void next_snapshot(void)
493{
494 snapshot_t *next;
495 int i;
496 pid_sort_t *psp;
497 pid_data_t *pp;
498
499 if (!s_snapshots) {
500 infobox("No snapshots", "\nNo snapshots in the ring...\n");
501 return;
502 }
503
504 next = s_cursnap->next;
505 if (next == 0)
506 next = s_snapshots;
507
508 s_cursnap = next;
509
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];
513 }
514 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
515 color_mode = next->color_mode;
516 /*
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.)
520 */
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));
525 }
526
527 /* Fix the pid structure index mappings */
528 psp = g_pids;
529
530 for (i = 0; i < g_npids; i++) {
531 pp = psp->pid;
532 pp->pid_index = i;
533 psp++;
534 }
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();
540}
541
542
543/****************************************************************************
544 * del_snapshot
545 ****************************************************************************/
546
547static void del_snapshot(void)
548{
549 snapshot_t *prev;
550 snapshot_t *this;
551
552 if (!s_snapshots) {
553 infobox("No snapshots", "\nNo snapshots to delete...\n");
554 return;
555 }
556
557 prev = NULL;
558 this = s_snapshots;
559
560 while (this && this != s_cursnap) {
561 prev = this;
562 this = this->next;
563 }
564
565 if (this != s_cursnap) {
566 infobox("BUG", "\nSnapshot AWOL!\n");
567 return;
568 }
569
570 s_cursnap = this->next;
571
572 /* middle of the list? */
573 if (prev) {
574 prev->next = this->next;
575 g_free(this->pidvec);
576 g_free(this);
577 } else { /* start of the list */
578 s_snapshots = this->next;
579 g_free(this->pidvec);
580 g_free(this);
581 }
582
583 /* Note: both will be NULL after last delete */
584 if (s_cursnap == NULL)
585 s_cursnap = s_snapshots;
586}
587
588/****************************************************************************
589 * write_snapshot
590 *
591 * VERY primitive right now - not endian or version independent, and only
592 * writes to "snapshots.g2" in the current directory
593 ****************************************************************************/
594static void write_snapshot(void)
595{
596 FILE *file = NULL;
597 snapshot_t *snap;
598 char *error = NULL;
599 int records = 0;
600
601 if (s_snapshots == NULL) {
602 error = "No snapshots defined";
603 errno = 0;
604 }
605
606 if (!error) {
607 file = fopen("snapshots.g2", "w");
608 if (file == NULL) {
609 error = "Unable to open snapshots.g2";
610 }
611 }
612
613 /*
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.
616 */
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 ||
622 fwrite(snap->pidvec,
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";
631 }
632 records++;
633 }
634
635 if (!error) {
636 if (fclose(file)) {
637 error = "Unable to close file";
638 }
639 }
640
641 if (error) {
642 infobox(error, strerror(errno));
643 } else {
644 char buf[64];
645 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
646 records);
647 message_line(buf);
648 }
649}
650
651/****************************************************************************
652 * read_snapshot
653 *
654 * VERY primitive right now - not endian or version independent, and only reads
655 * from "snapshots.g2" in the current directory
656 ****************************************************************************/
657static void read_snapshot(void)
658{
659 FILE *file;
660 snapshot_t *snap, *next_snap;
661 snapshot_t *new_snaps = NULL;
662 char *error = NULL;
663 int len, i, records = 0;
664 pid_data_t *pp;
665
666 file = fopen("snapshots.g2", "r");
667 if (file == NULL) {
668 error = "Unable to open snapshots.g2";
669 }
670
671 /*
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.
675 */
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 */
679
680 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
681 if (len == 0) {
682 /* EOF */
683 g_free(snap);
684 break;
685 } else {
686 /* insert into list straight away */
687 snap->next = new_snaps;
688 new_snaps = snap;
689 }
690 if (len != 1) {
691 error = "Problem reading first item from file";
692 break;
693 }
694 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
695 error = "Problem reading second item from file";
696 break;
697 }
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";
702 break;
703 }
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";
711 break;
712 }
713
714 /*
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.
719 */
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) {
723 break;
724 }
725 }
726 if (pp != NULL) {
727 snap->pidvec[i].pid = pp;
728 } else {
729 error = "Snapshot file referenced unknown pids";
730 break;
731 }
732 }
733
734 records++;
735 }
736
737 if (!error) {
738 if (fclose(file)) {
739 error = "Unable to close file";
740 }
741 }
742
743 if (error) {
744 /*
745 * Problem - clear up any detritus
746 */
747 infobox(error, strerror(errno));
748 for (snap = new_snaps; snap != NULL; snap = next_snap) {
749 next_snap = snap->next;
750 g_free(snap);
751 g_free(snap->pidvec);
752 }
753 } else {
754 /*
755 * Success! trash the old snapshots and replace with the new
756 */
757 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
758 next_snap = snap->next;
759 g_free(snap->pidvec);
760 g_free(snap);
761 }
762
763 s_cursnap = s_snapshots = new_snaps;
764 }
765
766 if (error) {
767 infobox(error, strerror(errno));
768 } else {
769 char buf[64];
770 snprintf(buf, sizeof(buf),
771 "Read %d snapshots from snapshots.g2", records);
772 message_line(buf);
773 }
774}
775
776/****************************************************************************
777* set_color
778*
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)
783static void set_color(int pid_index)
784{
Dave Barach2c35e582017-04-03 10:22:17 -0400785 pid_sort_t *psp;
786
787 psp = (g_pids + pid_index);
788
789 if (psp->selected)
790 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
791 else if (pid_index == COLOR_DEFAULT || !color_mode) {
Dave Barach52642c32016-02-11 19:28:19 -0500792 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
793 } else {
794 gdk_gc_set_foreground(da->style->black_gc,
795 &s_color[g_pids[pid_index].color_index]);
796 }
797}
798
799/****************************************************************************
800* toggle_event_select
801****************************************************************************/
802
Dave Barach2c35e582017-04-03 10:22:17 -0400803static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
Dave Barach52642c32016-02-11 19:28:19 -0500804{
805 int pid_index, start_index;
806 int x, y;
807 GdkRectangle *rp;
808 GdkRectangle hit_rect;
809 GdkRectangle dummy;
810 event_t *ep;
811 event_def_t *edp;
812 char tmpbuf [1024];
813 double time_per_pixel;
814
815 if (g_nevents == 0)
Dave Barach2c35e582017-04-03 10:22:17 -0400816 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500817
818 time_per_pixel = dtime_per_pixel(vp);
819
820 start_index = find_event_index (vp->minvistime);
821
822 /* Too far right? */
823 if (start_index >= g_nevents)
Dave Barach2c35e582017-04-03 10:22:17 -0400824 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500825
826 /*
827 * To see if the mouse hit a visible event, use a variant
828 * of the event display loop.
829 */
830
831 hit_rect.x = (int)event->x;
832 hit_rect.y = (int)event->y;
833 hit_rect.width = 1;
834 hit_rect.height = 1;
835
836 ep = (g_events + start_index);
837
838 while ((ep->time < vp->maxvistime) &&
839 (ep < (g_events + g_nevents))) {
840 pid_index = ep->pid->pid_index;
841
842 /* First filter: pid out of range */
843 if ((pid_index < vp->first_pid_index) ||
844 (pid_index >= vp->first_pid_index + vp->npids)) {
845 ep++;
846 continue;
847 }
848
849 /* Second filter: event hidden */
850 edp = find_event_definition (ep->code);
851 if (!edp->selected) {
852 ep++;
853 continue;
854 }
855
856 /*
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
859 */
860
861 /*
862 * $$$$ maybe keep looping until off the edge,
863 * maintain a "best hit", then declare that one the winner?
864 */
865
866 pid_index -= vp->first_pid_index;
867
868 y = pid_index*vp->strip_height + vp->event_offset;
869
870 x = vp->pid_ax_width +
871 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
872
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();
Dave Barach2c35e582017-04-03 10:22:17 -0400881 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500882 }
883 }
884
885 sprintf(tmpbuf, "%ld", ep->code);
886
887 /* Figure out the dimensions of the regular box */
888 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
889
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();
Dave Barach2c35e582017-04-03 10:22:17 -0400895 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500896 } else {
897 set_color(ep->pid->pid_index);
898
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;
906 }
Dave Barach2c35e582017-04-03 10:22:17 -0400907 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500908 }
909 ep++;
910 }
Dave Barach2c35e582017-04-03 10:22:17 -0400911 return -1;
Dave Barach52642c32016-02-11 19:28:19 -0500912}
913
914/****************************************************************************
Dave Barach2c35e582017-04-03 10:22:17 -0400915* toggle_track_select
916****************************************************************************/
917
918static void toggle_track_select (GdkEventButton *event,
919 v1_geometry_t *vp)
920{
921 int i;
922 int pid_index;
923 int y, delta_y;
924 pid_sort_t *psp;
925
926 if (g_nevents == 0)
927 return;
928
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;
933 if (delta_y < 0)
934 delta_y = -delta_y;
935 if (delta_y < 10) {
936 goto found;
937 }
938
939 }
940 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
941 return;
942
943 found:
944 pid_index = i + vp->first_pid_index;
945 psp = (g_pids + pid_index);
946 psp->selected ^= 1;
947 view1_display_when_idle();
948}
949
950/****************************************************************************
951* deselect_tracks
952****************************************************************************/
953static void deselect_tracks (void)
954{
955 int i;
956
957 for (i = 0; i < g_npids; i++)
958 g_pids[i].selected = 0;
959
960}
961
962
963/****************************************************************************
Dave Barach52642c32016-02-11 19:28:19 -0500964* move_current_track
965****************************************************************************/
966
967typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
968
969static void move_current_track(GdkEventButton *event,
970 v1_geometry_t *vp,
971 move_type type)
972{
973 int i;
974 int pid_index;
975 int y, delta_y;
976 pid_sort_t *new_pidvec;
977 pid_sort_t *psp;
978 pid_sort_t *pold, *pnew;
979 pid_data_t *pp;
980
981 if (g_nevents == 0)
982 return;
983
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;
988 if (delta_y < 0)
989 delta_y = -delta_y;
990 if (delta_y < 10) {
991 goto found;
992 }
993
994 }
995 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
996 return;
997
998 found:
999 pid_index = i + vp->first_pid_index;
1000
Dave Baracha8ed6bd2017-04-04 08:00:23 -04001001 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001002 pold = g_pids;
1003 pnew = new_pidvec;
1004
1005 if (type == MOVE_TOP) {
1006 /* move to top */
1007 *pnew++ = g_pids[pid_index];
1008 for (i = 0; i < pid_index; i++)
1009 *pnew++ = *pold++;
1010 pold++;
1011 i++;
1012 for (; i < g_npids; i++)
1013 *pnew++ = *pold++;
1014 } else {
1015 /* move to bottom */
1016 for (i = 0; i < pid_index; i++)
1017 *pnew++ = *pold++;
1018 pold++;
1019 i++;
1020 for (; i < g_npids; i++)
1021 *pnew++ = *pold++;
1022 *pnew = g_pids[pid_index];
1023 }
1024
1025 g_free(g_pids);
1026 g_pids = new_pidvec;
1027
1028 /*
1029 * Revert the pid_index mapping to an identity map,
1030 */
1031 psp = g_pids;
1032
1033 for (i = 0; i < g_npids; i++) {
1034 pp = psp->pid;
1035 pp->pid_index = i;
1036 psp++;
1037 }
1038 view1_display_when_idle();
1039}
1040
1041/****************************************************************************
1042* zoom_event
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****************************************************************************/
1047
1048void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1049{
1050 double xrange;
1051 double time_per_pixel;
1052 double width_in_pixels;
1053 double center_on_time, width_in_time;
1054 double center_on_pixel;
1055
1056 /*
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
1060 */
1061
1062 if (e1->x < vp->pid_ax_width)
1063 e1->x = vp->pid_ax_width;
1064
1065 if (e2->x < vp->pid_ax_width)
1066 e2->x = vp->pid_ax_width;
1067
1068 if (e2->x == e1->x)
1069 goto loser_zoom_repaint;
1070
1071 xrange = (double) (e2->x - e1->x);
1072 if (xrange < 0.00)
1073 xrange = -xrange;
1074
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;
1079
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;
1084
1085 /*
1086 * Transform back to 64-bit integer microseconds, reset the
1087 * scrollbar, schedule a repaint.
1088 */
1089 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1090 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1091
1092loser_zoom_repaint:
1093 recompute_hscrollbar();
1094
1095 view1_display_when_idle();
1096}
1097
1098/****************************************************************************
1099* scroll_y
1100*
1101* Scroll up or down by the specified delta
1102*
1103****************************************************************************/
1104static void scroll_y(int delta)
1105{
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;
1109 if (new_index < 0)
1110 new_index = 0;
1111
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();
1117 }
1118}
1119
1120/****************************************************************************
1121* view1_handle_key_press_event
1122* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1123*
1124* This routine implements hotkeys for the Quake generation:
1125*
1126* W - zoom in
1127* S - zoom out
1128* A - pan left
1129* D - pan right
1130* R - pan up
1131* F - pan down
1132* T - more traces
1133* G - fewer traces
1134*
1135* E - toggle summary mode
1136* C - toggle color mode
1137*
1138* X - take snapshot
1139* Z - next snapshot
1140* P - persist snapshots to file
1141* L - load snapshots from file
1142*
1143* ctrl-Q - exit
1144*
1145****************************************************************************/
1146gint
1147view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1148{
1149 long long delta;
1150
1151 switch (event->keyval) {
1152 case GDK_w: // zoom in
1153 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1154 break;
1155
1156 case GDK_s: // zoom out
1157 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1158 break;
1159
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;
1164 }
1165 s_v1->minvistime -= delta;
1166 s_v1->maxvistime -= delta;
1167 recompute_hscrollbar();
1168 break;
1169
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) {
1173 /*
1174 * @@@ this doesn't seem to quite reach the far right hand
1175 * side correctly - not sure why.
1176 */
1177 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1178 }
1179 s_v1->minvistime += delta;
1180 s_v1->maxvistime += delta;
1181 recompute_hscrollbar();
1182 break;
1183
1184 case GDK_r: // pan up
1185 scroll_y(-1);
1186 break;
1187
1188 case GDK_f: // pan down
1189 scroll_y(+1);
1190 break;
1191
1192 case GDK_t: // fewer tracks
1193 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1194 break;
1195
1196 case GDK_g: // more tracks
1197 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1198 break;
1199
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));
1204 break;
1205
1206 case GDK_c: // toggle color mode
1207 color_mode ^= 1;
1208 view1_display_when_idle();
1209 break;
1210
1211 case GDK_p: // persist snapshots
1212 write_snapshot();
1213 break;
1214
1215 case GDK_l: // load snapshots
1216 read_snapshot();
1217 break;
1218
1219 case GDK_x: // take snapshot
1220 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1221 break;
1222
1223 case GDK_z: // next snapshot
1224 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1225 break;
1226
1227 case GDK_q: // ctrl-q is exit
1228 if (event->state & GDK_CONTROL_MASK) {
1229 gtk_main_quit();
1230 }
1231 break;
1232 }
1233 return TRUE;
1234}
1235
1236/****************************************************************************
1237* button_press_event
1238* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1239*
1240* This routine implements three functions: zoom-to-area, time ruler, and
1241* show/hide event detail popup.
1242*
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
1246* an area zoom.
1247*
1248* The right mouse button (button 3) implements the time ruler.
1249****************************************************************************/
1250
1251static gint
1252button_press_event (GtkWidget *widget, GdkEventButton *event)
1253{
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;
1261 char tmpbuf [128];
1262 double time_per_pixel;
1263
1264 time_ax_y = 0;
1265
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;
1272 return(TRUE);
1273 }
1274 if (event->button == 3) {
1275 press3_valid = TRUE;
1276 press3_event = *event;
1277 return(TRUE);
1278 }
1279 return(TRUE);
1280
1281 case GDK_BUTTON_RELEASE:
1282 /* Time ruler */
1283 if (press3_valid) {
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();
1288 return(TRUE);
1289 }
1290 /* Event select / zoom-to-area */
1291 if (press1_valid) {
1292 press1_valid = FALSE;
1293 xdelta = (int)(press1_event.x - event->x);
1294 if (xdelta < 0)
1295 xdelta = -xdelta;
1296
1297 /* is the mouse more or less where it started? */
1298 if (xdelta < 10) {
1299 /* Control-left-mouse => sink the track */
1300 /* Shift-left-mouse => raise the track */
1301 if ((press1_event.state & GDK_CONTROL_MASK) ==
1302 GDK_CONTROL_MASK) {
1303 move_current_track(event, s_v1, MOVE_BOTTOM);
1304 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1305 GDK_SHIFT_MASK) {
1306 move_current_track(event, s_v1, MOVE_TOP);
1307 } else {
Dave Barach2c35e582017-04-03 10:22:17 -04001308 /* No modifiers: toggle the event / select track */
1309 if (toggle_event_select(event, s_v1))
1310 toggle_track_select(event, s_v1);
Dave Barach52642c32016-02-11 19:28:19 -05001311 }
1312 /* Repaint to get rid of the zoom bar */
1313 if (zoom_bar_up) {
1314 /* Fix the cursor and leave. No zoom */
1315 gdk_window_set_cursor (da->window, norm_cursor);
1316 zoom_bar_up = FALSE;
1317 break;
1318 }
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;
1323 }
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);
1330 }
1331 return(TRUE);
1332
1333 case GDK_MOTION_NOTIFY:
1334 /* Button one followed by motion: draw zoom fence and fix cursor */
1335 if (press1_valid) {
1336 /* Fence, cursor already set */
1337 if (zoom_bar_up)
1338 return(TRUE);
1339
1340 xdelta = (int)(press1_event.x - event->x);
1341 if (xdelta < 0)
1342 xdelta = -xdelta;
1343
1344 /* Haven't moved enough to declare a zoom sequence yet */
1345 if (xdelta < 10)
1346 return(TRUE);
1347
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;
1350
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,
1354 TBOX_DRAW_BOXED);
1355 gdk_window_set_cursor(da->window, zi_cursor);
1356 zoom_bar_up = TRUE;
1357 return(TRUE);
1358 }
1359 if (press3_valid) {
1360 double nsec;
1361
1362 gdk_window_set_cursor(da->window, zi_cursor);
1363
1364 /*
1365 * Some filtration is needed on Solaris, or the server will hang
1366 */
1367 if (event->time - last_truler_time < 75)
1368 return(TRUE);
1369
1370 last_truler_time = event->time;
1371
1372 line((int)(press3_event.x), s_v1->pop_offset,
1373 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1374
1375 xdelta = (int)(press3_event.x - event->x);
1376 if (xdelta < 0)
1377 xdelta = -xdelta;
1378
1379 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1380 ((double)(s_v1->total_width - s_v1->pid_ax_width));
1381
1382 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1383
1384 line((int)(press3_event.x), s_v1->pop_offset,
1385 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1386 /*
1387 * Note: use a fixed-width format so it looks like we're
1388 * erasing and redrawing the box.
1389 */
1390 nsec = ((double)xdelta)*time_per_pixel;
1391 if (nsec >1e9) {
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);
1397 } else {
1398 sprintf(tmpbuf, "%8.0f nsec", nsec);
1399 }
Dave Barach2c35e582017-04-03 10:22:17 -04001400 s_v1->last_time_interval = nsec;
Dave Barach52642c32016-02-11 19:28:19 -05001401 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1402 TBOX_DRAW_BOXED);
1403 return(TRUE);
1404 }
1405
1406 default:
1407 break;
1408#ifdef DEBUG
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);
1424 return(TRUE);
1425#endif
1426 }
1427
1428 view1_display_when_idle();
1429
1430 return(TRUE);
1431}
1432
1433/****************************************************************************
1434* configure_event
1435* Happens when the window manager resizes the viewer's main window.
1436****************************************************************************/
1437
1438static gint
1439configure_event (GtkWidget *widget, GdkEventConfigure *event)
1440{
1441 /* Toss the previous drawing area backing store pixmap */
1442 if (pm)
1443 gdk_pixmap_unref(pm);
1444
1445 /* Create a new pixmap, paint it */
1446 pm = gdk_pixmap_new(widget->window,
1447 widget->allocation.width,
1448 widget->allocation.height,
1449 -1);
1450 gdk_draw_rectangle (pm,
1451 widget->style->white_gc,
1452 TRUE,
1453 0, 0,
1454 widget->allocation.width,
1455 widget->allocation.height);
1456
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) /
1461 s_v1->strip_height;
1462
1463 /* Schedule a repaint */
1464 view1_display_when_idle();
1465 return(TRUE);
1466}
1467
1468/****************************************************************************
1469* expose_event
1470* Use backing store to fix the screen.
1471****************************************************************************/
1472static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1473{
1474 gdk_draw_pixmap(widget->window,
1475 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1476 pm,
1477 event->area.x, event->area.y,
1478 event->area.x, event->area.y,
1479 event->area.width, event->area.height);
1480
1481 return(FALSE);
1482}
1483
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****************************************************************************/
1489
1490boolean event_search_internal (void)
1491{
1492 event_t *ep;
1493 int i;
1494 int index;
1495 int pid_index;
1496 boolean full_redisplay = FALSE;
1497 ulonglong current_width;
1498 char tmpbuf [64];
1499
1500 /* No events yet? Act like the search worked, to avoid a loop */
1501 if (g_nevents == 0)
1502 return(TRUE);
1503
1504 ep = (g_events + s_srchindex);
1505 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1506
1507 /*
1508 * Assume the user wants to search [plus or minus]
1509 * from where they are.
1510 */
1511#ifdef notdef
1512 if (ep->time < s_v1->minvistime)
1513 s_srchindex = find_event_index (s_v1->minvistime);
1514#endif
1515
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;
1520
1521 ep = (g_events + index);
1522
1523 if (ep->code == s_srchcode) {
1524 if (s_srchfail_up)
1525 message_line("");
1526 s_srchindex = index;
1527 pid_index = ep->pid->pid_index;
1528
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;
1539 }
1540
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;
1547 } else {
1548 s_v1->minvistime = ep->time - ((current_width+1)/2);
1549 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1550 }
1551 recompute_hscrollbar();
1552 full_redisplay = TRUE;
1553 }
1554 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1555 full_redisplay = TRUE;
1556
1557#ifdef NOTDEF
1558 if (!full_redisplay){
1559 if (!s_result_up) {
1560 s_result_up = TRUE;
1561 time_per_pixel = dtime_per_pixel(s_v1);
1562
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)) /
1566 time_per_pixel);
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);
1570 } else {
1571 full_redisplay = TRUE;
1572 }
1573 }
1574#endif
1575
1576 if (full_redisplay)
1577 view1_display_when_idle();
1578 return(TRUE);
1579 }
1580 }
1581 sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode);
1582 message_line(tmpbuf);
1583 s_srchfail_up = TRUE;
1584 return(TRUE);
1585}
1586
1587/****************************************************************************
1588* event_search_callback
1589****************************************************************************/
1590
1591boolean event_search_callback (char *s)
1592{
1593 /* No events yet? Act like the search worked, to avoid a loop */
1594 if (g_nevents == 0)
1595 return(TRUE);
1596
1597 s_srchcode = atol(s);
1598
1599 if (s_srchcode == 0)
1600 return(FALSE);
1601
1602 return(event_search_internal());
1603}
1604
1605/****************************************************************************
1606* event_search
1607****************************************************************************/
1608
1609static void event_search (void)
1610{
1611 modal_dialog ("Event Search: Please Enter Event Code",
1612 "Invalid: Please Reenter Event Code", NULL,
1613 event_search_callback);
1614}
1615
1616/****************************************************************************
1617* init_track_colors
1618****************************************************************************/
1619static void init_track_colors(void)
1620{
1621 int i;
1622 unsigned hash;
1623 char *label_char;
1624 unsigned RGB[3];
1625 gboolean dont_care[g_npids];
1626
1627 /*
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.
1635 */
1636 if (s_color != NULL ) {
1637 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
1638 s_color, g_npids);
1639 memset(s_color, 0, sizeof(GdkColor) * g_npids);
1640 } else {
1641 /*
1642 * First time through: allocate the array to hold the GCs.
1643 */
Dave Barach2c35e582017-04-03 10:22:17 -04001644 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
Dave Barach52642c32016-02-11 19:28:19 -05001645 }
1646
1647 /*
1648 * Go through and assign a color for each track.
1649 */
Dave Barach2c35e582017-04-03 10:22:17 -04001650 /* Setup entry 0 in the colormap as pure red (for selection) */
1651 s_color[0] = fg_red;
1652
1653 for (i = 1; i < g_npids; i++) {
Dave Barach52642c32016-02-11 19:28:19 -05001654 /*
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.
1662 *
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.
1666 */
1667 label_char = get_track_label(g_pids[i].pid_value);
1668 hash = 0;
1669 while (*label_char != '\0' && *label_char != '(') {
1670 hash = hash * 33 + *label_char++;
1671 }
1672 hash += hash >> 5; /* even out the lower order bits a touch */
1673
1674 /*
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.
1680 *
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.
1687 */
1688 RGB[0] = (hash & 0xff000000) >> 16;
1689 RGB[1] = (hash & 0x007f0000) >> 8;
1690 RGB[2] = (hash & 0x0000ff00);
1691 RGB[hash % 3] &= 0x1fff;
1692
1693 {
1694 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1695 s_color[i] = color;
1696 g_pids[i].color_index = i;
1697 }
1698 }
1699
1700 /*
1701 * Actually allocate the colors in one bulk operation. We ignore the return
1702 * values.
1703 */
1704 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
Dave Barach2c35e582017-04-03 10:22:17 -04001705 s_color, g_npids+1, FALSE, TRUE, dont_care);
Dave Barach52642c32016-02-11 19:28:19 -05001706}
1707
1708
1709/****************************************************************************
1710* chase_event_etc
1711* Reorder the pid_index fields so the viewer "chases" the last selected
1712* event.
1713****************************************************************************/
1714
1715static void chase_event_etc(enum chase_mode mode)
1716{
1717 pid_sort_t *psp, *new_pidvec;
1718 pid_data_t *pp;
1719 event_t *ep;
1720 int pids_mapped;
1721 ulong code_to_chase;
1722 ulong datum_to_chase;
1723 ulong pid_to_chase;
1724 int i;
1725 int winner;
1726
1727 if (!s_last_selected_event) {
1728 infobox("No selected event",
1729 "\nPlease select an event and try again...\n");
1730 return;
1731 }
1732
1733 /* Clear all index assignments */
1734 psp = g_pids;
1735 for (i = 0; i < g_npids; i++) {
1736 pp = psp->pid;
1737 pp->pid_index = 0xFFFFFFFF;
1738 psp++;
1739 }
1740
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;
1745 pids_mapped = 0;
Dave Baracha8ed6bd2017-04-04 08:00:23 -04001746 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001747
1748 while (1) {
1749 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
1750 if (ep >= g_events + g_nevents)
1751 break;
1752 } else {
1753 if (ep < g_events)
1754 break;
1755 }
1756
1757 winner = 0;
1758 switch(mode) {
1759 case CHASE_EVENT:
1760 if (ep->code == code_to_chase) {
1761 winner = 1;
1762 }
1763 break;
1764
1765 case CHASE_DATUM:
1766 if (ep->datum == datum_to_chase) {
1767 winner = 1;
1768 }
1769 break;
1770
1771 case CHASE_TRACK:
1772 if (ep->pid->pid_value == pid_to_chase) {
1773 winner = 1;
1774 }
1775 break;
1776
1777 default:
1778 infobox("BUG", "unknown mode in chase_event_etc\n");
1779 break;
1780 }
1781
1782 if (winner) {
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;
1788 pids_mapped++;
1789 if (pids_mapped == g_npids)
1790 break;
1791 }
1792 }
1793 if (srch_chase_dir == SRCH_CHASE_FORWARD)
1794 ep++;
1795 else
1796 ep--;
1797 }
1798
1799 /* Pass 2, first-to-last, to collect stragglers */
1800 ep = g_events;
1801
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;
1808 pids_mapped++;
1809 if (pids_mapped == g_npids)
1810 break;
1811 }
1812 ep++;
1813 }
1814
1815 if (pids_mapped != g_npids) {
1816 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
1817 }
1818
1819 g_free (g_pids);
1820 g_pids = new_pidvec;
1821
1822 /*
1823 * The new g_pids vector contains the "chase" sort, so we revert
1824 * the pid_index mapping to an identity map
1825 */
1826 psp = g_pids;
1827
1828 for (i = 0; i < g_npids; i++) {
1829 pp = psp->pid;
1830 pp->pid_index = i;
1831 psp++;
1832 }
1833
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();
1840}
1841
1842/****************************************************************************
1843* unchase_event_etc
1844* Copy g_original_pids to g_pids, revert index mapping
1845****************************************************************************/
1846static void unchase_event_etc(void)
1847{
1848 int i;
1849 pid_sort_t *psp;
1850 pid_data_t *pp;
1851
1852 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
1853
1854 /* Fix the pid structure index mappings */
1855 psp = g_pids;
1856
1857 for (i = 0; i < g_npids; i++) {
1858 pp = psp->pid;
1859 pp->pid_index = i;
1860 psp++;
1861 }
1862
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();
1869}
1870
1871/****************************************************************************
1872* print_ps_header
1873* To fit a reasonable-sized landscape mode plot onto letter-size paper,
1874* scale everything by .75.
1875****************************************************************************/
1876
1877static void print_ps_header (v1_geometry_t *vp, char *filename)
1878{
1879 time_t now;
1880
1881 now = time(0);
1882
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,
1890 vp->total_width);
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");
1899}
1900
1901/****************************************************************************
1902* xrt
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
1906* formula:
1907*
1908* Xr = x*cos(theta) - y*sin(theta);
1909* Yr = x*sin(theta) + y*cos(theta);
1910*
1911* If we let theta = 90, this reduces to
1912* Xr = -y
1913* Yr = x
1914*
1915* Translate back to the origin in X by adding Ymax, yielding
1916* Xrt = Ymax - y
1917****************************************************************************/
1918
1919static inline int xrt(int x, int y)
1920{
1921 return (s_v1->total_height - y);
1922}
1923
1924static inline int yrt(int x, int y)
1925{
1926 return(x);
1927}
1928
1929/****************************************************************************
1930* print_screen_callback
1931****************************************************************************/
1932
1933static boolean print_screen_callback(char *filename)
1934{
1935 s_printfp = fopen (filename, "wt");
1936
1937 if (s_printfp == NULL)
1938 return(FALSE);
1939
1940 /*
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.
1946 */
1947 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
1948
1949 print_ps_header(s_v1, filename);
1950
1951 display_pid_axis(s_v1);
1952 display_event_data(s_v1);
1953 display_time_axis(s_v1);
1954
1955 fclose (s_printfp);
1956 s_printfp = 0;
1957 s_print_offset = 0;
1958
1959 /* For tactile feedback */
1960 view1_display_when_idle();
1961 return(TRUE);
1962}
1963
Dave Barach2c35e582017-04-03 10:22:17 -04001964int event_time_cmp (const void *a, const void *b)
1965{
1966 const event_t *e1 = a;
1967 const event_t *e2 = b;
1968
1969 if (e1->time < e2->time)
1970 return -1;
1971 else if (e1->time > e2->time)
1972 return 1;
1973 return 0;
1974}
1975
1976/****************************************************************************
1977* slew_tracks
1978****************************************************************************/
1979static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
1980{
1981 event_t *ep;
1982 pid_sort_t *pp;
1983 int pid_index;
1984 ulonglong delta;
1985
1986 delta = (ulonglong) (vp->last_time_interval);
1987
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);
1993
1994 if (pp->selected) {
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)...");
1999 goto out;
2000 }
2001 }
2002 }
2003 }
2004
2005 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2006 pid_index = ep->pid->pid_index;
2007 pp = (g_pids + pid_index);
2008
2009 if (pp->selected) {
2010 if (which == SLEW_LEFT_BUTTON)
2011 ep->time -= delta;
2012 else
2013 ep->time += delta;
2014 }
2015 }
2016
2017 /* Re-sort the events, to avoid screwing up the event display */
2018 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2019
2020 /* De-select tracks */
2021 deselect_tracks();
2022
2023out:
2024 view1_display_when_idle();
2025}
2026
Dave Barach52642c32016-02-11 19:28:19 -05002027/****************************************************************************
2028* view1_button_click_callback
2029****************************************************************************/
2030
2031static void view1_button_click_callback(GtkButton *item, gpointer data)
2032{
2033 enum view1_button_click click = (enum view1_button_click) data;
2034 event_t *ep;
2035 ulonglong event_incdec;
2036 ulonglong current_width;
2037 ulonglong zoom_delta;
2038
Dave Barach52642c32016-02-11 19:28:19 -05002039 current_width = s_v1->maxvistime - s_v1->minvistime;
2040 event_incdec = (current_width) / 3;
2041
2042 if (event_incdec == 0LL)
2043 event_incdec = 1;
2044
2045 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2046
2047 switch(click) {
2048 case TOP_BUTTON:
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));
2053 break;
2054
2055 case BOTTOM_BUTTON:
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));
2061 break;
2062
2063 case SNAP_BUTTON:
2064 add_snapshot();
2065 break;
2066
2067 case NEXT_BUTTON:
2068 next_snapshot();
2069 break;
2070
2071 case DEL_BUTTON:
2072 del_snapshot();
2073 break;
2074
2075 case CHASE_EVENT_BUTTON:
2076 chase_event_etc(CHASE_EVENT);
2077 break;
2078
2079 case CHASE_DATUM_BUTTON:
2080 chase_event_etc(CHASE_DATUM);
2081 break;
2082
2083 case CHASE_TRACK_BUTTON:
2084 chase_event_etc(CHASE_TRACK);
2085 break;
2086
2087 case UNCHASE_BUTTON:
2088 unchase_event_etc();
2089 break;
2090
2091 case START_BUTTON:
2092 start_button:
2093 s_v1->minvistime = 0LL;
2094 s_v1->maxvistime = current_width;
2095 recompute_hscrollbar();
2096 break;
2097
2098 case ZOOMIN_BUTTON:
2099 s_v1->minvistime += zoom_delta;
2100 s_v1->maxvistime -= zoom_delta;
2101 recompute_hscrollbar();
2102 break;
2103
2104 case SEARCH_AGAIN_BUTTON:
2105 if (s_srchcode) {
2106 event_search_internal();
2107 break;
2108 }
2109 /* NOTE FALLTHROUGH */
2110
2111 case SEARCH_BUTTON:
2112 event_search();
2113 break;
2114
2115 case ZOOMOUT_BUTTON:
2116 if (zoom_delta == 0LL)
2117 zoom_delta = 1;
2118
2119 if (s_v1->minvistime >= zoom_delta) {
2120 s_v1->minvistime -= zoom_delta;
2121 s_v1->maxvistime += zoom_delta;
2122 } else {
2123 s_v1->minvistime = 0;
2124 s_v1->maxvistime += zoom_delta*2;
2125 }
2126
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;
2131 }
2132 recompute_hscrollbar();
2133 break;
2134
2135 case END_BUTTON:
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)
2140 goto start_button;
2141 recompute_hscrollbar();
2142 break;
2143
2144 case MORE_TRACES_BUTTON:
2145 /* Reduce the strip height to fit more traces on screen */
2146 s_v1->strip_height -= 1;
2147
2148 if (s_v1->strip_height < 1) {
2149 s_v1->strip_height = 1;
2150 }
2151
2152 /* Recalculate the number of strips on the screen */
2153 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2154 s_v1->strip_height;
2155 recompute_vscrollbar();
2156 break;
2157
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;
2163 }
2164
2165 /* Recalculate the number of strips on the screen */
2166 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2167 s_v1->strip_height;
2168 recompute_vscrollbar();
2169 break;
2170
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);
2175 break;
2176
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);
2181 break;
2182
2183 case SUMMARY_BUTTON:
2184 summary_mode = TRUE;
2185 gtk_widget_hide (s_view1_summary_button);
2186 gtk_widget_show (s_view1_nosummary_button);
2187 break;
2188
2189 case NOSUMMARY_BUTTON:
2190 summary_mode = FALSE;
2191 gtk_widget_show (s_view1_summary_button);
2192 gtk_widget_hide (s_view1_nosummary_button);
2193 break;
Dave Barach2c35e582017-04-03 10:22:17 -04002194
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");
2199 break;
2200 }
2201 slew_tracks (s_v1, click);
2202 break;
Dave Barach52642c32016-02-11 19:28:19 -05002203 }
2204
2205 view1_display_when_idle();
2206}
2207
2208/****************************************************************************
2209* view1_print_callback
2210****************************************************************************/
2211
2212void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2213{
2214 modal_dialog("Print Screen (PostScript format) to file:",
2215 "Invalid file: Print Screen to file:",
2216 "g2.ps", print_screen_callback);
2217}
2218
2219/****************************************************************************
2220* view1_hscroll
2221****************************************************************************/
2222
2223static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2224{
2225 ulonglong current_width;
2226
2227 current_width = (s_v1->maxvistime - s_v1->minvistime);
2228
2229 s_v1->minvistime = (ulonglong)(adj->value);
2230 s_v1->maxvistime = s_v1->minvistime + current_width;
2231
2232 view1_display_when_idle();
2233
2234#ifdef NOTDEF
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);
2241#endif
2242}
2243
2244/****************************************************************************
2245* view1_vscroll
2246****************************************************************************/
2247
2248static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2249{
2250 s_v1->first_pid_index = (int)adj->value;
2251 view1_display_when_idle();
2252}
2253
2254void set_pid_ax_width(int width)
2255{
2256 s_v1->pid_ax_width = width;
2257 view1_display_when_idle();
2258}
2259
2260/****************************************************************************
2261* view1_init
2262****************************************************************************/
2263
2264void view1_init(void)
2265{
2266
2267 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2268 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2269
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;
2280
2281 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2282 s_v1->strip_height;
2283
2284 s_v1->minvistime = 0;
2285 s_v1->maxvistime = 200;
2286
2287 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2288
2289 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2290
2291 da = gtk_drawing_area_new();
2292 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2293 c_view1_draw_height);
2294
2295#ifdef NOTDEF
2296 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2297 (GtkSignalFunc) motion_notify_event, NULL);
2298#endif
2299
2300 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2301 (GtkSignalFunc) expose_event, NULL);
2302
2303 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2304 (GtkSignalFunc) configure_event, NULL);
2305
2306 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2307 (GtkSignalFunc) button_press_event, NULL);
2308
2309 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2310 (GtkSignalFunc) button_press_event, NULL);
2311
2312 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2313 (GtkSignalFunc) button_press_event, NULL);
2314
2315 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2316 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2317 | GDK_BUTTON_MOTION_MASK);
2318
2319
2320 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2321
2322 g_font = gdk_font_load ("8x13");
2323 if (g_font == NULL) {
2324 g_error("Couldn't load 8x13 font...\n");
2325 }
2326 gdk_font_ref(g_font);
2327
2328 /* PID axis menu */
2329 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2330
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 */);
2337
2338 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2339
2340 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2341 GTK_SIGNAL_FUNC (view1_vscroll),
2342 (gpointer)s_view1_vscroll);
2343
2344 s_view1_topbutton = gtk_button_new_with_label("Top");
2345 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2346
2347 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2348 GTK_SIGNAL_FUNC(view1_button_click_callback),
2349 (gpointer) TOP_BUTTON);
2350
2351 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2352 GTK_SIGNAL_FUNC(view1_button_click_callback),
2353 (gpointer) BOTTOM_BUTTON);
2354
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);
2364
2365#ifdef NOTDEF
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,
2369 TRUE, FALSE, 0);
2370
2371#endif
2372
2373 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2374 FALSE, FALSE, 0);
2375
2376 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2377 TRUE, TRUE, 0);
2378
2379 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2380 FALSE, FALSE, 0);
2381
2382 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2383 FALSE, FALSE, 0);
2384
2385 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2386 FALSE, FALSE, 0);
2387
2388 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2389 FALSE, FALSE, 0);
2390
2391 /* Time axis menu */
2392
2393 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2394
2395 s_view1_startbutton = gtk_button_new_with_label("Start");
2396
2397 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2398
2399 s_view1_searchbutton = gtk_button_new_with_label("Search");
2400
2401 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2402
2403 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2404
2405 s_view1_endbutton = gtk_button_new_with_label("End");
2406
2407 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2408 GTK_SIGNAL_FUNC(view1_button_click_callback),
2409 (gpointer) START_BUTTON);
2410
2411 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2412 GTK_SIGNAL_FUNC(view1_button_click_callback),
2413 (gpointer) ZOOMIN_BUTTON);
2414
2415 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2416 GTK_SIGNAL_FUNC(view1_button_click_callback),
2417 (gpointer) SEARCH_BUTTON);
2418
2419 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2420 GTK_SIGNAL_FUNC(view1_button_click_callback),
2421 (gpointer) SEARCH_AGAIN_BUTTON);
2422
2423 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2424 GTK_SIGNAL_FUNC(view1_button_click_callback),
2425 (gpointer) ZOOMOUT_BUTTON);
2426
2427 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2428 GTK_SIGNAL_FUNC(view1_button_click_callback),
2429 (gpointer) END_BUTTON);
2430
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 */);
2437
2438 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2439
2440 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2441 GTK_SIGNAL_FUNC (view1_hscroll),
2442 (gpointer)s_view1_hscroll);
2443
2444 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2445 FALSE, FALSE, 0);
2446
2447 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2448 TRUE, TRUE, 0);
2449
2450 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2451 FALSE, FALSE, 0);
2452
2453 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2454 FALSE, FALSE, 0);
2455
2456 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2457 FALSE, FALSE, 0);
2458
2459 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2460 FALSE, FALSE, 0);
2461
2462 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2463 FALSE, FALSE, 0);
2464
2465 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2466 TRUE, TRUE, 0);
2467
2468 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2469 FALSE, FALSE, 0);
2470
2471
2472 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2473
2474 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2475
2476 s_view1_nextbutton = gtk_button_new_with_label("Next");
2477
2478 s_view1_delbutton = gtk_button_new_with_label("Del");
2479
2480 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2481
2482 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2483
2484 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2485
2486 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2487
2488 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2489 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2490
2491 s_view1_summary_button = gtk_button_new_with_label("Summary");
2492 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2493
Dave Barach2c35e582017-04-03 10:22:17 -04002494 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->");
2496
Dave Barach52642c32016-02-11 19:28:19 -05002497 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2498 GTK_SIGNAL_FUNC(view1_button_click_callback),
2499 (gpointer) SNAP_BUTTON);
2500
2501 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2502 GTK_SIGNAL_FUNC(view1_button_click_callback),
2503 (gpointer) NEXT_BUTTON);
2504
2505 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2506 GTK_SIGNAL_FUNC(view1_button_click_callback),
2507 (gpointer) DEL_BUTTON);
2508
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);
2512
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);
2516
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);
2520
2521 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2522 GTK_SIGNAL_FUNC(view1_button_click_callback),
2523 (gpointer) UNCHASE_BUTTON);
2524
2525 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2526 GTK_SIGNAL_FUNC(view1_button_click_callback),
2527 (gpointer) FORWARD_BUTTON);
2528
2529 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2530 GTK_SIGNAL_FUNC(view1_button_click_callback),
2531 (gpointer) BACKWARD_BUTTON);
2532
2533 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2534 GTK_SIGNAL_FUNC(view1_button_click_callback),
2535 (gpointer) SUMMARY_BUTTON);
2536
2537 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2538 GTK_SIGNAL_FUNC(view1_button_click_callback),
2539 (gpointer) NOSUMMARY_BUTTON);
2540
Dave Barach2c35e582017-04-03 10:22:17 -04002541 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);
2544
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);
2548
Dave Barach52642c32016-02-11 19:28:19 -05002549 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2550 FALSE, FALSE, 0);
2551
2552 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2553 FALSE, FALSE, 0);
2554
2555 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2556 FALSE, FALSE, 0);
2557
2558 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2559 FALSE, FALSE, 0);
2560
2561 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2562 FALSE, FALSE, 0);
2563
2564 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2565 FALSE, FALSE, 0);
2566
2567 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2568 FALSE, FALSE, 0);
2569
2570 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2571 FALSE, FALSE, 0);
2572
2573 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2574 FALSE, FALSE, 0);
2575
2576 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2577 FALSE, FALSE, 0);
2578
2579 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2580 FALSE, FALSE, 0);
2581
2582 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2583 FALSE, FALSE, 0);
2584
Dave Barach2c35e582017-04-03 10:22:17 -04002585 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2586 s_view1_time_slew_left_button,
2587 FALSE, FALSE, 0);
2588
2589 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2590 s_view1_time_slew_right_button,
2591 FALSE, FALSE, 0);
2592
Dave Barach52642c32016-02-11 19:28:19 -05002593 s_view1_label = gtk_label_new(NULL);
2594
2595 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2596 FALSE, FALSE, 0);
2597
2598 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2599 TRUE, TRUE, 0);
2600
2601 gtk_widget_show_all (s_view1_vbox);
2602 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2603 gtk_widget_grab_focus(da);
2604
2605 gtk_widget_hide (s_view1_forward_button);
2606 gtk_widget_hide (summary_mode ? s_view1_summary_button
2607 : s_view1_nosummary_button);
2608
2609 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2610 zi_height);
2611 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2612 zi_height);
2613
2614 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2615 zi_mask, &fg_black,
2616 &bg_white, zi_x_hot,
2617 zi_y_hot);
2618 gdk_pixmap_unref (zi_source);
2619 gdk_pixmap_unref (zi_mask);
2620
2621 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2622}
2623
2624/****************************************************************************
2625* line_print
2626****************************************************************************/
2627
2628void line_print (int x1, int y1, int x2, int y2)
2629{
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));
2633
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");
2638}
2639
2640/****************************************************************************
2641* tbox_print
2642****************************************************************************/
2643GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2644 GdkRectangle *rp)
2645{
2646 if (function == TBOX_PRINT_BOXED) {
2647 rp->width -= 4;
2648 }
2649
2650 if ((function == TBOX_PRINT_BOXED) ||
2651 (function == TBOX_PRINT_EVENT)) {
2652
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));
2658
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));
2662
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)));
2666
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)));
2670
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));
2674
2675 fprintf(s_printfp, "stroke\n");
2676 }
2677
2678 if ((function == TBOX_PRINT_BOXED) ||
2679 (function == TBOX_PRINT_PLAIN)) {
2680
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");
2689 }
2690
2691 return(rp);
2692}
2693
2694/****************************************************************************
2695* tbox - draws an optionally boxed string whose lower lefthand
2696* corner is at (x, y). As usual, Y is backwards.
2697****************************************************************************/
2698
2699GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
2700{
2701 static GdkRectangle update_rect;
2702 gint lbearing, rbearing, width, ascent, descent;
2703
2704 gdk_string_extents (g_font, s,
2705 &lbearing, &rbearing,
2706 &width, &ascent, &descent);
2707
2708 /*
2709 * If we have enough room to display full size events, then just
2710 * use the BOXED function instead of the EVENT function.
2711 */
2712 if (s_v1->strip_height > 9) {
2713 switch (function) {
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;
2717 default:
2718 break;
2719 /* Nothing */
2720 }
2721 }
2722
2723 switch (function) {
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);
2728
2729 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
2730 x, y - (ascent+descent+3), width + 2,
2731 ascent + descent + 3);
2732
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:
2737 update_rect.x = x;
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);
2743 break;
2744
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,
2748 x, y - 1, 3, 3);
2749 /* NOTE FALLTHROUGH */
2750 case TBOX_GETRECT_EVENT:
2751 update_rect.x = x;
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);
2757 break;
2758
2759
2760 case TBOX_DRAW_PLAIN:
2761
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:
2766 update_rect.x = x;
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);
2772 break;
2773
2774 case TBOX_PRINT_BOXED:
2775 update_rect.x = x;
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));
2782
2783 case TBOX_PRINT_EVENT:
2784 /* We have a small event box to print...no text */
2785 update_rect.x = x;
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));
2790 }
2791 return(&update_rect);
2792}
2793
2794/****************************************************************************
2795* line
2796*
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.
2800*
2801* line_batch_mode contains the state for this:
2802*
2803* BATCH_OFF: no batching, update for every line
2804* BATCH_NEW: just entered a batch, so initialize the area to update from
2805* scratch
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****************************************************************************/
2810
2811static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
2812static int line_batch_count;
2813static int line_minx, line_miny, line_maxx, line_maxy;
2814
2815void line_batch_start (void)
2816{
2817 line_batch_mode = BATCH_NEW;
2818 line_batch_count = 0;
2819}
2820
2821void line_batch_end (void)
2822{
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);
2830 }
2831 line_batch_mode = BATCH_OFF;
2832}
2833
2834void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
2835{
2836 GdkRectangle update_rect;
2837 GdkGC *gc = NULL;
2838
2839 switch(function) {
2840 case LINE_DRAW_BLACK:
2841 gc = da->style->black_gc;
2842 break;
2843
2844 case LINE_DRAW_WHITE:
2845 gc = da->style->white_gc;
2846 break;
2847
2848 case LINE_PRINT:
2849 line_print (x1, y1, x2, y2);
2850 return;
2851 }
2852
2853 gdk_draw_line (pm, gc, x1, y1, x2, y2);
2854
2855 switch (line_batch_mode) {
2856 case BATCH_OFF:
2857 update_rect.x = x1;
2858 update_rect.y = y1;
2859 update_rect.width = (x2-x1) + 1;
2860 update_rect.height = (y2-y1) + 1;
2861 gtk_widget_draw (da, &update_rect);
2862 break;
2863
2864 case BATCH_NEW:
2865 line_minx = x1;
2866 line_maxx = x2;
2867 line_miny = y1;
2868 line_maxy = y2;
2869 line_batch_mode = BATCH_EXISTING;
2870 line_batch_count = 1;
2871 break;
2872
2873 case BATCH_EXISTING:
2874 if (line_minx > x1)
2875 line_minx = x1;
2876 if (line_miny > y1)
2877 line_miny = y1;
2878 if (line_maxx < x2)
2879 line_maxx = x2;
2880 if (line_maxy < y2)
2881 line_maxy = y2;
2882 line_batch_count++;
2883 break;
2884 }
2885}
2886
2887
2888/****************************************************************************
2889* display_pid_axis
2890****************************************************************************/
2891
2892static void display_pid_axis(v1_geometry_t *vp)
2893{
2894 int y, i, label_tick;
2895 int last_printed_y = -vp->strip_height;
2896 pid_sort_t *pp;
2897 int pid_index;
2898 char *label_fmt;
2899 char tmpbuf [128];
2900
2901 /* No pids yet? Outta here */
2902 if (g_pids == NULL)
2903 return;
2904
2905 line_batch_start();
2906
2907 for (i = 0; i < vp->npids; i++) {
2908 pid_index = vp->first_pid_index + i;
2909 if (pid_index >= g_npids)
2910 break;
2911
Dave Barach52642c32016-02-11 19:28:19 -05002912 pp = (g_pids + pid_index);
2913
Dave Barach2c35e582017-04-03 10:22:17 -04002914 set_color(pid_index);
2915
Dave Barach52642c32016-02-11 19:28:19 -05002916 label_fmt = get_track_label(pp->pid_value);
2917 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
2918
2919 y = i*vp->strip_height + vp->pid_ax_offset;
2920
2921 /*
2922 * Have we incremented enough space to have another label not
2923 * overlap the previous label?
2924 */
2925 if (y - last_printed_y > 9) {
2926 /* Draw label */
2927 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
2928
2929 last_printed_y = y;
2930
2931 /*
2932 * And let the line stick out a bit more to indicate this label
2933 * relates to the following line.
2934 */
2935 label_tick = 4;
2936 }
2937 else {
2938 label_tick = 0;
2939 }
2940
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);
2946 }
2947 }
2948
2949 set_color(COLOR_DEFAULT);
2950 line_batch_end();
2951}
2952
2953/****************************************************************************
2954* view1_read_events_callback
2955* New event data just showed up, reset a few things.
2956****************************************************************************/
2957
2958void view1_read_events_callback(void)
2959{
2960 int max_vis_index;
2961
2962 s_v1->first_pid_index = 0;
2963
2964 max_vis_index = 300;
2965 if (max_vis_index > g_nevents)
2966 max_vis_index = g_nevents-1;
2967
2968 s_v1->minvistime = 0LL;
2969 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
2970 s_srchindex = 0;
2971 s_srchcode = 0;
2972 s_last_selected_event = 0;
2973
2974 init_track_colors();
2975
2976 recompute_hscrollbar();
2977 recompute_vscrollbar();
2978}
2979
2980/****************************************************************************
2981* display_event_data
2982****************************************************************************/
2983
2984static void display_event_data(v1_geometry_t *vp)
2985{
2986 int start_index;
2987 int pid_index;
2988 int x, y;
2989 event_t *ep;
2990 event_def_t *edp;
2991 double time_per_pixel;
2992 char tmpbuf[1024];
2993 GdkRectangle *print_rect;
2994 int *last_x_used;
2995
2996 /* Happens if one loads the event def header first, for example. */
2997 if (g_nevents == 0)
2998 return;
2999
3000 time_per_pixel = dtime_per_pixel(vp);
3001
3002 start_index = find_event_index (vp->minvistime);
3003
3004 /* Scrolled too far right? */
3005 if (start_index >= g_nevents)
3006 return;
3007
3008 ep = (g_events + start_index);
3009
3010 if (s_print_offset || summary_mode) {
3011 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3012 } else {
3013 last_x_used = NULL;
3014 }
3015
3016 line_batch_start();
3017
3018 while (ep < (g_events + g_nevents) &&
3019 (ep->time < vp->maxvistime)) {
3020 pid_index = ep->pid->pid_index;
3021 set_color(pid_index);
3022
3023 /* First filter: pid out of range */
3024 if ((pid_index < vp->first_pid_index) ||
3025 (pid_index >= vp->first_pid_index + vp->npids)) {
3026 ep++;
3027 continue;
3028 }
3029
3030 /* Second filter: event hidden */
3031 edp = find_event_definition (ep->code);
3032 if (!edp->selected) {
3033 ep++;
3034 continue;
3035 }
3036
3037 /* Display it... */
3038
3039 pid_index -= vp->first_pid_index;
3040
3041 y = pid_index*vp->strip_height + vp->event_offset;
3042
3043 x = vp->pid_ax_width +
3044 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3045
3046 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3047 ep++;
3048 continue;
3049 }
3050
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);
3054#ifdef NOTDEF
3055 sprintf(tmpbuf, edp->name);
3056 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3057 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3058#endif
3059 } else {
3060 sprintf(tmpbuf, "SEARCH RESULT");
3061 }
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;
3067 }
3068 if (summary_mode) {
3069 int delta = vp->strip_height / 3;
3070 if (delta < 1)
3071 delta = 1;
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;
3075 } else {
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;
3080 }
3081
3082 ep++;
3083 }
3084 if (last_x_used)
3085 g_free(last_x_used);
3086 line_batch_end();
3087 set_color(COLOR_DEFAULT);
3088}
3089
3090/****************************************************************************
3091* display_clear
3092****************************************************************************/
3093
3094static void display_clear(void)
3095{
3096 GdkRectangle update_rect;
3097
3098 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3099 0, 0, da->allocation.width,
3100 da->allocation.height);
3101
3102 update_rect.x = 0;
3103 update_rect.y = 0;
3104 update_rect.width = da->allocation.width;
3105 update_rect.height = da->allocation.height;
3106
3107 gtk_widget_draw (da, &update_rect);
3108}
3109
3110/****************************************************************************
3111* display_time_axis
3112****************************************************************************/
3113
3114static void display_time_axis(v1_geometry_t *vp)
3115{
3116 int x, y, i;
3117 int xoffset, nticks;
3118 char tmpbuf [128];
3119 double unit_divisor;
3120 double time;
3121 char *units;
3122 double time_per_pixel;
3123
3124 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3125
3126 x = vp->pid_ax_width;
3127
3128 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3129
3130 time_per_pixel = dtime_per_pixel(vp);
3131
3132 units = "ns";
3133 unit_divisor = 1.00;
3134
3135 if ((vp->maxvistime / unit_divisor) > 1000) {
3136 units = "us";
3137 unit_divisor = 1000.00;
3138 }
3139
3140 if ((vp->maxvistime / unit_divisor) > 1000) {
3141 units = "ms";
3142 unit_divisor = 1000.00*1000.00;
3143 }
3144 if ((vp->maxvistime / unit_divisor) > 1000) {
3145 units = "s";
3146 unit_divisor = 1000.00*1000.00*1000.00;
3147 }
3148
3149 /* Draw line */
3150 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3151
3152 xoffset = 0;
3153
3154 for (i = 0; i < nticks; i++) {
3155 /* Tick mark */
3156 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3157
3158 time = (double)(x + xoffset - vp->pid_ax_width);
3159 time *= time_per_pixel;
3160 time += (double)(vp->minvistime);
3161 time /= unit_divisor;
3162
3163 sprintf (tmpbuf, "%.2f%s", time, units);
3164
3165 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3166
3167 xoffset += vp->time_ax_spacing;
3168 }
3169}
3170
3171/****************************************************************************
3172* clear_scoreboard
3173* Forget about any temporary displays, they're gone now...
3174****************************************************************************/
3175
3176static void clear_scoreboard(void)
3177{
3178 s_result_up = FALSE;
3179}
3180
3181/****************************************************************************
3182* view1_display
3183****************************************************************************/
3184
3185void view1_display(void)
3186{
3187 display_clear();
3188 display_pid_axis(s_v1);
3189 display_event_data(s_v1);
3190 display_time_axis(s_v1);
3191 clear_scoreboard();
3192}
3193
3194static gint idle_tag;
3195
3196/****************************************************************************
3197* view1_display_eventually
3198****************************************************************************/
3199
3200static void view1_display_eventually(void)
3201{
3202 gtk_idle_remove(idle_tag);
3203 idle_tag = 0;
3204 view1_display();
3205}
3206
3207
3208/****************************************************************************
3209* view1_display_when_idle
3210****************************************************************************/
3211
3212void view1_display_when_idle(void)
3213{
3214 if (idle_tag == 0) {
3215 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3216 }
3217}
3218
3219/****************************************************************************
3220* view1_about
3221****************************************************************************/
3222
3223void view1_about (char *tmpbuf)
3224{
3225 int nsnaps;
3226 snapshot_t *snaps;
3227
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);
3232
3233 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3234 nsnaps++;
3235 }
3236 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);
3237}