blob: 9c86fcdcec4bd2825de762e28551ae03b73e2b60 [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);
Dave Barachb7b92992018-10-17 10:38:51 -04001639 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001640 } 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;
Dave Baracha4bab9d2017-12-14 17:21:36 -05002131 /* Single event? Make window 1s wide... */
2132 if (g_nevents == 1)
2133 s_v1->maxvistime = 1000000;
2134
Dave Barach52642c32016-02-11 19:28:19 -05002135 }
2136 recompute_hscrollbar();
2137 break;
2138
2139 case END_BUTTON:
2140 ep = (g_events + g_nevents - 1);
2141 s_v1->maxvistime = ep->time + event_incdec/3;
2142 s_v1->minvistime = s_v1->maxvistime - current_width;
2143 if (s_v1->minvistime > s_v1->maxvistime)
2144 goto start_button;
2145 recompute_hscrollbar();
2146 break;
2147
2148 case MORE_TRACES_BUTTON:
2149 /* Reduce the strip height to fit more traces on screen */
2150 s_v1->strip_height -= 1;
2151
2152 if (s_v1->strip_height < 1) {
2153 s_v1->strip_height = 1;
2154 }
2155
2156 /* Recalculate the number of strips on the screen */
2157 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2158 s_v1->strip_height;
2159 recompute_vscrollbar();
2160 break;
2161
2162 case LESS_TRACES_BUTTON:
2163 /* Increase the strip height to fit fewer on the screen */
2164 s_v1->strip_height += 1;
2165 if (s_v1->strip_height > 80) {
2166 s_v1->strip_height = 80;
2167 }
2168
2169 /* Recalculate the number of strips on the screen */
2170 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2171 s_v1->strip_height;
2172 recompute_vscrollbar();
2173 break;
2174
2175 case FORWARD_BUTTON:
2176 srch_chase_dir = SRCH_CHASE_FORWARD;
2177 gtk_widget_hide (s_view1_forward_button);
2178 gtk_widget_show (s_view1_backward_button);
2179 break;
2180
2181 case BACKWARD_BUTTON:
2182 srch_chase_dir = SRCH_CHASE_BACKWARD;
2183 gtk_widget_show (s_view1_forward_button);
2184 gtk_widget_hide (s_view1_backward_button);
2185 break;
2186
2187 case SUMMARY_BUTTON:
2188 summary_mode = TRUE;
2189 gtk_widget_hide (s_view1_summary_button);
2190 gtk_widget_show (s_view1_nosummary_button);
2191 break;
2192
2193 case NOSUMMARY_BUTTON:
2194 summary_mode = FALSE;
2195 gtk_widget_show (s_view1_summary_button);
2196 gtk_widget_hide (s_view1_nosummary_button);
2197 break;
Dave Barach2c35e582017-04-03 10:22:17 -04002198
2199 case SLEW_LEFT_BUTTON:
2200 case SLEW_RIGHT_BUTTON:
2201 if (s_v1->last_time_interval < 10e-9) {
2202 infobox("slew", "\nNo time interval set...\n");
2203 break;
2204 }
2205 slew_tracks (s_v1, click);
2206 break;
Dave Barach52642c32016-02-11 19:28:19 -05002207 }
2208
2209 view1_display_when_idle();
2210}
2211
2212/****************************************************************************
2213* view1_print_callback
2214****************************************************************************/
2215
2216void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2217{
2218 modal_dialog("Print Screen (PostScript format) to file:",
2219 "Invalid file: Print Screen to file:",
2220 "g2.ps", print_screen_callback);
2221}
2222
2223/****************************************************************************
2224* view1_hscroll
2225****************************************************************************/
2226
2227static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2228{
2229 ulonglong current_width;
2230
2231 current_width = (s_v1->maxvistime - s_v1->minvistime);
2232
2233 s_v1->minvistime = (ulonglong)(adj->value);
2234 s_v1->maxvistime = s_v1->minvistime + current_width;
2235
2236 view1_display_when_idle();
2237
2238#ifdef NOTDEF
2239 g_print ("adj->lower = %.2f\n", adj->lower);
2240 g_print ("adj->upper = %.2f\n", adj->upper);
2241 g_print ("adj->value = %.2f\n", adj->value);
2242 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2243 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2244 g_print ("adj->page_size = %.2f\n", adj->page_size);
2245#endif
2246}
2247
2248/****************************************************************************
2249* view1_vscroll
2250****************************************************************************/
2251
2252static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2253{
2254 s_v1->first_pid_index = (int)adj->value;
2255 view1_display_when_idle();
2256}
2257
2258void set_pid_ax_width(int width)
2259{
2260 s_v1->pid_ax_width = width;
2261 view1_display_when_idle();
2262}
2263
2264/****************************************************************************
2265* view1_init
2266****************************************************************************/
2267
2268void view1_init(void)
2269{
2270
2271 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2272 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2273
2274 s_v1->pid_ax_width = 80;
2275 s_v1->time_ax_height = 80;
2276 s_v1->time_ax_spacing = 100;
2277 s_v1->strip_height = 25;
2278 s_v1->pop_offset = 20;
2279 s_v1->pid_ax_offset = 34;
2280 s_v1->event_offset = 40;
2281 s_v1->total_height = c_view1_draw_height;
2282 s_v1->total_width = c_view1_draw_width;
2283 s_v1->first_pid_index = 0;
2284
2285 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
2286 s_v1->strip_height;
2287
2288 s_v1->minvistime = 0;
2289 s_v1->maxvistime = 200;
2290
2291 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2292
2293 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2294
2295 da = gtk_drawing_area_new();
2296 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
2297 c_view1_draw_height);
2298
2299#ifdef NOTDEF
2300 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2301 (GtkSignalFunc) motion_notify_event, NULL);
2302#endif
2303
2304 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2305 (GtkSignalFunc) expose_event, NULL);
2306
2307 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2308 (GtkSignalFunc) configure_event, NULL);
2309
2310 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2311 (GtkSignalFunc) button_press_event, NULL);
2312
2313 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2314 (GtkSignalFunc) button_press_event, NULL);
2315
2316 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2317 (GtkSignalFunc) button_press_event, NULL);
2318
2319 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2320 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
2321 | GDK_BUTTON_MOTION_MASK);
2322
2323
2324 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2325
2326 g_font = gdk_font_load ("8x13");
2327 if (g_font == NULL) {
2328 g_error("Couldn't load 8x13 font...\n");
2329 }
2330 gdk_font_ref(g_font);
2331
2332 /* PID axis menu */
2333 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2334
2335 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
2336 0.0 /* minimum value */,
2337 2000.0 /* maximum value */,
2338 0.1 /* step increment */,
2339 10.0/* page increment */,
2340 10.0/* page size */);
2341
2342 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2343
2344 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
2345 GTK_SIGNAL_FUNC (view1_vscroll),
2346 (gpointer)s_view1_vscroll);
2347
2348 s_view1_topbutton = gtk_button_new_with_label("Top");
2349 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2350
2351 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
2352 GTK_SIGNAL_FUNC(view1_button_click_callback),
2353 (gpointer) TOP_BUTTON);
2354
2355 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
2356 GTK_SIGNAL_FUNC(view1_button_click_callback),
2357 (gpointer) BOTTOM_BUTTON);
2358
2359 /* More Traces button and Less Traces button */
2360 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2361 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2362 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
2363 GTK_SIGNAL_FUNC(view1_button_click_callback),
2364 (gpointer) MORE_TRACES_BUTTON);
2365 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
2366 GTK_SIGNAL_FUNC(view1_button_click_callback),
2367 (gpointer) LESS_TRACES_BUTTON);
2368
2369#ifdef NOTDEF
2370 /* Trick to bottom-justify the menu: */
2371 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2372 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2373 TRUE, FALSE, 0);
2374
2375#endif
2376
2377 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2378 FALSE, FALSE, 0);
2379
2380 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2381 TRUE, TRUE, 0);
2382
2383 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2384 FALSE, FALSE, 0);
2385
2386 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2387 FALSE, FALSE, 0);
2388
2389 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2390 FALSE, FALSE, 0);
2391
2392 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2393 FALSE, FALSE, 0);
2394
2395 /* Time axis menu */
2396
2397 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
2398
2399 s_view1_startbutton = gtk_button_new_with_label("Start");
2400
2401 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2402
2403 s_view1_searchbutton = gtk_button_new_with_label("Search");
2404
2405 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2406
2407 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2408
2409 s_view1_endbutton = gtk_button_new_with_label("End");
2410
2411 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
2412 GTK_SIGNAL_FUNC(view1_button_click_callback),
2413 (gpointer) START_BUTTON);
2414
2415 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
2416 GTK_SIGNAL_FUNC(view1_button_click_callback),
2417 (gpointer) ZOOMIN_BUTTON);
2418
2419 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
2420 GTK_SIGNAL_FUNC(view1_button_click_callback),
2421 (gpointer) SEARCH_BUTTON);
2422
2423 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
2424 GTK_SIGNAL_FUNC(view1_button_click_callback),
2425 (gpointer) SEARCH_AGAIN_BUTTON);
2426
2427 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
2428 GTK_SIGNAL_FUNC(view1_button_click_callback),
2429 (gpointer) ZOOMOUT_BUTTON);
2430
2431 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
2432 GTK_SIGNAL_FUNC(view1_button_click_callback),
2433 (gpointer) END_BUTTON);
2434
2435 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
2436 0.0 /* minimum value */,
2437 2000.0 /* maximum value */,
2438 0.1 /* step increment */,
2439 10.0/* page increment */,
2440 10.0/* page size */);
2441
2442 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2443
2444 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
2445 GTK_SIGNAL_FUNC (view1_hscroll),
2446 (gpointer)s_view1_hscroll);
2447
2448 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2449 FALSE, FALSE, 0);
2450
2451 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2452 TRUE, TRUE, 0);
2453
2454 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2455 FALSE, FALSE, 0);
2456
2457 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2458 FALSE, FALSE, 0);
2459
2460 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2461 FALSE, FALSE, 0);
2462
2463 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2464 FALSE, FALSE, 0);
2465
2466 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2467 FALSE, FALSE, 0);
2468
2469 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
2470 TRUE, TRUE, 0);
2471
2472 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2473 FALSE, FALSE, 0);
2474
2475
2476 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2477
2478 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2479
2480 s_view1_nextbutton = gtk_button_new_with_label("Next");
2481
2482 s_view1_delbutton = gtk_button_new_with_label("Del");
2483
2484 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2485
2486 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2487
2488 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2489
2490 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2491
2492 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2493 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2494
2495 s_view1_summary_button = gtk_button_new_with_label("Summary");
2496 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2497
Dave Barach2c35e582017-04-03 10:22:17 -04002498 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2499 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2500
Dave Barach52642c32016-02-11 19:28:19 -05002501 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
2502 GTK_SIGNAL_FUNC(view1_button_click_callback),
2503 (gpointer) SNAP_BUTTON);
2504
2505 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
2506 GTK_SIGNAL_FUNC(view1_button_click_callback),
2507 (gpointer) NEXT_BUTTON);
2508
2509 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
2510 GTK_SIGNAL_FUNC(view1_button_click_callback),
2511 (gpointer) DEL_BUTTON);
2512
2513 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
2514 GTK_SIGNAL_FUNC(view1_button_click_callback),
2515 (gpointer) CHASE_EVENT_BUTTON);
2516
2517 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
2518 GTK_SIGNAL_FUNC(view1_button_click_callback),
2519 (gpointer) CHASE_DATUM_BUTTON);
2520
2521 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
2522 GTK_SIGNAL_FUNC(view1_button_click_callback),
2523 (gpointer) CHASE_TRACK_BUTTON);
2524
2525 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
2526 GTK_SIGNAL_FUNC(view1_button_click_callback),
2527 (gpointer) UNCHASE_BUTTON);
2528
2529 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
2530 GTK_SIGNAL_FUNC(view1_button_click_callback),
2531 (gpointer) FORWARD_BUTTON);
2532
2533 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
2534 GTK_SIGNAL_FUNC(view1_button_click_callback),
2535 (gpointer) BACKWARD_BUTTON);
2536
2537 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
2538 GTK_SIGNAL_FUNC(view1_button_click_callback),
2539 (gpointer) SUMMARY_BUTTON);
2540
2541 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
2542 GTK_SIGNAL_FUNC(view1_button_click_callback),
2543 (gpointer) NOSUMMARY_BUTTON);
2544
Dave Barach2c35e582017-04-03 10:22:17 -04002545 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
2546 GTK_SIGNAL_FUNC(view1_button_click_callback),
2547 (gpointer) SLEW_LEFT_BUTTON);
2548
2549 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
2550 GTK_SIGNAL_FUNC(view1_button_click_callback),
2551 (gpointer) SLEW_RIGHT_BUTTON);
2552
Dave Barach52642c32016-02-11 19:28:19 -05002553 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2554 FALSE, FALSE, 0);
2555
2556 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2557 FALSE, FALSE, 0);
2558
2559 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2560 FALSE, FALSE, 0);
2561
2562 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2563 FALSE, FALSE, 0);
2564
2565 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2566 FALSE, FALSE, 0);
2567
2568 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2569 FALSE, FALSE, 0);
2570
2571 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2572 FALSE, FALSE, 0);
2573
2574 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2575 FALSE, FALSE, 0);
2576
2577 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2578 FALSE, FALSE, 0);
2579
2580 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2581 FALSE, FALSE, 0);
2582
2583 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2584 FALSE, FALSE, 0);
2585
2586 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2587 FALSE, FALSE, 0);
2588
Dave Barach2c35e582017-04-03 10:22:17 -04002589 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2590 s_view1_time_slew_left_button,
2591 FALSE, FALSE, 0);
2592
2593 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2594 s_view1_time_slew_right_button,
2595 FALSE, FALSE, 0);
2596
Dave Barach52642c32016-02-11 19:28:19 -05002597 s_view1_label = gtk_label_new(NULL);
2598
2599 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2600 FALSE, FALSE, 0);
2601
2602 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2603 TRUE, TRUE, 0);
2604
2605 gtk_widget_show_all (s_view1_vbox);
2606 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2607 gtk_widget_grab_focus(da);
2608
2609 gtk_widget_hide (s_view1_forward_button);
2610 gtk_widget_hide (summary_mode ? s_view1_summary_button
2611 : s_view1_nosummary_button);
2612
2613 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
2614 zi_height);
2615 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2616 zi_height);
2617
2618 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
2619 zi_mask, &fg_black,
2620 &bg_white, zi_x_hot,
2621 zi_y_hot);
2622 gdk_pixmap_unref (zi_source);
2623 gdk_pixmap_unref (zi_mask);
2624
2625 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2626}
2627
2628/****************************************************************************
2629* line_print
2630****************************************************************************/
2631
2632void line_print (int x1, int y1, int x2, int y2)
2633{
2634 fprintf(s_printfp, "newpath\n");
2635 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
2636 yrt(x1, s_v1->total_height - y1));
2637
2638 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2639 yrt (x2, s_v1->total_height - y2));
2640 fprintf(s_printfp, "1 setlinewidth\n");
2641 fprintf(s_printfp, "stroke\n");
2642}
2643
2644/****************************************************************************
2645* tbox_print
2646****************************************************************************/
2647GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2648 GdkRectangle *rp)
2649{
2650 if (function == TBOX_PRINT_BOXED) {
2651 rp->width -= 4;
2652 }
2653
2654 if ((function == TBOX_PRINT_BOXED) ||
2655 (function == TBOX_PRINT_EVENT)) {
2656
2657 fprintf(s_printfp, "newpath\n");
2658 fprintf(s_printfp, "0 setlinewidth\n");
2659 fprintf(s_printfp, "%d %d moveto\n",
2660 xrt(rp->x, s_v1->total_height - rp->y),
2661 yrt(rp->x, 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),
2665 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
2666
2667 fprintf(s_printfp, "%d %d lineto\n",
2668 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
2669 yrt(rp->x+rp->width, 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+rp->height)),
2673 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
2674
2675 fprintf(s_printfp, "%d %d lineto\n",
2676 xrt(rp->x, s_v1->total_height - rp->y),
2677 yrt(rp->x, s_v1->total_height - rp->y));
2678
2679 fprintf(s_printfp, "stroke\n");
2680 }
2681
2682 if ((function == TBOX_PRINT_BOXED) ||
2683 (function == TBOX_PRINT_PLAIN)) {
2684
2685 fprintf(s_printfp, "newpath\n");
2686 fprintf(s_printfp, "%d %d moveto\n",
2687 xrt(x, s_v1->total_height - (y-2)),
2688 yrt(x, s_v1->total_height - (y-2)));
2689 fprintf(s_printfp, "gsave\n");
2690 fprintf(s_printfp, "90 rotate\n");
2691 fprintf(s_printfp, "(%s) show\n", s);
2692 fprintf(s_printfp, "grestore\n");
2693 }
2694
2695 return(rp);
2696}
2697
2698/****************************************************************************
2699* tbox - draws an optionally boxed string whose lower lefthand
2700* corner is at (x, y). As usual, Y is backwards.
2701****************************************************************************/
2702
2703GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
2704{
2705 static GdkRectangle update_rect;
2706 gint lbearing, rbearing, width, ascent, descent;
2707
2708 gdk_string_extents (g_font, s,
2709 &lbearing, &rbearing,
2710 &width, &ascent, &descent);
2711
2712 /*
2713 * If we have enough room to display full size events, then just
2714 * use the BOXED function instead of the EVENT function.
2715 */
2716 if (s_v1->strip_height > 9) {
2717 switch (function) {
2718 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
2719 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
2720 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
2721 default:
2722 break;
2723 /* Nothing */
2724 }
2725 }
2726
2727 switch (function) {
2728 case TBOX_DRAW_BOXED:
2729 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
2730 x, y - (ascent+descent+3), width + 2,
2731 ascent + descent + 3);
2732
2733 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
2734 x, y - (ascent+descent+3), width + 2,
2735 ascent + descent + 3);
2736
2737 gdk_draw_string (pm, g_font, da->style->black_gc,
2738 x + 1, y - 1, (const gchar *)s);
2739 /* NOTE FALLTHROUGH */
2740 case TBOX_GETRECT_BOXED:
2741 update_rect.x = x;
2742 update_rect.y = y -(ascent+descent+3);
2743 update_rect.width = width + 3;
2744 update_rect.height = ascent + descent + 4;
2745 if (function == TBOX_DRAW_BOXED)
2746 gtk_widget_draw (da, &update_rect);
2747 break;
2748
2749 case TBOX_DRAW_EVENT:
2750 /* We have a small event to draw...no text */
2751 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
2752 x, y - 1, 3, 3);
2753 /* NOTE FALLTHROUGH */
2754 case TBOX_GETRECT_EVENT:
2755 update_rect.x = x;
2756 update_rect.y = y - 1;
2757 update_rect.width = 4;
2758 update_rect.height = 4;
2759 if (function == TBOX_DRAW_EVENT)
2760 gtk_widget_draw (da, &update_rect);
2761 break;
2762
2763
2764 case TBOX_DRAW_PLAIN:
2765
2766 gdk_draw_string (pm, g_font, da->style->black_gc,
2767 x + 1, y - 1, (const gchar *)s);
2768 /* NOTE FALLTHROUGH */
2769 case TBOX_GETRECT_PLAIN:
2770 update_rect.x = x;
2771 update_rect.y = y -(ascent+descent+1);
2772 update_rect.width = width;
2773 update_rect.height = ascent + descent;
2774 if (function == TBOX_DRAW_PLAIN)
2775 gtk_widget_draw (da, &update_rect);
2776 break;
2777
2778 case TBOX_PRINT_BOXED:
2779 update_rect.x = x;
2780 update_rect.y = y -(ascent+descent+3);
2781 update_rect.width = width + 3;
2782 update_rect.height = ascent + descent + 4;
2783 /* note fallthrough */
2784 case TBOX_PRINT_PLAIN:
2785 return(tbox_print(s, x, y, function, &update_rect));
2786
2787 case TBOX_PRINT_EVENT:
2788 /* We have a small event box to print...no text */
2789 update_rect.x = x;
2790 update_rect.y = y - 1;
2791 update_rect.width = 4;
2792 update_rect.height = 4;
2793 return(tbox_print(s, x, y, function, &update_rect));
2794 }
2795 return(&update_rect);
2796}
2797
2798/****************************************************************************
2799* line
2800*
2801* For lines there is a primitive batching facility, that doesn't update
2802* the drawing area until the batch is complete. This is handy for drawing
2803* the pid axis and for summary mode.
2804*
2805* line_batch_mode contains the state for this:
2806*
2807* BATCH_OFF: no batching, update for every line
2808* BATCH_NEW: just entered a batch, so initialize the area to update from
2809* scratch
2810* BATCH_EXISTING: have drawn at least one line in batch mode, so the update
2811* area should only be expanded from now on to include the
2812* union of the "rectangular hull" of all lines
2813****************************************************************************/
2814
2815static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
2816static int line_batch_count;
2817static int line_minx, line_miny, line_maxx, line_maxy;
2818
2819void line_batch_start (void)
2820{
2821 line_batch_mode = BATCH_NEW;
2822 line_batch_count = 0;
2823}
2824
2825void line_batch_end (void)
2826{
2827 GdkRectangle update_rect;
2828 if (line_batch_count > 0) {
2829 update_rect.x = line_minx;
2830 update_rect.y = line_miny;
2831 update_rect.width = (line_maxx - line_minx) + 1;
2832 update_rect.height = (line_maxy - line_miny) + 1;
2833 gtk_widget_draw (da, &update_rect);
2834 }
2835 line_batch_mode = BATCH_OFF;
2836}
2837
2838void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
2839{
2840 GdkRectangle update_rect;
2841 GdkGC *gc = NULL;
2842
2843 switch(function) {
2844 case LINE_DRAW_BLACK:
2845 gc = da->style->black_gc;
2846 break;
2847
2848 case LINE_DRAW_WHITE:
2849 gc = da->style->white_gc;
2850 break;
2851
2852 case LINE_PRINT:
2853 line_print (x1, y1, x2, y2);
2854 return;
2855 }
2856
2857 gdk_draw_line (pm, gc, x1, y1, x2, y2);
2858
2859 switch (line_batch_mode) {
2860 case BATCH_OFF:
2861 update_rect.x = x1;
2862 update_rect.y = y1;
2863 update_rect.width = (x2-x1) + 1;
2864 update_rect.height = (y2-y1) + 1;
2865 gtk_widget_draw (da, &update_rect);
2866 break;
2867
2868 case BATCH_NEW:
2869 line_minx = x1;
2870 line_maxx = x2;
2871 line_miny = y1;
2872 line_maxy = y2;
2873 line_batch_mode = BATCH_EXISTING;
2874 line_batch_count = 1;
2875 break;
2876
2877 case BATCH_EXISTING:
2878 if (line_minx > x1)
2879 line_minx = x1;
2880 if (line_miny > y1)
2881 line_miny = y1;
2882 if (line_maxx < x2)
2883 line_maxx = x2;
2884 if (line_maxy < y2)
2885 line_maxy = y2;
2886 line_batch_count++;
2887 break;
2888 }
2889}
2890
2891
2892/****************************************************************************
2893* display_pid_axis
2894****************************************************************************/
2895
2896static void display_pid_axis(v1_geometry_t *vp)
2897{
2898 int y, i, label_tick;
2899 int last_printed_y = -vp->strip_height;
2900 pid_sort_t *pp;
2901 int pid_index;
2902 char *label_fmt;
2903 char tmpbuf [128];
2904
2905 /* No pids yet? Outta here */
2906 if (g_pids == NULL)
2907 return;
2908
2909 line_batch_start();
2910
2911 for (i = 0; i < vp->npids; i++) {
2912 pid_index = vp->first_pid_index + i;
2913 if (pid_index >= g_npids)
2914 break;
2915
Dave Barach52642c32016-02-11 19:28:19 -05002916 pp = (g_pids + pid_index);
2917
Dave Barach2c35e582017-04-03 10:22:17 -04002918 set_color(pid_index);
2919
Dave Barach52642c32016-02-11 19:28:19 -05002920 label_fmt = get_track_label(pp->pid_value);
2921 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
2922
2923 y = i*vp->strip_height + vp->pid_ax_offset;
2924
2925 /*
2926 * Have we incremented enough space to have another label not
2927 * overlap the previous label?
2928 */
2929 if (y - last_printed_y > 9) {
2930 /* Draw label */
2931 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
2932
2933 last_printed_y = y;
2934
2935 /*
2936 * And let the line stick out a bit more to indicate this label
2937 * relates to the following line.
2938 */
2939 label_tick = 4;
2940 }
2941 else {
2942 label_tick = 0;
2943 }
2944
2945 /* Draw axis line, but only if the lines aren't too close together */
2946 if (vp->strip_height > 4) {
2947 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
2948 vp->total_width, y+4*s_print_offset,
2949 LINE_DRAW_BLACK+s_print_offset);
2950 }
2951 }
2952
2953 set_color(COLOR_DEFAULT);
2954 line_batch_end();
2955}
2956
2957/****************************************************************************
2958* view1_read_events_callback
2959* New event data just showed up, reset a few things.
2960****************************************************************************/
2961
2962void view1_read_events_callback(void)
2963{
2964 int max_vis_index;
2965
2966 s_v1->first_pid_index = 0;
2967
2968 max_vis_index = 300;
2969 if (max_vis_index > g_nevents)
2970 max_vis_index = g_nevents-1;
2971
2972 s_v1->minvistime = 0LL;
2973 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
Dave Baracha4bab9d2017-12-14 17:21:36 -05002974 /* Single event? Make the initial display 1s wide */
2975 if (g_nevents == 1)
2976 s_v1->maxvistime = 1000000;
Dave Barach52642c32016-02-11 19:28:19 -05002977 s_srchindex = 0;
2978 s_srchcode = 0;
2979 s_last_selected_event = 0;
2980
2981 init_track_colors();
2982
2983 recompute_hscrollbar();
2984 recompute_vscrollbar();
2985}
2986
2987/****************************************************************************
2988* display_event_data
2989****************************************************************************/
2990
2991static void display_event_data(v1_geometry_t *vp)
2992{
2993 int start_index;
2994 int pid_index;
2995 int x, y;
2996 event_t *ep;
2997 event_def_t *edp;
2998 double time_per_pixel;
2999 char tmpbuf[1024];
3000 GdkRectangle *print_rect;
3001 int *last_x_used;
3002
3003 /* Happens if one loads the event def header first, for example. */
3004 if (g_nevents == 0)
3005 return;
3006
3007 time_per_pixel = dtime_per_pixel(vp);
3008
3009 start_index = find_event_index (vp->minvistime);
3010
3011 /* Scrolled too far right? */
3012 if (start_index >= g_nevents)
3013 return;
3014
3015 ep = (g_events + start_index);
3016
3017 if (s_print_offset || summary_mode) {
3018 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3019 } else {
3020 last_x_used = NULL;
3021 }
3022
3023 line_batch_start();
3024
3025 while (ep < (g_events + g_nevents) &&
3026 (ep->time < vp->maxvistime)) {
3027 pid_index = ep->pid->pid_index;
3028 set_color(pid_index);
3029
3030 /* First filter: pid out of range */
3031 if ((pid_index < vp->first_pid_index) ||
3032 (pid_index >= vp->first_pid_index + vp->npids)) {
3033 ep++;
3034 continue;
3035 }
3036
3037 /* Second filter: event hidden */
3038 edp = find_event_definition (ep->code);
3039 if (!edp->selected) {
3040 ep++;
3041 continue;
3042 }
3043
3044 /* Display it... */
3045
3046 pid_index -= vp->first_pid_index;
3047
3048 y = pid_index*vp->strip_height + vp->event_offset;
3049
3050 x = vp->pid_ax_width +
3051 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3052
3053 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3054 ep++;
3055 continue;
3056 }
3057
3058 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3059 if (ep->flags & EVENT_FLAG_SELECT) {
3060 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3061#ifdef NOTDEF
3062 sprintf(tmpbuf, edp->name);
3063 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3064 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3065#endif
3066 } else {
3067 sprintf(tmpbuf, "SEARCH RESULT");
3068 }
3069 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
3070 TBOX_DRAW_BOXED+s_print_offset);
3071 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3072 if (last_x_used != NULL)
3073 last_x_used[pid_index] = x + print_rect->width;
3074 }
3075 if (summary_mode) {
3076 int delta = vp->strip_height / 3;
3077 if (delta < 1)
3078 delta = 1;
3079 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3080 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3081 last_x_used[pid_index] = x + 1;
3082 } else {
3083 sprintf(tmpbuf, "%ld", ep->code);
3084 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3085 if (last_x_used != NULL)
3086 last_x_used[pid_index] = x + print_rect->width;
3087 }
3088
3089 ep++;
3090 }
3091 if (last_x_used)
3092 g_free(last_x_used);
3093 line_batch_end();
3094 set_color(COLOR_DEFAULT);
3095}
3096
3097/****************************************************************************
3098* display_clear
3099****************************************************************************/
3100
3101static void display_clear(void)
3102{
3103 GdkRectangle update_rect;
3104
3105 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3106 0, 0, da->allocation.width,
3107 da->allocation.height);
3108
3109 update_rect.x = 0;
3110 update_rect.y = 0;
3111 update_rect.width = da->allocation.width;
3112 update_rect.height = da->allocation.height;
3113
3114 gtk_widget_draw (da, &update_rect);
3115}
3116
3117/****************************************************************************
3118* display_time_axis
3119****************************************************************************/
3120
3121static void display_time_axis(v1_geometry_t *vp)
3122{
3123 int x, y, i;
3124 int xoffset, nticks;
3125 char tmpbuf [128];
3126 double unit_divisor;
3127 double time;
3128 char *units;
3129 double time_per_pixel;
3130
3131 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3132
3133 x = vp->pid_ax_width;
3134
3135 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3136
3137 time_per_pixel = dtime_per_pixel(vp);
3138
3139 units = "ns";
3140 unit_divisor = 1.00;
3141
3142 if ((vp->maxvistime / unit_divisor) > 1000) {
3143 units = "us";
3144 unit_divisor = 1000.00;
3145 }
3146
3147 if ((vp->maxvistime / unit_divisor) > 1000) {
3148 units = "ms";
3149 unit_divisor = 1000.00*1000.00;
3150 }
3151 if ((vp->maxvistime / unit_divisor) > 1000) {
3152 units = "s";
3153 unit_divisor = 1000.00*1000.00*1000.00;
3154 }
3155
3156 /* Draw line */
3157 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3158
3159 xoffset = 0;
3160
3161 for (i = 0; i < nticks; i++) {
3162 /* Tick mark */
3163 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3164
3165 time = (double)(x + xoffset - vp->pid_ax_width);
3166 time *= time_per_pixel;
3167 time += (double)(vp->minvistime);
3168 time /= unit_divisor;
3169
3170 sprintf (tmpbuf, "%.2f%s", time, units);
3171
3172 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
3173
3174 xoffset += vp->time_ax_spacing;
3175 }
3176}
3177
3178/****************************************************************************
3179* clear_scoreboard
3180* Forget about any temporary displays, they're gone now...
3181****************************************************************************/
3182
3183static void clear_scoreboard(void)
3184{
3185 s_result_up = FALSE;
3186}
3187
3188/****************************************************************************
3189* view1_display
3190****************************************************************************/
3191
3192void view1_display(void)
3193{
3194 display_clear();
3195 display_pid_axis(s_v1);
3196 display_event_data(s_v1);
3197 display_time_axis(s_v1);
3198 clear_scoreboard();
3199}
3200
3201static gint idle_tag;
3202
3203/****************************************************************************
3204* view1_display_eventually
3205****************************************************************************/
3206
3207static void view1_display_eventually(void)
3208{
3209 gtk_idle_remove(idle_tag);
3210 idle_tag = 0;
3211 view1_display();
3212}
3213
3214
3215/****************************************************************************
3216* view1_display_when_idle
3217****************************************************************************/
3218
3219void view1_display_when_idle(void)
3220{
3221 if (idle_tag == 0) {
3222 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3223 }
3224}
3225
3226/****************************************************************************
3227* view1_about
3228****************************************************************************/
3229
3230void view1_about (char *tmpbuf)
3231{
3232 int nsnaps;
3233 snapshot_t *snaps;
3234
3235 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3236 s_v1->minvistime, s_v1->maxvistime);
3237 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
3238 s_v1->strip_height);
3239
3240 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3241 nsnaps++;
3242 }
3243 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);
3244}