blob: ca05b78267f5e511e24cc44b1fe9edc3a80bede6 [file] [log] [blame]
Dave Barach9c8cfd32019-02-03 10:44:47 -05001/*
Dave Barach52642c32016-02-11 19:28:19 -05002 *------------------------------------------------------------------
Dave Barach9c8cfd32019-02-03 10:44:47 -05003 * Copyright (c) 2005-2019 Cisco and/or its affiliates.
Dave Barach52642c32016-02-11 19:28:19 -05004 * 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>
Dave Barach9c8cfd32019-02-03 10:44:47 -050027#include <math.h>
Dave Barach52642c32016-02-11 19:28:19 -050028
29/*
30 * The main event display view.
Dave Barach9c8cfd32019-02-03 10:44:47 -050031 *
Dave Barach52642c32016-02-11 19:28:19 -050032 * Important variables:
33 *
34 * "da" -- the drawing area, aka the screen representation of the
35 * event view.
36 *
37 * "pm" -- the backing pixmap for the drawing area. Note that
38 * all graphics operations target this backing
39 * store, then call gtk_widget_draw to copy a rectangle from
40 * the backing store onto the screen.
41 *
42 * "s_v1" -- pointer to the current v1_geometry_t object.
Dave Barach9c8cfd32019-02-03 10:44:47 -050043 *
Dave Barach52642c32016-02-11 19:28:19 -050044 * Box heirarchy:
45 * s_view1_vbox
46 * s_view1_hbox
47 * da s_view1_vmenubox
48 * s_view1_topbutton("Top")
49 * s_view1_vscroll (vertical scrollbar)
50 * s_view1_bottombutton("Bottom")
51 * s_view1_hmenubox
52 * s_view1_startbutton("Start");
53 * s_view1_hscroll(horizontal scrollbar)
54 * s_view1_endbutton("End")
55 * s_view1_zoominbutton("Zoomin")
56 * s_view1_searchbutton("Search")
57 * s_view1_searchagainbutton("Search Again")
58 * s_view1_zoomoutbutton("Zoomout")
59 * s_view1_label
60 */
61
62/*
63 * Globals
64 */
65
66GdkFont *g_font; /* a fixed-width font to use */
Dave Barach2c35e582017-04-03 10:22:17 -040067/* color format: 0 (for static colors), r (0-64k), g (0-64k), b (0-64k) */
Dave Barach52642c32016-02-11 19:28:19 -050068GdkColor fg_black = {0, 0, 0, 0};
Dave Barach2c35e582017-04-03 10:22:17 -040069GdkColor fg_red = {0, 65535, 0, 0};
Dave Barach52642c32016-02-11 19:28:19 -050070GdkColor bg_white = {0, 65535, 65535, 65535};
71static boolean summary_mode = TRUE; /* start out in summary mode */
Dave Barach2c35e582017-04-03 10:22:17 -040072static boolean color_mode = FALSE; /* start out in monochrome mode */
Dave Barach52642c32016-02-11 19:28:19 -050073
74/*
75 * Locals
76 */
77
Dave Barach9c8cfd32019-02-03 10:44:47 -050078/*
Dave Barach52642c32016-02-11 19:28:19 -050079 * user_data values passed to view1_button_click_callback,
80 * which is used by the various action buttons noted above
81 */
82enum view1_button_click {
83 TOP_BUTTON=1,
84 BOTTOM_BUTTON,
85 START_BUTTON,
86 ZOOMIN_BUTTON,
87 SEARCH_BUTTON,
Dave Barach9c8cfd32019-02-03 10:44:47 -050088 ANOMALY_BUTTON,
89 ANOMALY_NEXT_BUTTON,
90 ANOMALY_THRESHOLD_BUTTON,
Dave Barach52642c32016-02-11 19:28:19 -050091 SEARCH_AGAIN_BUTTON,
92 ZOOMOUT_BUTTON,
93 END_BUTTON,
94 MORE_TRACES_BUTTON,
95 LESS_TRACES_BUTTON,
96 SNAP_BUTTON,
97 NEXT_BUTTON,
98 DEL_BUTTON,
99 CHASE_EVENT_BUTTON,
100 CHASE_DATUM_BUTTON,
101 CHASE_TRACK_BUTTON,
102 UNCHASE_BUTTON,
103 FORWARD_BUTTON,
104 BACKWARD_BUTTON,
105 SUMMARY_BUTTON,
106 NOSUMMARY_BUTTON,
Dave Barach2c35e582017-04-03 10:22:17 -0400107 SLEW_LEFT_BUTTON,
108 SLEW_RIGHT_BUTTON,
Dave Barach52642c32016-02-11 19:28:19 -0500109};
110
111enum chase_mode {
112 CHASE_EVENT=1,
113 CHASE_DATUM,
114 CHASE_TRACK,
115};
116
117enum sc_dir {
118 SRCH_CHASE_FORWARD = 0,
119 SRCH_CHASE_BACKWARD = 1,
120};
121
122static GtkWidget *s_view1_hbox; /* see box heirarchy chart */
123static GtkWidget *s_view1_vbox; /* see box heirarchy chart */
124static GtkWidget *da; /* main drawing area */
125static GdkPixmap *pm; /* and its backing pixmap */
126static GdkCursor *norm_cursor; /* the "normal" cursor */
127
128/*
129 * view geometry parameters
130 *
131 * Remember:
132 * Y increases down the page.
133 * Strip origin is at the top
134 * Payday is Friday
135 * Don't put your fingers in your mouth.
136 *
137 * Most of these values are in pixels
138 */
139
140typedef struct v1_geometry {
141 int pid_ax_width; /* Width of the PID axis */
142 int time_ax_height; /* Height of the time axis */
143 int time_ax_spacing; /* TimeAxis: Space between tick-marks */
144 int strip_height; /* Height of a regular PID trace */
145 int pop_offset; /* Vertical offset of the detail box */
146 int pid_ax_offset; /* Vertical offset of the PID axis */
147 int event_offset; /* Vertical offset of the event boxes */
148 int total_height; /* total height of da, see configure_event */
149 int total_width; /* ditto, for width */
Dave Barach2c35e582017-04-03 10:22:17 -0400150 double last_time_interval; /* last time interval, in f64 seconds */
Dave Barach9c8cfd32019-02-03 10:44:47 -0500151 double anomaly_threshold_stddevs; /* Anomaly detection threshold */
152
Dave Barach52642c32016-02-11 19:28:19 -0500153 /* Derived values */
154 int first_pid_index; /* Index of first displayed PID */
155 int npids; /* Max number of displayed pids */
156 ulonglong minvistime; /* in usec */
157 ulonglong maxvistime; /* in usec */
Dave Barach9c8cfd32019-02-03 10:44:47 -0500158
159 /* Anomaly detection statistics */
160 f64 *means, *variances, *two_stddevs;
Dave Barach3117ad82019-02-04 17:41:29 -0500161 f64 *mins, *maxes;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500162 u32 *matches;
163
Dave Barach52642c32016-02-11 19:28:19 -0500164} v1_geometry_t;
165
166
167/* The active geometry object */
Dave Barach9c8cfd32019-02-03 10:44:47 -0500168static v1_geometry_t s_v1record;
169static v1_geometry_t *s_v1 = &s_v1record;
Dave Barach52642c32016-02-11 19:28:19 -0500170
171/* The color array */
172static GdkColor *s_color;
173
174/* Snapshot ring */
175typedef struct snapshot {
176 struct snapshot *next;
177 /* Screen geometry */
178 v1_geometry_t geometry;
179 boolean show_event[NEVENTS];
180 pid_sort_t *pidvec;
181 /*
182 * Note: not worth recomputing the vertical scrollbar, just save
183 * its value here
184 */
185 gfloat vscroll_value;
186 boolean summary_mode;
187 boolean color_mode;
188} snapshot_t;
189
190static snapshot_t *s_snapshots;
191static snapshot_t *s_cursnap;
192static event_t *s_last_selected_event;
193
194/*
195 * various widgets, see the box heirarchy chart above
Dave Barach9c8cfd32019-02-03 10:44:47 -0500196 * The toolkit keeps track of these things, we could lose many of
197 * these pointers.
Dave Barach52642c32016-02-11 19:28:19 -0500198 */
199static GtkWidget *s_view1_vmenubox;
200static GtkWidget *s_view1_topbutton;
201static GtkWidget *s_view1_bottombutton;
202static GtkWidget *s_view1_more_traces_button;
203static GtkWidget *s_view1_less_traces_button;
204
205static GtkWidget *s_view1_hmenubox;
206static GtkWidget *s_view1_hmenubox2;
207static GtkWidget *s_view1_startbutton;
208static GtkWidget *s_view1_zoominbutton;
209static GtkWidget *s_view1_searchbutton;
210static GtkWidget *s_view1_srchagainbutton;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500211static GtkWidget *s_view1_anomalybutton;
212static GtkWidget *s_view1_anomalynextbutton;
Dave Barach52642c32016-02-11 19:28:19 -0500213static GtkWidget *s_view1_zoomoutbutton;
214static GtkWidget *s_view1_endbutton;
215
216static GtkWidget *s_view1_snapbutton;
217static GtkWidget *s_view1_nextbutton;
218static GtkWidget *s_view1_delbutton;
219
220static GtkWidget *s_view1_chase_event_button;
221static GtkWidget *s_view1_chase_datum_button;
222static GtkWidget *s_view1_chase_track_button;
223static GtkWidget *s_view1_unchasebutton;
224
225static GtkWidget *s_view1_forward_button;
226static GtkWidget *s_view1_backward_button;
227
228static GtkWidget *s_view1_summary_button;
229static GtkWidget *s_view1_nosummary_button;
230
Dave Barach2c35e582017-04-03 10:22:17 -0400231static GtkWidget *s_view1_time_slew_right_button;
232static GtkWidget *s_view1_time_slew_left_button;
233
Dave Barach9c8cfd32019-02-03 10:44:47 -0500234static GtkWidget *s_view1_anomalythresholdbutton;
235
Dave Barach52642c32016-02-11 19:28:19 -0500236static GtkWidget *s_view1_hscroll;
237static GtkObject *s_view1_hsadj;
238
239static GtkWidget *s_view1_vscroll;
240static GtkObject *s_view1_vsadj;
241
242static GtkWidget *s_view1_label;
243
244/*
Dave Barach9c8cfd32019-02-03 10:44:47 -0500245 * Search context
Dave Barach52642c32016-02-11 19:28:19 -0500246 */
247static ulong s_srchcode; /* search event code */
Dave Barach9c8cfd32019-02-03 10:44:47 -0500248static ulong s_anomalycode; /* anomaly event code */
Dave Barach52642c32016-02-11 19:28:19 -0500249static int s_srchindex; /* last hit was at this event index */
250static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */
251static boolean s_srchfail_up; /* The status line "Search Failed" is up */
252static int srch_chase_dir; /* search/chase dir, 0=>forward */
253
254
255/*
Dave Barach9c8cfd32019-02-03 10:44:47 -0500256 * Print context
Dave Barach52642c32016-02-11 19:28:19 -0500257 */
258static int s_print_offset; /* Magic offset added to line, tbox fn codes */
Dave Barach9c8cfd32019-02-03 10:44:47 -0500259static FILE *s_printfp;
Dave Barach52642c32016-02-11 19:28:19 -0500260
261/*
262 * Forward reference prototypes
263 */
264static void display_pid_axis(v1_geometry_t *vp);
265static void display_event_data(v1_geometry_t *vp);
266static void display_time_axis(v1_geometry_t *vp);
267static void view1_button_click_callback(GtkButton *item, gpointer data);
268
269/*
270 * config params
271 */
272
273gint c_view1_draw_width;
274gint c_view1_draw_height;
275
276/*
277 * Zoom-In / Time Ruler cursor
278 */
279
280#define zi_width 32
281#define zi_height 32
282#define zi_x_hot 22
283#define zi_y_hot 14
284static unsigned char zi_bits[] = {
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
286 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
287 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
288 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
289 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
290 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
291 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
292 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
293 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
294 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
296
297static unsigned char zi_bkgd[] = {
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
299 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
300 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
301 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00,
302 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00,
303 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00,
304 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00,
305 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
306 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
307 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
309
310static GdkCursor *zi_cursor;
311static GdkPixmap *zi_source, *zi_mask;
312
Dave Barach9c8cfd32019-02-03 10:44:47 -0500313/*
Dave Barach52642c32016-02-11 19:28:19 -0500314 * Frequently-used small computations, best
315 * done correctly once and instantiated.
316 */
317
318/****************************************************************************
319* dtime_per_pixel
320****************************************************************************/
321
322static inline double dtime_per_pixel(v1_geometry_t *vp)
323{
324 return ((double)(vp->maxvistime - vp->minvistime)) /
325 ((double)(vp->total_width - vp->pid_ax_width));
326}
327
328/****************************************************************************
329* message_line
330* Changes the status line. Pass "" to clear the status line.
331****************************************************************************/
332
333void message_line (char *s)
334{
335 gtk_label_set_text (GTK_LABEL(s_view1_label), s);
336}
337
338/****************************************************************************
339* set_window_title
340* Changes the window title to include the specified filename.
341****************************************************************************/
342
343void set_window_title (const char *filename)
344{
345 char title[128];
346 snprintf(title, sizeof(title), "g2 (%s)", filename);
347 gtk_window_set_title(GTK_WINDOW(g_mainwindow), title);
348}
349
350/****************************************************************************
351* recompute_hscrollbar
352* Adjust the horizontal scrollbar's adjustment object.
Dave Barach9c8cfd32019-02-03 10:44:47 -0500353*
Dave Barach52642c32016-02-11 19:28:19 -0500354* GtkAdjustments are really cool, but have to be set up exactly
355* right or the various client objects screw up completely.
356*
357* Note: this function is *not* called when the user clicks the scrollbar.
358****************************************************************************/
359
360static void recompute_hscrollbar (void)
361{
362 ulonglong current_width;
363 ulonglong event_incdec;
364 GtkAdjustment *adj;
365 event_t *ep;
366
367 if (g_nevents == 0)
368 return;
369
370 ep = (g_events + (g_nevents-1));
371 current_width = s_v1->maxvistime - s_v1->minvistime;
372 event_incdec = (current_width) / 6;
373
374 adj = GTK_ADJUSTMENT(s_view1_hsadj);
375
Dave Barach9c8cfd32019-02-03 10:44:47 -0500376 /*
Dave Barach52642c32016-02-11 19:28:19 -0500377 * Structure member decoder ring
378 * -----------------------------
379 * lower the minimum possible value
380 * value the current value
381 * upper the maximum possible value
382 * step_increment end button click increment
383 * page_increment click in trough increment
384 * page_size size of currently visible area
385 */
386
Dave Barach9c8cfd32019-02-03 10:44:47 -0500387 adj->lower = (gfloat)0.00;
Dave Barach52642c32016-02-11 19:28:19 -0500388 adj->value = (gfloat)s_v1->minvistime;
389
390 /* Minor click: move about 1/6 of a page */
391 adj->step_increment = (gfloat)event_incdec;
392
393 /* Major click: move about 1/3 of a page. */
394 adj->page_increment = (gfloat)(2*event_incdec);
395
396 /* allow the user to go a bit past the end */
397 adj->upper = adj->page_increment/3 + (gfloat)(ep->time);
398 adj->page_size = (gfloat)(current_width);
399
400 /*
Dave Barach9c8cfd32019-02-03 10:44:47 -0500401 * Tell all clients (e.g. the visible scrollbar) to
402 * make themselves look right
Dave Barach52642c32016-02-11 19:28:19 -0500403 */
404 gtk_adjustment_changed(adj);
405 gtk_adjustment_value_changed(adj);
406}
407
408/****************************************************************************
409* recompute_vscrollbar
410* Ditto, for the vertical scrollbar
411****************************************************************************/
412
413static void recompute_vscrollbar (void)
414{
415 GtkAdjustment *adj;
416
417 adj = GTK_ADJUSTMENT(s_view1_vsadj);
418
419 adj->lower = (gfloat)0.00;
420 adj->upper = (gfloat)g_npids;
421 adj->value = (gfloat)0.00;
422 adj->step_increment = 1.00;
423 adj->page_increment = (gfloat)(s_v1->npids / 3);
424 adj->page_size = (gfloat)s_v1->npids;
425 gtk_adjustment_changed(adj);
426 gtk_adjustment_value_changed(adj);
427}
428
429/****************************************************************************
430* format_popbox_string
431****************************************************************************/
432
433elog_main_t elog_main;
434
435void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp)
436{
437 char *fp;
438
439#ifdef NOTDEF
440 sprintf(tmpbuf,"%d:", ep->code);
441#endif
442 if (ep->flags & EVENT_FLAG_CLIB) {
443 elog_event_t *eep;
444 u8 *s;
445
446 eep = get_clib_event (ep->datum);
Dave Barach9c8cfd32019-02-03 10:44:47 -0500447
Dave Barach52642c32016-02-11 19:28:19 -0500448 s = format (0, "%U", format_elog_event, &elog_main, eep);
449 memcpy (tmpbuf, s, vec_len(s));
450 tmpbuf[vec_len(s)] = 0;
451 vec_free(s);
452 return;
453 }
454
455 snprintf(tmpbuf, len, "%s", edp->name);
456 fp = edp->format;
457 /* Make sure there's a real format string. If so, add it */
458 while (fp && *fp) {
459 if (*fp != ' ') {
460 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
461 /* %s only supported for cpel files */
462 if (fp[1] == 's') {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500463 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
Dave Barach52642c32016-02-11 19:28:19 -0500464 edp->format, strtab_ref(ep->datum));
465 } else {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500466 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
Dave Barach52642c32016-02-11 19:28:19 -0500467 edp->format, ep->datum);
468 }
469 return;
470 }
471 fp++;
472 }
473}
474
475/****************************************************************************
476 * add_snapshot
477 ****************************************************************************/
478
479static void add_snapshot(void)
480{
481 int i;
482 snapshot_t *new = g_malloc(sizeof(snapshot_t));
483
484 memcpy(&new->geometry, s_v1, sizeof(new->geometry));
485 for (i = 0; i < NEVENTS; i++) {
486 new->show_event[i] = g_eventdefs[i].selected;
487 }
488 new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids);
489 memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids);
490 new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value;
491 new->summary_mode = summary_mode;
492 new->color_mode = color_mode;
493
494 if (s_snapshots) {
495 new->next = s_snapshots;
496 s_snapshots = new;
497 } else {
498 new->next = 0;
499 s_snapshots = new;
500 }
501 s_cursnap = new;
502}
503
504/****************************************************************************
505 * next_snapshot
506 ****************************************************************************/
507
508static void next_snapshot(void)
509{
510 snapshot_t *next;
511 int i;
512 pid_sort_t *psp;
513 pid_data_t *pp;
514
515 if (!s_snapshots) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500516 infobox("No snapshots", "\nNo snapshots in the ring...\n");
Dave Barach52642c32016-02-11 19:28:19 -0500517 return;
518 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500519
Dave Barach52642c32016-02-11 19:28:19 -0500520 next = s_cursnap->next;
521 if (next == 0)
522 next = s_snapshots;
523
524 s_cursnap = next;
525
526 memcpy(s_v1, &next->geometry, sizeof(next->geometry));
527 for (i = 0; i < NEVENTS; i++) {
528 g_eventdefs[i].selected = next->show_event[i];
529 }
530 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
531 color_mode = next->color_mode;
532 /*
533 * Update summary mode via a button push so that the button state is
534 * updated accordingly. (Should ideally clean up the view/controller
535 * separation properly one day.)
536 */
537 if (summary_mode != next->summary_mode) {
538 view1_button_click_callback
539 (NULL, (gpointer)(unsigned long long)
540 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
541 }
542
543 /* Fix the pid structure index mappings */
544 psp = g_pids;
545
546 for (i = 0; i < g_npids; i++) {
547 pp = psp->pid;
548 pp->pid_index = i;
549 psp++;
550 }
551 GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value;
552 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
553 recompute_hscrollbar();
554 pointsel_next_snapshot();
555 view1_display_when_idle();
556}
557
558
559/****************************************************************************
560 * del_snapshot
561 ****************************************************************************/
562
563static void del_snapshot(void)
564{
565 snapshot_t *prev;
566 snapshot_t *this;
567
568 if (!s_snapshots) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500569 infobox("No snapshots", "\nNo snapshots to delete...\n");
Dave Barach52642c32016-02-11 19:28:19 -0500570 return;
571 }
572
573 prev = NULL;
574 this = s_snapshots;
575
576 while (this && this != s_cursnap) {
577 prev = this;
578 this = this->next;
579 }
580
581 if (this != s_cursnap) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500582 infobox("BUG", "\nSnapshot AWOL!\n");
Dave Barach52642c32016-02-11 19:28:19 -0500583 return;
584 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500585
Dave Barach52642c32016-02-11 19:28:19 -0500586 s_cursnap = this->next;
587
588 /* middle of the list? */
589 if (prev) {
590 prev->next = this->next;
591 g_free(this->pidvec);
592 g_free(this);
593 } else { /* start of the list */
594 s_snapshots = this->next;
595 g_free(this->pidvec);
596 g_free(this);
597 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500598
Dave Barach52642c32016-02-11 19:28:19 -0500599 /* Note: both will be NULL after last delete */
600 if (s_cursnap == NULL)
601 s_cursnap = s_snapshots;
602}
603
604/****************************************************************************
605 * write_snapshot
606 *
607 * VERY primitive right now - not endian or version independent, and only
608 * writes to "snapshots.g2" in the current directory
609 ****************************************************************************/
610static void write_snapshot(void)
611{
612 FILE *file = NULL;
613 snapshot_t *snap;
614 char *error = NULL;
615 int records = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500616
Dave Barach52642c32016-02-11 19:28:19 -0500617 if (s_snapshots == NULL) {
618 error = "No snapshots defined";
619 errno = 0;
620 }
621
622 if (!error) {
623 file = fopen("snapshots.g2", "w");
624 if (file == NULL) {
625 error = "Unable to open snapshots.g2";
626 }
627 }
628
629 /*
630 * Simply serialize the arch-dependent binary data, without a care in the
631 * world. Don't come running to me if you try to read it and crash.
632 */
633 for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500634 if (fwrite(&snap->geometry,
Dave Barach52642c32016-02-11 19:28:19 -0500635 sizeof(snap->geometry), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500636 fwrite(&snap->show_event,
Dave Barach52642c32016-02-11 19:28:19 -0500637 sizeof(snap->show_event), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500638 fwrite(snap->pidvec,
Dave Barach52642c32016-02-11 19:28:19 -0500639 sizeof(pid_sort_t) * g_npids, 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500640 fwrite(&snap->vscroll_value,
Dave Barach52642c32016-02-11 19:28:19 -0500641 sizeof(snap->vscroll_value), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500642 fwrite(&snap->summary_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500643 sizeof(snap->summary_mode), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500644 fwrite(&snap->color_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500645 sizeof(snap->color_mode), 1, file) != 1) {
646 error = "Error writing data";
647 }
648 records++;
649 }
650
651 if (!error) {
652 if (fclose(file)) {
653 error = "Unable to close file";
654 }
655 }
656
657 if (error) {
658 infobox(error, strerror(errno));
659 } else {
660 char buf[64];
Dave Barach9c8cfd32019-02-03 10:44:47 -0500661 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
Dave Barach52642c32016-02-11 19:28:19 -0500662 records);
663 message_line(buf);
664 }
665}
666
667/****************************************************************************
668 * read_snapshot
669 *
670 * VERY primitive right now - not endian or version independent, and only reads
671 * from "snapshots.g2" in the current directory
672 ****************************************************************************/
673static void read_snapshot(void)
674{
675 FILE *file;
676 snapshot_t *snap, *next_snap;
677 snapshot_t *new_snaps = NULL;
678 char *error = NULL;
679 int len, i, records = 0;
680 pid_data_t *pp;
681
682 file = fopen("snapshots.g2", "r");
683 if (file == NULL) {
684 error = "Unable to open snapshots.g2";
685 }
686
687 /*
688 * Read in the snapshots and link them together. We insert them backwards,
689 * but that's tolerable. If the data is in anyway not what we expect, we'll
690 * probably crash. Sorry.
691 */
692 while (!error && !feof(file)) {
693 snap = g_malloc(sizeof(*snap));
694 snap->pidvec = NULL; /* so we can free this if there's an error */
695
696 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
697 if (len == 0) {
698 /* EOF */
699 g_free(snap);
700 break;
701 } else {
702 /* insert into list straight away */
703 snap->next = new_snaps;
704 new_snaps = snap;
705 }
706 if (len != 1) {
707 error = "Problem reading first item from file";
708 break;
709 }
710 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
711 error = "Problem reading second item from file";
712 break;
713 }
714 len = sizeof(pid_sort_t) * g_npids;
715 snap->pidvec = g_malloc(len);
716 if (fread(snap->pidvec, len, 1, file) != 1) {
717 error = "Problem reading third item from file";
718 break;
719 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500720 if (fread(&snap->vscroll_value,
Dave Barach52642c32016-02-11 19:28:19 -0500721 sizeof(snap->vscroll_value), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500722 fread(&snap->summary_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500723 sizeof(snap->summary_mode), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500724 fread(&snap->color_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500725 sizeof(snap->color_mode), 1, file) != 1) {
726 error = "Problem reading final items from file";
727 break;
728 }
729
730 /*
731 * Fix up the pointers from the sorted pid vector back into our pid
732 * data objects, by walking the linked list of pid_data_t objects for
733 * every one looking for a match. This is O(n^2) grossness, but in real
734 * life there aren't that many pids, and it seems zippy enough.
735 */
736 for (i = 0; i < g_npids; i++) {
737 for (pp = g_pid_data_list; pp != NULL; pp = pp->next) {
738 if (pp->pid_value == snap->pidvec[i].pid_value) {
739 break;
740 }
741 }
742 if (pp != NULL) {
743 snap->pidvec[i].pid = pp;
744 } else {
745 error = "Snapshot file referenced unknown pids";
746 break;
747 }
748 }
749
750 records++;
751 }
752
753 if (!error) {
754 if (fclose(file)) {
755 error = "Unable to close file";
756 }
757 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500758
Dave Barach52642c32016-02-11 19:28:19 -0500759 if (error) {
760 /*
761 * Problem - clear up any detritus
762 */
763 infobox(error, strerror(errno));
764 for (snap = new_snaps; snap != NULL; snap = next_snap) {
765 next_snap = snap->next;
766 g_free(snap);
767 g_free(snap->pidvec);
768 }
769 } else {
770 /*
771 * Success! trash the old snapshots and replace with the new
772 */
773 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
774 next_snap = snap->next;
775 g_free(snap->pidvec);
776 g_free(snap);
777 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500778
Dave Barach52642c32016-02-11 19:28:19 -0500779 s_cursnap = s_snapshots = new_snaps;
780 }
781
782 if (error) {
783 infobox(error, strerror(errno));
784 } else {
785 char buf[64];
Dave Barach9c8cfd32019-02-03 10:44:47 -0500786 snprintf(buf, sizeof(buf),
Dave Barach52642c32016-02-11 19:28:19 -0500787 "Read %d snapshots from snapshots.g2", records);
788 message_line(buf);
789 }
790}
791
792/****************************************************************************
793* set_color
794*
795* Set the color for the specified pid_index, or COLOR_DEFAULT to return it
796* to the usual black.
797****************************************************************************/
798#define COLOR_DEFAULT (-1)
799static void set_color(int pid_index)
800{
Dave Barach2c35e582017-04-03 10:22:17 -0400801 pid_sort_t *psp;
802
803 psp = (g_pids + pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -0500804
Dave Barach2c35e582017-04-03 10:22:17 -0400805 if (psp->selected)
806 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
807 else if (pid_index == COLOR_DEFAULT || !color_mode) {
Dave Barach52642c32016-02-11 19:28:19 -0500808 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
809 } else {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500810 gdk_gc_set_foreground(da->style->black_gc,
Dave Barach52642c32016-02-11 19:28:19 -0500811 &s_color[g_pids[pid_index].color_index]);
812 }
813}
814
815/****************************************************************************
816* toggle_event_select
817****************************************************************************/
818
Dave Barach2c35e582017-04-03 10:22:17 -0400819static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
Dave Barach52642c32016-02-11 19:28:19 -0500820{
821 int pid_index, start_index;
822 int x, y;
823 GdkRectangle *rp;
824 GdkRectangle hit_rect;
825 GdkRectangle dummy;
826 event_t *ep;
827 event_def_t *edp;
828 char tmpbuf [1024];
829 double time_per_pixel;
830
831 if (g_nevents == 0)
Dave Barach2c35e582017-04-03 10:22:17 -0400832 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500833
834 time_per_pixel = dtime_per_pixel(vp);
835
836 start_index = find_event_index (vp->minvistime);
837
838 /* Too far right? */
839 if (start_index >= g_nevents)
Dave Barach2c35e582017-04-03 10:22:17 -0400840 return 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500841
842 /*
Dave Barach52642c32016-02-11 19:28:19 -0500843 * To see if the mouse hit a visible event, use a variant
844 * of the event display loop.
845 */
846
847 hit_rect.x = (int)event->x;
848 hit_rect.y = (int)event->y;
849 hit_rect.width = 1;
850 hit_rect.height = 1;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500851
Dave Barach52642c32016-02-11 19:28:19 -0500852 ep = (g_events + start_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -0500853
854 while ((ep->time < vp->maxvistime) &&
Dave Barach52642c32016-02-11 19:28:19 -0500855 (ep < (g_events + g_nevents))) {
856 pid_index = ep->pid->pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500857
Dave Barach52642c32016-02-11 19:28:19 -0500858 /* First filter: pid out of range */
859 if ((pid_index < vp->first_pid_index) ||
860 (pid_index >= vp->first_pid_index + vp->npids)) {
861 ep++;
862 continue;
863 }
864
865 /* Second filter: event hidden */
866 edp = find_event_definition (ep->code);
867 if (!edp->selected) {
868 ep++;
869 continue;
870 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500871
872 /*
Dave Barach52642c32016-02-11 19:28:19 -0500873 * At this point, we know that the point is at least on the
Dave Barach9c8cfd32019-02-03 10:44:47 -0500874 * screen. See if the mouse hit within the bounding box
Dave Barach52642c32016-02-11 19:28:19 -0500875 */
876
Dave Barach9c8cfd32019-02-03 10:44:47 -0500877 /*
Dave Barach52642c32016-02-11 19:28:19 -0500878 * $$$$ maybe keep looping until off the edge,
879 * maintain a "best hit", then declare that one the winner?
880 */
881
882 pid_index -= vp->first_pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500883
Dave Barach52642c32016-02-11 19:28:19 -0500884 y = pid_index*vp->strip_height + vp->event_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500885
886 x = vp->pid_ax_width +
Dave Barach52642c32016-02-11 19:28:19 -0500887 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
888
889 /* Perhaps we're trying to toggle the detail box? */
890 if (ep->flags & EVENT_FLAG_SELECT) {
891 /* Figure out the dimensions of the detail box */
892 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
893 rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED);
894 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
895 ep->flags &= ~EVENT_FLAG_SELECT;
896 view1_display_when_idle();
Dave Barach2c35e582017-04-03 10:22:17 -0400897 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500898 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500899 }
Dave Barach52642c32016-02-11 19:28:19 -0500900
901 sprintf(tmpbuf, "%ld", ep->code);
902
903 /* Figure out the dimensions of the regular box */
904 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
905
906 if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) {
907 /* we hit the rectangle. */
908 if (ep->flags & EVENT_FLAG_SELECT) {
909 ep->flags &= ~EVENT_FLAG_SELECT;
910 view1_display_when_idle();
Dave Barach2c35e582017-04-03 10:22:17 -0400911 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500912 } else {
913 set_color(ep->pid->pid_index);
914
915 /* It wasn't selected, so put up the detail box */
916 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
917 tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED);
918 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK);
919 ep->flags |= EVENT_FLAG_SELECT;
920 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
921 s_last_selected_event = ep;
922 }
Dave Barach2c35e582017-04-03 10:22:17 -0400923 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500924 }
925 ep++;
926 }
Dave Barach2c35e582017-04-03 10:22:17 -0400927 return -1;
Dave Barach52642c32016-02-11 19:28:19 -0500928}
929
930/****************************************************************************
Dave Barach2c35e582017-04-03 10:22:17 -0400931* toggle_track_select
932****************************************************************************/
933
Dave Barach9c8cfd32019-02-03 10:44:47 -0500934static void toggle_track_select (GdkEventButton *event,
Dave Barach2c35e582017-04-03 10:22:17 -0400935 v1_geometry_t *vp)
936{
937 int i;
938 int pid_index;
939 int y, delta_y;
940 pid_sort_t *psp;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500941
Dave Barach2c35e582017-04-03 10:22:17 -0400942 if (g_nevents == 0)
943 return;
944
945 /* Scan pid/track axis locations, looking for a match */
946 for (i = 0; i < vp->npids; i++) {
947 y = i*vp->strip_height + vp->pid_ax_offset;
948 delta_y = y - event->y;
949 if (delta_y < 0)
950 delta_y = -delta_y;
951 if (delta_y < 10) {
952 goto found;
953 }
954
955 }
956 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
957 return;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500958
Dave Barach2c35e582017-04-03 10:22:17 -0400959 found:
960 pid_index = i + vp->first_pid_index;
961 psp = (g_pids + pid_index);
962 psp->selected ^= 1;
963 view1_display_when_idle();
964}
965
966/****************************************************************************
967* deselect_tracks
968****************************************************************************/
969static void deselect_tracks (void)
970{
971 int i;
972
973 for (i = 0; i < g_npids; i++)
974 g_pids[i].selected = 0;
975
976}
977
978
979/****************************************************************************
Dave Barach52642c32016-02-11 19:28:19 -0500980* move_current_track
981****************************************************************************/
982
983typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
984
Dave Barach9c8cfd32019-02-03 10:44:47 -0500985static void move_current_track(GdkEventButton *event,
Dave Barach52642c32016-02-11 19:28:19 -0500986 v1_geometry_t *vp,
987 move_type type)
988{
989 int i;
990 int pid_index;
991 int y, delta_y;
992 pid_sort_t *new_pidvec;
993 pid_sort_t *psp;
994 pid_sort_t *pold, *pnew;
995 pid_data_t *pp;
996
997 if (g_nevents == 0)
998 return;
999
1000 /* Scan pid/track axis locations, looking for a match */
1001 for (i = 0; i < vp->npids; i++) {
1002 y = i*vp->strip_height + vp->pid_ax_offset;
1003 delta_y = y - event->y;
1004 if (delta_y < 0)
1005 delta_y = -delta_y;
1006 if (delta_y < 10) {
1007 goto found;
1008 }
1009
1010 }
1011 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
1012 return;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001013
Dave Barach52642c32016-02-11 19:28:19 -05001014 found:
1015 pid_index = i + vp->first_pid_index;
1016
Dave Baracha8ed6bd2017-04-04 08:00:23 -04001017 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001018 pold = g_pids;
1019 pnew = new_pidvec;
1020
1021 if (type == MOVE_TOP) {
1022 /* move to top */
1023 *pnew++ = g_pids[pid_index];
1024 for (i = 0; i < pid_index; i++)
1025 *pnew++ = *pold++;
1026 pold++;
1027 i++;
1028 for (; i < g_npids; i++)
1029 *pnew++ = *pold++;
1030 } else {
1031 /* move to bottom */
1032 for (i = 0; i < pid_index; i++)
1033 *pnew++ = *pold++;
1034 pold++;
1035 i++;
1036 for (; i < g_npids; i++)
1037 *pnew++ = *pold++;
1038 *pnew = g_pids[pid_index];
1039 }
1040
1041 g_free(g_pids);
1042 g_pids = new_pidvec;
1043
1044 /*
Dave Barach9c8cfd32019-02-03 10:44:47 -05001045 * Revert the pid_index mapping to an identity map,
Dave Barach52642c32016-02-11 19:28:19 -05001046 */
1047 psp = g_pids;
1048
1049 for (i = 0; i < g_npids; i++) {
1050 pp = psp->pid;
1051 pp->pid_index = i;
1052 psp++;
1053 }
1054 view1_display_when_idle();
1055}
1056
1057/****************************************************************************
1058* zoom_event
Dave Barach9c8cfd32019-02-03 10:44:47 -05001059* Process a zoom gesture. The use of doubles is required to avoid
Dave Barach52642c32016-02-11 19:28:19 -05001060* truncating the various variable values, which in turn would lead to
1061* some pretty random-looking zoom responses.
1062****************************************************************************/
1063
1064void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1065{
1066 double xrange;
1067 double time_per_pixel;
1068 double width_in_pixels;
1069 double center_on_time, width_in_time;
1070 double center_on_pixel;
1071
Dave Barach9c8cfd32019-02-03 10:44:47 -05001072 /*
1073 * Clip the zoom area to the event display area.
Dave Barach52642c32016-02-11 19:28:19 -05001074 * Otherwise, center_on_time - width_in_time is in hyperspace
Dave Barach9c8cfd32019-02-03 10:44:47 -05001075 * to the left of zero
Dave Barach52642c32016-02-11 19:28:19 -05001076 */
Dave Barach9c8cfd32019-02-03 10:44:47 -05001077
Dave Barach52642c32016-02-11 19:28:19 -05001078 if (e1->x < vp->pid_ax_width)
1079 e1->x = vp->pid_ax_width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001080
Dave Barach52642c32016-02-11 19:28:19 -05001081 if (e2->x < vp->pid_ax_width)
1082 e2->x = vp->pid_ax_width;
1083
1084 if (e2->x == e1->x)
1085 goto loser_zoom_repaint;
1086
1087 xrange = (double) (e2->x - e1->x);
1088 if (xrange < 0.00)
1089 xrange = -xrange;
1090
1091 /* Actually, width in pixels of half the zoom area */
1092 width_in_pixels = xrange / 2.00;
1093 time_per_pixel = dtime_per_pixel(vp);
1094 width_in_time = width_in_pixels * time_per_pixel;
1095
1096 /* Center the screen on the center of the zoom area */
Dave Barach9c8cfd32019-02-03 10:44:47 -05001097 center_on_pixel = (double)((e2->x + e1->x) / 2.00) -
Dave Barach52642c32016-02-11 19:28:19 -05001098 (double)vp->pid_ax_width;
1099 center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime;
1100
1101 /*
1102 * Transform back to 64-bit integer microseconds, reset the
Dave Barach9c8cfd32019-02-03 10:44:47 -05001103 * scrollbar, schedule a repaint.
Dave Barach52642c32016-02-11 19:28:19 -05001104 */
1105 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1106 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1107
1108loser_zoom_repaint:
1109 recompute_hscrollbar();
Dave Barach9c8cfd32019-02-03 10:44:47 -05001110
Dave Barach52642c32016-02-11 19:28:19 -05001111 view1_display_when_idle();
1112}
1113
1114/****************************************************************************
1115* scroll_y
1116*
1117* Scroll up or down by the specified delta
1118*
1119****************************************************************************/
1120static void scroll_y(int delta)
1121{
1122 int new_index = s_v1->first_pid_index + delta;
1123 if (new_index + s_v1->npids > g_npids)
1124 new_index = g_npids - s_v1->npids;
1125 if (new_index < 0)
1126 new_index = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001127
Dave Barach52642c32016-02-11 19:28:19 -05001128 if (new_index != s_v1->first_pid_index) {
1129 s_v1->first_pid_index = new_index;
1130 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index;
1131 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1132 view1_display_when_idle();
1133 }
1134}
1135
1136/****************************************************************************
1137* view1_handle_key_press_event
1138* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1139*
1140* This routine implements hotkeys for the Quake generation:
1141*
1142* W - zoom in
1143* S - zoom out
1144* A - pan left
1145* D - pan right
1146* R - pan up
1147* F - pan down
1148* T - more traces
1149* G - fewer traces
1150*
1151* E - toggle summary mode
1152* C - toggle color mode
1153*
1154* X - take snapshot
1155* Z - next snapshot
1156* P - persist snapshots to file
1157* L - load snapshots from file
1158*
1159* ctrl-Q - exit
1160*
1161****************************************************************************/
1162gint
1163view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1164{
1165 long long delta;
1166
1167 switch (event->keyval) {
1168 case GDK_w: // zoom in
1169 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1170 break;
1171
1172 case GDK_s: // zoom out
1173 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1174 break;
1175
1176 case GDK_a: // pan left
1177 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1178 if (s_v1->minvistime < delta) {
1179 delta = s_v1->minvistime;
1180 }
1181 s_v1->minvistime -= delta;
1182 s_v1->maxvistime -= delta;
1183 recompute_hscrollbar();
1184 break;
1185
1186 case GDK_d: // pan right
1187 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1188 if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) {
1189 /*
1190 * @@@ this doesn't seem to quite reach the far right hand
1191 * side correctly - not sure why.
1192 */
1193 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1194 }
1195 s_v1->minvistime += delta;
1196 s_v1->maxvistime += delta;
1197 recompute_hscrollbar();
1198 break;
1199
1200 case GDK_r: // pan up
1201 scroll_y(-1);
1202 break;
1203
1204 case GDK_f: // pan down
1205 scroll_y(+1);
1206 break;
1207
1208 case GDK_t: // fewer tracks
1209 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1210 break;
1211
1212 case GDK_g: // more tracks
1213 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1214 break;
1215
1216 case GDK_e: // toggle summary mode
1217 view1_button_click_callback
1218 (NULL, (gpointer)(unsigned long long)
1219 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
1220 break;
1221
1222 case GDK_c: // toggle color mode
1223 color_mode ^= 1;
1224 view1_display_when_idle();
1225 break;
1226
1227 case GDK_p: // persist snapshots
1228 write_snapshot();
1229 break;
1230
1231 case GDK_l: // load snapshots
1232 read_snapshot();
1233 break;
1234
1235 case GDK_x: // take snapshot
1236 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1237 break;
1238
1239 case GDK_z: // next snapshot
1240 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1241 break;
1242
1243 case GDK_q: // ctrl-q is exit
1244 if (event->state & GDK_CONTROL_MASK) {
1245 gtk_main_quit();
1246 }
1247 break;
1248 }
1249 return TRUE;
1250}
1251
1252/****************************************************************************
1253* button_press_event
1254* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1255*
1256* This routine implements three functions: zoom-to-area, time ruler, and
Dave Barach9c8cfd32019-02-03 10:44:47 -05001257* show/hide event detail popup.
Dave Barach52642c32016-02-11 19:28:19 -05001258*
Dave Barach9c8cfd32019-02-03 10:44:47 -05001259* The left mouse button (button 1) has two simultaneous functions: event
Dave Barach52642c32016-02-11 19:28:19 -05001260* detail popup, and zoom-to-area. If the press and release events occur
1261* within a small delta-x, it's a detail popup event. Otherwise, it's
1262* an area zoom.
1263*
1264* The right mouse button (button 3) implements the time ruler.
1265****************************************************************************/
1266
1267static gint
1268button_press_event (GtkWidget *widget, GdkEventButton *event)
1269{
1270 static GdkEventButton press1_event;
1271 static boolean press1_valid;
1272 static GdkEventButton press3_event;
1273 static guint32 last_truler_time;
1274 static boolean press3_valid;
1275 static boolean zoom_bar_up;
1276 int time_ax_y, xdelta;
1277 char tmpbuf [128];
1278 double time_per_pixel;
1279
1280 time_ax_y = 0;
1281
1282 switch(event->type) {
1283 case GDK_BUTTON_PRESS:
1284 /* Capture the appropriate starting point */
1285 if (event->button == 1) {
1286 press1_valid = TRUE;
1287 press1_event = *event;
1288 return(TRUE);
1289 }
1290 if (event->button == 3) {
1291 press3_valid = TRUE;
1292 press3_event = *event;
1293 return(TRUE);
1294 }
1295 return(TRUE);
1296
1297 case GDK_BUTTON_RELEASE:
1298 /* Time ruler */
1299 if (press3_valid) {
1300 press3_valid = FALSE;
1301 /* Fix the cursor, and repaint the screen from scratch */
1302 gdk_window_set_cursor (da->window, norm_cursor);
1303 view1_display_when_idle();
1304 return(TRUE);
1305 }
1306 /* Event select / zoom-to-area */
1307 if (press1_valid) {
1308 press1_valid = FALSE;
1309 xdelta = (int)(press1_event.x - event->x);
1310 if (xdelta < 0)
1311 xdelta = -xdelta;
1312
1313 /* is the mouse more or less where it started? */
1314 if (xdelta < 10) {
1315 /* Control-left-mouse => sink the track */
1316 /* Shift-left-mouse => raise the track */
1317 if ((press1_event.state & GDK_CONTROL_MASK) ==
1318 GDK_CONTROL_MASK) {
1319 move_current_track(event, s_v1, MOVE_BOTTOM);
1320 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1321 GDK_SHIFT_MASK) {
1322 move_current_track(event, s_v1, MOVE_TOP);
1323 } else {
Dave Barach2c35e582017-04-03 10:22:17 -04001324 /* No modifiers: toggle the event / select track */
1325 if (toggle_event_select(event, s_v1))
1326 toggle_track_select(event, s_v1);
Dave Barach52642c32016-02-11 19:28:19 -05001327 }
1328 /* Repaint to get rid of the zoom bar */
1329 if (zoom_bar_up) {
1330 /* Fix the cursor and leave. No zoom */
1331 gdk_window_set_cursor (da->window, norm_cursor);
1332 zoom_bar_up = FALSE;
1333 break;
1334 }
1335 } else { /* mouse moved enough to zoom */
1336 zoom_event(&press1_event, event, s_v1);
1337 gdk_window_set_cursor (da->window, norm_cursor);
1338 zoom_bar_up = FALSE;
1339 }
1340 } else if (event->button == 4) {
1341 /* scroll wheel up */
1342 scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1);
1343 } else if (event->button == 5) {
1344 /* scroll wheel down */
1345 scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1);
1346 }
1347 return(TRUE);
1348
1349 case GDK_MOTION_NOTIFY:
1350 /* Button one followed by motion: draw zoom fence and fix cursor */
1351 if (press1_valid) {
1352 /* Fence, cursor already set */
1353 if (zoom_bar_up)
1354 return(TRUE);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001355
Dave Barach52642c32016-02-11 19:28:19 -05001356 xdelta = (int)(press1_event.x - event->x);
1357 if (xdelta < 0)
1358 xdelta = -xdelta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001359
Dave Barach52642c32016-02-11 19:28:19 -05001360 /* Haven't moved enough to declare a zoom sequence yet */
Dave Barach9c8cfd32019-02-03 10:44:47 -05001361 if (xdelta < 10)
Dave Barach52642c32016-02-11 19:28:19 -05001362 return(TRUE);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001363
Dave Barach52642c32016-02-11 19:28:19 -05001364 /* Draw the zoom fence, use the key-down X coordinate */
1365 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001366
1367 line((int)(press1_event.x), s_v1->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05001368 (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK);
1369 tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset,
1370 TBOX_DRAW_BOXED);
1371 gdk_window_set_cursor(da->window, zi_cursor);
1372 zoom_bar_up = TRUE;
1373 return(TRUE);
1374 }
1375 if (press3_valid) {
1376 double nsec;
1377
1378 gdk_window_set_cursor(da->window, zi_cursor);
1379
Dave Barach9c8cfd32019-02-03 10:44:47 -05001380 /*
Dave Barach52642c32016-02-11 19:28:19 -05001381 * Some filtration is needed on Solaris, or the server will hang
1382 */
1383 if (event->time - last_truler_time < 75)
1384 return(TRUE);
1385
1386 last_truler_time = event->time;
1387
Dave Barach9c8cfd32019-02-03 10:44:47 -05001388 line((int)(press3_event.x), s_v1->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05001389 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1390
1391 xdelta = (int)(press3_event.x - event->x);
1392 if (xdelta < 0)
1393 xdelta = -xdelta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001394
1395 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1396 ((double)(s_v1->total_width - s_v1->pid_ax_width));
Dave Barach52642c32016-02-11 19:28:19 -05001397
1398 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1399
Dave Barach9c8cfd32019-02-03 10:44:47 -05001400 line((int)(press3_event.x), s_v1->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05001401 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1402 /*
1403 * Note: use a fixed-width format so it looks like we're
Dave Barach9c8cfd32019-02-03 10:44:47 -05001404 * erasing and redrawing the box.
Dave Barach52642c32016-02-11 19:28:19 -05001405 */
1406 nsec = ((double)xdelta)*time_per_pixel;
1407 if (nsec >1e9) {
1408 sprintf(tmpbuf, "%8.3f sec ", nsec/1e9);
1409 } else if (nsec > 1e6) {
1410 sprintf(tmpbuf, "%8.3f msec", nsec/1e6);
1411 } else if (nsec > 1e3) {
1412 sprintf(tmpbuf, "%8.3f usec", nsec/1e3);
1413 } else {
1414 sprintf(tmpbuf, "%8.0f nsec", nsec);
1415 }
Dave Barach2c35e582017-04-03 10:22:17 -04001416 s_v1->last_time_interval = nsec;
Dave Barach52642c32016-02-11 19:28:19 -05001417 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1418 TBOX_DRAW_BOXED);
1419 return(TRUE);
1420 }
1421
1422 default:
1423 break;
1424#ifdef DEBUG
1425 g_print("button:\ttype = %d\n", event->type);
1426 g_print("\twindow = 0x%x\n", event->window);
1427 g_print("\tsend_event = %d\n", event->send_event);
1428 g_print("\ttime = %d\n", event->time);
1429 g_print("\tx = %6.2f\n", event->x);
1430 g_print("\ty = %6.2f\n", event->y);
1431 g_print("\tpressure = %6.2f\n", event->pressure);
1432 g_print("\txtilt = %6.2f\n", event->xtilt);
1433 g_print("\tytilt = %6.2f\n", event->ytilt);
1434 g_print("\tstate = %d\n", event->state);
1435 g_print("\tbutton = %d\n", event->button);
1436 g_print("\tsource = %d\n", event->source);
1437 g_print("\tdeviceid = %d\n", event->deviceid);
1438 g_print("\tx_root = %6.2f\n", event->x_root);
1439 g_print("\ty_root = %6.2f\n", event->y_root);
1440 return(TRUE);
1441#endif
1442 }
1443
1444 view1_display_when_idle();
1445
1446 return(TRUE);
1447}
1448
1449/****************************************************************************
1450* configure_event
1451* Happens when the window manager resizes the viewer's main window.
1452****************************************************************************/
1453
1454static gint
1455configure_event (GtkWidget *widget, GdkEventConfigure *event)
1456{
1457 /* Toss the previous drawing area backing store pixmap */
1458 if (pm)
1459 gdk_pixmap_unref(pm);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001460
Dave Barach52642c32016-02-11 19:28:19 -05001461 /* Create a new pixmap, paint it */
1462 pm = gdk_pixmap_new(widget->window,
1463 widget->allocation.width,
1464 widget->allocation.height,
1465 -1);
1466 gdk_draw_rectangle (pm,
1467 widget->style->white_gc,
1468 TRUE,
1469 0, 0,
1470 widget->allocation.width,
1471 widget->allocation.height);
1472
1473 /* Reset the view geometry parameters, as required */
1474 s_v1->total_width = widget->allocation.width;
1475 s_v1->total_height = widget->allocation.height;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001476 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05001477 s_v1->strip_height;
1478
1479 /* Schedule a repaint */
1480 view1_display_when_idle();
1481 return(TRUE);
1482}
1483
1484/****************************************************************************
1485* expose_event
1486* Use backing store to fix the screen.
1487****************************************************************************/
1488static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1489{
1490 gdk_draw_pixmap(widget->window,
1491 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1492 pm,
1493 event->area.x, event->area.y,
1494 event->area.x, event->area.y,
1495 event->area.width, event->area.height);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001496
Dave Barach52642c32016-02-11 19:28:19 -05001497 return(FALSE);
1498}
1499
1500/****************************************************************************
1501* event_search_internal
1502* This routine searches forward from s_srchindex, looking for s_srchcode;
1503* wraps at the end of the buffer.
1504****************************************************************************/
1505
1506boolean event_search_internal (void)
1507{
1508 event_t *ep;
1509 int i;
1510 int index;
1511 int pid_index;
1512 boolean full_redisplay = FALSE;
1513 ulonglong current_width;
1514 char tmpbuf [64];
1515
1516 /* No events yet? Act like the search worked, to avoid a loop */
1517 if (g_nevents == 0)
1518 return(TRUE);
1519
1520 ep = (g_events + s_srchindex);
1521 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1522
Dave Barach9c8cfd32019-02-03 10:44:47 -05001523 /*
Dave Barach52642c32016-02-11 19:28:19 -05001524 * Assume the user wants to search [plus or minus]
1525 * from where they are.
1526 */
1527#ifdef notdef
1528 if (ep->time < s_v1->minvistime)
1529 s_srchindex = find_event_index (s_v1->minvistime);
1530#endif
1531
1532 for (i = 1; i <= g_nevents; i++) {
1533 index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ?
1534 (s_srchindex - i) % g_nevents :
1535 (i + s_srchindex) % g_nevents;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001536
Dave Barach52642c32016-02-11 19:28:19 -05001537 ep = (g_events + index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001538
Dave Barach52642c32016-02-11 19:28:19 -05001539 if (ep->code == s_srchcode) {
1540 if (s_srchfail_up)
1541 message_line("");
1542 s_srchindex = index;
1543 pid_index = ep->pid->pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001544
Dave Barach52642c32016-02-11 19:28:19 -05001545 /* Need a vertical scroll? */
1546 if ((pid_index < s_v1->first_pid_index) ||
1547 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1548 if (pid_index > (g_npids - s_v1->npids))
1549 pid_index = (g_npids - s_v1->npids);
1550 s_v1->first_pid_index = pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001551 GTK_ADJUSTMENT(s_view1_vsadj)->value =
Dave Barach52642c32016-02-11 19:28:19 -05001552 (gdouble)s_v1->first_pid_index;
1553 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1554 full_redisplay = TRUE;
1555 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05001556
Dave Barach52642c32016-02-11 19:28:19 -05001557 /* Need a horizontal scroll? */
1558 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1559 current_width = (s_v1->maxvistime - s_v1->minvistime);
1560 if (ep->time < ((current_width+1) / 2)) {
1561 s_v1->minvistime = 0ll;
1562 s_v1->maxvistime = current_width;
1563 } else {
1564 s_v1->minvistime = ep->time - ((current_width+1)/2);
1565 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1566 }
1567 recompute_hscrollbar();
1568 full_redisplay = TRUE;
1569 }
1570 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1571 full_redisplay = TRUE;
1572
1573#ifdef NOTDEF
1574 if (!full_redisplay){
1575 if (!s_result_up) {
1576 s_result_up = TRUE;
1577 time_per_pixel = dtime_per_pixel(s_v1);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001578
Dave Barach52642c32016-02-11 19:28:19 -05001579 y = pid_index*s_v1->strip_height + s_v1->event_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001580 x = s_v1->pid_ax_width +
1581 (int)(((double)(ep->time - s_v1->minvistime)) /
Dave Barach52642c32016-02-11 19:28:19 -05001582 time_per_pixel);
1583 sprintf(tmpbuf, "SEARCH RESULT");
1584 tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED);
1585 line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK);
1586 } else {
1587 full_redisplay = TRUE;
1588 }
1589 }
1590#endif
1591
1592 if (full_redisplay)
1593 view1_display_when_idle();
1594 return(TRUE);
1595 }
1596 }
1597 sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode);
1598 message_line(tmpbuf);
1599 s_srchfail_up = TRUE;
1600 return(TRUE);
1601}
1602
1603/****************************************************************************
1604* event_search_callback
1605****************************************************************************/
1606
1607boolean event_search_callback (char *s)
1608{
1609 /* No events yet? Act like the search worked, to avoid a loop */
1610 if (g_nevents == 0)
1611 return(TRUE);
1612
1613 s_srchcode = atol(s);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001614
Dave Barach52642c32016-02-11 19:28:19 -05001615 if (s_srchcode == 0)
1616 return(FALSE);
1617
1618 return(event_search_internal());
1619}
1620
Dave Barach9c8cfd32019-02-03 10:44:47 -05001621
1622/****************************************************************************
1623* anomaly_statistics_init
1624****************************************************************************/
1625
1626static int anomaly_statistics_init (void)
1627{
1628 elog_event_t *eep;
1629 u32 data;
1630 event_t *ep;
1631 pid_data_t *pid;
1632 int i;
1633 int index;
1634 int pid_index;
1635 f64 fdata;
1636
1637 /* Gather summary statistics... */
1638 ep = g_events;
1639
1640 vec_reset_length (s_v1->means);
1641 vec_reset_length (s_v1->matches);
1642 vec_reset_length (s_v1->variances);
1643 vec_reset_length (s_v1->two_stddevs);
Dave Barach3117ad82019-02-04 17:41:29 -05001644 vec_reset_length (s_v1->mins);
1645 vec_reset_length (s_v1->maxes);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001646
1647 for (i = 0; i < g_nevents; i++) {
1648 if (ep->code != s_anomalycode) {
1649 ep++;
1650 continue;
1651 }
1652 pid = ep->pid;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001653 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
Dave Barach3117ad82019-02-04 17:41:29 -05001654 vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
1655 vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
1656 vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001657 eep = get_clib_event (ep->datum);
1658 data = clib_mem_unaligned (eep->data, u32);
1659 fdata = data;
1660 s_v1->means[pid->pid_index] += fdata;
1661 s_v1->matches[pid->pid_index] += 1;
Dave Barach3117ad82019-02-04 17:41:29 -05001662 /* First data point? set min, max */
1663 if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
1664 s_v1->mins[pid->pid_index] = fdata;
1665 s_v1->maxes[pid->pid_index] = fdata;
1666 } else {
1667 s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
1668 fdata : s_v1->mins[pid->pid_index];
1669 s_v1->maxes[pid->pid_index] =
1670 (fdata > s_v1->maxes[pid->pid_index]) ?
1671 fdata : s_v1->maxes[pid->pid_index];
1672 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05001673 ep++;
1674 }
1675 if (vec_len (s_v1->matches) == 0)
1676 return -1;
1677
1678 /* Compute s_v1->means */
1679 for (i = 0; i < vec_len (s_v1->means); i++)
1680 s_v1->means[i] = s_v1->matches[i]
1681 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1682
1683 /* Compute s_v1->variances */
1684 ep = g_events;
1685 for (i = 0; i < g_nevents; i++) {
1686 if (ep->code != s_anomalycode) {
1687 ep++;
1688 continue;
1689 }
1690 pid = ep->pid;
1691 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1692 eep = get_clib_event (ep->datum);
1693 data = clib_mem_unaligned (eep->data, u32);
1694 fdata = data;
1695 s_v1->variances[pid->pid_index] +=
1696 (fdata - s_v1->means[pid->pid_index])
1697 * (fdata - s_v1->means[pid->pid_index]);
1698 ep++;
1699 }
1700
1701 /* Normalize variances */
1702 for (i = 0; i < vec_len (s_v1->variances); i++)
1703 s_v1->variances[i] = s_v1->matches[i]
1704 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1705
1706 /* Compute the anomaly threshold, by default 2.5*stddev */
1707 for (i = 0; i < vec_len (s_v1->variances); i++)
1708 vec_add1 (s_v1->two_stddevs,
1709 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1710 return 0;
1711}
1712
1713/****************************************************************************
1714* anomaly_search_internal
1715* This routine searches forward from s_srchindex, looking for s_srchcode;
1716* wraps at the end of the buffer.
1717****************************************************************************/
1718
1719boolean anomaly_search_internal (void)
1720{
1721 elog_event_t *eep;
1722 u32 data;
1723 event_t *ep;
1724 pid_data_t *pid;
1725 int i;
1726 int index;
1727 int pid_index;
1728 boolean full_redisplay = FALSE;
1729 ulonglong current_width;
1730 char tmpbuf [64];
1731 f64 fdata;
1732
1733 if (vec_len (s_v1->matches) == 0)
1734 anomaly_statistics_init();
1735
1736 ep = (g_events + s_srchindex);
1737 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1738
1739 /*
1740 * If the user rearranged the screen, start from the minimum
1741 * visible time
1742 */
1743 if (ep->time < s_v1->minvistime)
1744 s_srchindex = find_event_index (s_v1->minvistime);
1745
1746 for (i = 1; i <= g_nevents; i++) {
1747 index = (i + s_srchindex) % g_nevents;
1748
1749 ep = (g_events + index);
1750 if (ep->code != s_anomalycode)
1751 continue;
1752 pid = ep->pid;
1753
1754 eep = get_clib_event (ep->datum);
1755 data = clib_mem_unaligned (eep->data, u32);
1756 fdata = data;
1757
1758 /*
1759 * Found an anomaly? Define an anomaly as a datum
1760 * greater than 2*stddev above average.
1761 */
1762 if ((fdata - s_v1->means[pid->pid_index]) >
1763 s_v1->two_stddevs[pid->pid_index]) {
1764 u8 *s;
1765
Dave Barach3117ad82019-02-04 17:41:29 -05001766 s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
Dave Barach9c8cfd32019-02-03 10:44:47 -05001767 s_v1->anomaly_threshold_stddevs);
1768
1769 for (i = 0; i < vec_len (s_v1->means); i++) {
Dave Barach3117ad82019-02-04 17:41:29 -05001770 if (s_v1->matches[i] > 0)
1771 s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
1772 s_v1->mins[i], s_v1->maxes[i],
1773 s_v1->means[i],
1774 s_v1->means[i]+s_v1->two_stddevs[i]);
1775 else
1776 s = format (s, "{no match} ");
Dave Barach9c8cfd32019-02-03 10:44:47 -05001777 }
1778
1779 message_line ((char *)s);
1780 vec_free (s);
1781
1782 s_srchindex = index;
1783 pid_index = ep->pid->pid_index;
1784
1785 /* Need a vertical scroll? */
1786 if ((pid_index < s_v1->first_pid_index) ||
1787 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1788 if (pid_index > (g_npids - s_v1->npids))
1789 pid_index = (g_npids - s_v1->npids);
1790 s_v1->first_pid_index = pid_index;
1791 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1792 (gdouble)s_v1->first_pid_index;
1793 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1794 full_redisplay = TRUE;
1795 }
1796
1797 /* Need a horizontal scroll? */
1798 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1799 current_width = (s_v1->maxvistime - s_v1->minvistime);
1800 if (ep->time < ((current_width+1) / 2)) {
1801 s_v1->minvistime = 0ll;
1802 s_v1->maxvistime = current_width;
1803 } else {
1804 s_v1->minvistime = ep->time - ((current_width+1)/2);
1805 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1806 }
1807 recompute_hscrollbar();
1808 full_redisplay = TRUE;
1809 }
1810 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1811 full_redisplay = TRUE;
1812
1813 if (full_redisplay)
1814 view1_display_when_idle();
1815
1816 return(TRUE);
1817 }
1818 }
1819 sprintf (tmpbuf, "Search for an anomalous event %ld failed...\n",
1820 s_anomalycode);
1821 message_line(tmpbuf);
1822 s_srchfail_up = TRUE;
1823 return(TRUE);
1824}
1825
1826/****************************************************************************
1827* anomaly_search_callback
1828****************************************************************************/
1829
1830boolean anomaly_search_callback (char *s)
1831{
1832 ulong new_anomalycode;
1833
1834 /* No events yet? Act like the search worked, to avoid a loop */
1835 if (g_nevents == 0)
1836 return(TRUE);
1837
1838 new_anomalycode = atol(s);
1839
1840 if (new_anomalycode == 0)
1841 return(FALSE);
1842
1843 if (new_anomalycode != s_anomalycode ||
1844 vec_len (s_v1->matches) == 0) {
1845 s_anomalycode = new_anomalycode;
1846 if (anomaly_statistics_init()) {
1847 u8 *s;
1848
1849 s = format (0, "Search for an anomalous event %ld failed...\n",
1850 s_anomalycode);
1851 message_line ((char *) s);
1852 vec_free (s);
1853 return (TRUE);
1854 }
1855 }
1856 return(anomaly_search_internal());
1857}
1858
1859/****************************************************************************
1860* anomaly_threshold_callback
1861****************************************************************************/
1862
1863boolean anomaly_threshold_callback (char *s)
1864{
1865 f64 new_threshold;
1866
1867 /* No events yet? Act like the search worked, to avoid a loop */
1868 if (g_nevents == 0)
1869 return(TRUE);
1870
1871 new_threshold = atof (s);
1872
1873 if (new_threshold == 0.0 || new_threshold > 10.0)
1874 return(FALSE);
1875
1876 s_v1->anomaly_threshold_stddevs = new_threshold;
1877
1878 vec_reset_length (s_v1->means);
1879 vec_reset_length (s_v1->matches);
1880 vec_reset_length (s_v1->variances);
1881 vec_reset_length (s_v1->two_stddevs);
1882 return (TRUE);
1883}
1884
Dave Barach52642c32016-02-11 19:28:19 -05001885/****************************************************************************
1886* event_search
1887****************************************************************************/
1888
1889static void event_search (void)
1890{
1891 modal_dialog ("Event Search: Please Enter Event Code",
1892 "Invalid: Please Reenter Event Code", NULL,
1893 event_search_callback);
1894}
1895
1896/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05001897* anomaly_search
1898****************************************************************************/
1899
1900static void anomaly_search (void)
1901{
1902 modal_dialog ("Anomaly Search: Please Enter Event Code",
1903 "Invalid: Please Reenter Event Code", NULL,
1904 anomaly_search_callback);
1905}
1906
1907/****************************************************************************
1908* anomaly_threshold
1909****************************************************************************/
1910
1911static void anomaly_threshold (void)
1912{
1913 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1914 "Invalid: Please Reenter Threshold in Standard Deviations",
1915 NULL, anomaly_threshold_callback);
1916}
1917
1918/****************************************************************************
Dave Barach52642c32016-02-11 19:28:19 -05001919* init_track_colors
1920****************************************************************************/
1921static void init_track_colors(void)
1922{
1923 int i;
1924 unsigned hash;
1925 char *label_char;
1926 unsigned RGB[3];
1927 gboolean dont_care[g_npids];
1928
1929 /*
1930 * If we've already allocated the colors once, then in theory we should
1931 * just be able to re-order the GCs already created to match the new track
1932 * order; the track -> color mapping doesn't currently change at runtime.
1933 * However, it's easier just to allocate everything from fresh. As a nod in
1934 * the direction of politeness towards our poor abused X server, we at
1935 * least mop up the previously allocated GCs first, although in practice
Dave Barach9c8cfd32019-02-03 10:44:47 -05001936 * even omitting this didn't seem to cause a problem.
Dave Barach52642c32016-02-11 19:28:19 -05001937 */
1938 if (s_color != NULL ) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05001939 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
Dave Barach52642c32016-02-11 19:28:19 -05001940 s_color, g_npids);
Dave Barachb7b92992018-10-17 10:38:51 -04001941 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001942 } else {
1943 /*
1944 * First time through: allocate the array to hold the GCs.
1945 */
Dave Barach2c35e582017-04-03 10:22:17 -04001946 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
Dave Barach52642c32016-02-11 19:28:19 -05001947 }
1948
1949 /*
1950 * Go through and assign a color for each track.
1951 */
Dave Barach2c35e582017-04-03 10:22:17 -04001952 /* Setup entry 0 in the colormap as pure red (for selection) */
1953 s_color[0] = fg_red;
1954
1955 for (i = 1; i < g_npids; i++) {
Dave Barach52642c32016-02-11 19:28:19 -05001956 /*
1957 * We compute the color from a hash of the thread name. That way we get
1958 * a distribution of different colors, and the same thread has the same
1959 * color across multiple data sets. Unfortunately, even though the
1960 * process name and thread id are invariant across data sets, the
1961 * process id isn't, so we want to exclude that from the hash. Since
1962 * the pid appears in parentheses after the process name and tid, we
1963 * can just stop at the '(' character.
1964 *
1965 * We could create a substring and use the CLIB Jenkins hash, but given
1966 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1967 * just as good, and it's easiest just to compute it inline.
1968 */
1969 label_char = get_track_label(g_pids[i].pid_value);
1970 hash = 0;
1971 while (*label_char != '\0' && *label_char != '(') {
1972 hash = hash * 33 + *label_char++;
1973 }
1974 hash += hash >> 5; /* even out the lower order bits a touch */
1975
1976 /*
1977 * OK, now we have our hash. We get the color by using the first three
1978 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1979 * and then use the fourth byte to choose one of R, G, B and mask this
1980 * one down. This ensures the color can't be too close to white and
1981 * therefore hard to see.
1982 *
1983 * We also drop the top bit of the green, since bright green on its own
1984 * is hard to see against white. Generally we err on the side of
1985 * keeping it dark, rather than using the full spectrum of colors. This
1986 * does result in something of a preponderance of muddy colors and a
1987 * bit of a lack of cheery bright ones, but at least you can read
1988 * everything. It would be nice to do better.
1989 */
1990 RGB[0] = (hash & 0xff000000) >> 16;
1991 RGB[1] = (hash & 0x007f0000) >> 8;
1992 RGB[2] = (hash & 0x0000ff00);
1993 RGB[hash % 3] &= 0x1fff;
1994
1995 {
1996 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1997 s_color[i] = color;
1998 g_pids[i].color_index = i;
1999 }
2000 }
2001
2002 /*
2003 * Actually allocate the colors in one bulk operation. We ignore the return
2004 * values.
2005 */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002006 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
Dave Barach2c35e582017-04-03 10:22:17 -04002007 s_color, g_npids+1, FALSE, TRUE, dont_care);
Dave Barach52642c32016-02-11 19:28:19 -05002008}
2009
2010
2011/****************************************************************************
2012* chase_event_etc
2013* Reorder the pid_index fields so the viewer "chases" the last selected
2014* event.
2015****************************************************************************/
2016
2017static void chase_event_etc(enum chase_mode mode)
2018{
2019 pid_sort_t *psp, *new_pidvec;
2020 pid_data_t *pp;
2021 event_t *ep;
2022 int pids_mapped;
2023 ulong code_to_chase;
2024 ulong datum_to_chase;
2025 ulong pid_to_chase;
2026 int i;
2027 int winner;
2028
2029 if (!s_last_selected_event) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002030 infobox("No selected event",
Dave Barach52642c32016-02-11 19:28:19 -05002031 "\nPlease select an event and try again...\n");
2032 return;
2033 }
2034
2035 /* Clear all index assignments */
2036 psp = g_pids;
2037 for (i = 0; i < g_npids; i++) {
2038 pp = psp->pid;
2039 pp->pid_index = 0xFFFFFFFF;
2040 psp++;
2041 }
2042
2043 ep = s_last_selected_event;
2044 code_to_chase = ep->code;
2045 datum_to_chase = ep->datum;
2046 pid_to_chase = ep->pid->pid_value;
2047 pids_mapped = 0;
Dave Baracha8ed6bd2017-04-04 08:00:23 -04002048 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05002049
2050 while (1) {
2051 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2052 if (ep >= g_events + g_nevents)
2053 break;
2054 } else {
2055 if (ep < g_events)
2056 break;
2057 }
2058
2059 winner = 0;
2060 switch(mode) {
2061 case CHASE_EVENT:
2062 if (ep->code == code_to_chase) {
2063 winner = 1;
2064 }
2065 break;
2066
2067 case CHASE_DATUM:
2068 if (ep->datum == datum_to_chase) {
2069 winner = 1;
2070 }
2071 break;
2072
2073 case CHASE_TRACK:
2074 if (ep->pid->pid_value == pid_to_chase) {
2075 winner = 1;
2076 }
2077 break;
2078
2079 default:
2080 infobox("BUG", "unknown mode in chase_event_etc\n");
2081 break;
2082 }
2083
2084 if (winner) {
2085 if (ep->pid->pid_index == 0xFFFFFFFF) {
2086 ep->pid->pid_index = pids_mapped;
2087 new_pidvec[pids_mapped].pid = ep->pid;
2088 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2089 new_pidvec[pids_mapped].color_index = 0;
2090 pids_mapped++;
2091 if (pids_mapped == g_npids)
2092 break;
2093 }
2094 }
2095 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2096 ep++;
2097 else
2098 ep--;
2099 }
2100
2101 /* Pass 2, first-to-last, to collect stragglers */
2102 ep = g_events;
2103
2104 while (ep < g_events + g_nevents) {
2105 if (ep->pid->pid_index == 0xFFFFFFFF) {
2106 ep->pid->pid_index = pids_mapped;
2107 new_pidvec[pids_mapped].pid = ep->pid;
2108 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2109 new_pidvec[pids_mapped].color_index = 0;
2110 pids_mapped++;
2111 if (pids_mapped == g_npids)
2112 break;
2113 }
2114 ep++;
2115 }
2116
2117 if (pids_mapped != g_npids) {
2118 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2119 }
2120
2121 g_free (g_pids);
2122 g_pids = new_pidvec;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002123
Dave Barach52642c32016-02-11 19:28:19 -05002124 /*
2125 * The new g_pids vector contains the "chase" sort, so we revert
Dave Barach9c8cfd32019-02-03 10:44:47 -05002126 * the pid_index mapping to an identity map
Dave Barach52642c32016-02-11 19:28:19 -05002127 */
2128 psp = g_pids;
2129
2130 for (i = 0; i < g_npids; i++) {
2131 pp = psp->pid;
2132 pp->pid_index = i;
2133 psp++;
2134 }
2135
2136 /* AutoScroll the PID axis so we show the first "chased" event */
2137 s_v1->first_pid_index = 0;
2138 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2139 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2140 init_track_colors();
2141 view1_display_when_idle();
2142}
2143
2144/****************************************************************************
2145* unchase_event_etc
2146* Copy g_original_pids to g_pids, revert index mapping
2147****************************************************************************/
2148static void unchase_event_etc(void)
2149{
2150 int i;
2151 pid_sort_t *psp;
2152 pid_data_t *pp;
2153
Dave Barach9c8cfd32019-02-03 10:44:47 -05002154 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05002155
2156 /* Fix the pid structure index mappings */
2157 psp = g_pids;
2158
2159 for (i = 0; i < g_npids; i++) {
2160 pp = psp->pid;
2161 pp->pid_index = i;
2162 psp++;
2163 }
2164
2165 /* Scroll PID axis to the top */
2166 s_v1->first_pid_index = 0;
2167 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2168 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2169 init_track_colors();
2170 view1_display_when_idle();
2171}
2172
2173/****************************************************************************
2174* print_ps_header
2175* To fit a reasonable-sized landscape mode plot onto letter-size paper,
2176* scale everything by .75.
2177****************************************************************************/
2178
2179static void print_ps_header (v1_geometry_t *vp, char *filename)
2180{
2181 time_t now;
2182
2183 now = time(0);
2184
2185 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2186 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2187 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2188 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2189 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2190 fprintf(s_printfp, "%%%%Origin: 0 0\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05002191 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
Dave Barach52642c32016-02-11 19:28:19 -05002192 vp->total_width);
2193 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2194 fprintf(s_printfp, "%%%%Pages: 1\n");
2195 fprintf(s_printfp, "%%%%Page: 1 1\n");
2196 fprintf(s_printfp, "%%%%EOF\n");
2197 fprintf(s_printfp, "/Times-Roman findfont\n");
2198 fprintf(s_printfp, "12 scalefont\n");
2199 fprintf(s_printfp, "setfont\n");
2200 fprintf(s_printfp, ".75 .75 scale\n");
2201}
2202
2203/****************************************************************************
2204* xrt
2205* Xcoordinate rotate and translate. We need to emit postscript that
2206* has a reasonable aspect ratio for printing. To do that, we rotate the
Dave Barach9c8cfd32019-02-03 10:44:47 -05002207* intended picture by 90 degrees, using the standard 2D rotation
Dave Barach52642c32016-02-11 19:28:19 -05002208* formula:
Dave Barach9c8cfd32019-02-03 10:44:47 -05002209*
Dave Barach52642c32016-02-11 19:28:19 -05002210* Xr = x*cos(theta) - y*sin(theta);
2211* Yr = x*sin(theta) + y*cos(theta);
2212*
2213* If we let theta = 90, this reduces to
2214* Xr = -y
2215* Yr = x
2216*
2217* Translate back to the origin in X by adding Ymax, yielding
2218* Xrt = Ymax - y
2219****************************************************************************/
2220
2221static inline int xrt(int x, int y)
2222{
2223 return (s_v1->total_height - y);
2224}
2225
2226static inline int yrt(int x, int y)
2227{
2228 return(x);
2229}
2230
2231/****************************************************************************
2232* print_screen_callback
2233****************************************************************************/
2234
2235static boolean print_screen_callback(char *filename)
2236{
2237 s_printfp = fopen (filename, "wt");
2238
2239 if (s_printfp == NULL)
2240 return(FALSE);
2241
2242 /*
2243 * This variable allows us to magically turn the view1 display
2244 * code into a print-driver, with a minimum of fuss. The idea is to
2245 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2246 * the required value, aka s_print_offset.
2247 * Make sure to fix g2.h if you mess here, or vice versa.
2248 */
2249 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2250
2251 print_ps_header(s_v1, filename);
2252
2253 display_pid_axis(s_v1);
2254 display_event_data(s_v1);
2255 display_time_axis(s_v1);
2256
2257 fclose (s_printfp);
2258 s_printfp = 0;
2259 s_print_offset = 0;
2260
2261 /* For tactile feedback */
2262 view1_display_when_idle();
2263 return(TRUE);
2264}
2265
Dave Barach2c35e582017-04-03 10:22:17 -04002266int event_time_cmp (const void *a, const void *b)
2267{
2268 const event_t *e1 = a;
2269 const event_t *e2 = b;
2270
2271 if (e1->time < e2->time)
2272 return -1;
2273 else if (e1->time > e2->time)
2274 return 1;
2275 return 0;
2276}
2277
2278/****************************************************************************
2279* slew_tracks
2280****************************************************************************/
2281static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2282{
2283 event_t *ep;
2284 pid_sort_t *pp;
2285 int pid_index;
2286 ulonglong delta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002287
Dave Barach2c35e582017-04-03 10:22:17 -04002288 delta = (ulonglong) (vp->last_time_interval);
2289
2290 /* Make sure we don't push events to the left of the big bang */
2291 if (which == SLEW_LEFT_BUTTON) {
2292 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2293 pid_index = ep->pid->pid_index;
2294 pp = (g_pids + pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002295
Dave Barach2c35e582017-04-03 10:22:17 -04002296 if (pp->selected) {
2297 if (ep->time < delta) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002298 infobox("Slew Range Error",
Dave Barach2c35e582017-04-03 10:22:17 -04002299 "\nCan't slew selected data left that far..."
2300 "\nEvents would preceed the Big Bang (t=0)...");
2301 goto out;
2302 }
2303 }
2304 }
2305 }
2306
2307 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2308 pid_index = ep->pid->pid_index;
2309 pp = (g_pids + pid_index);
2310
2311 if (pp->selected) {
2312 if (which == SLEW_LEFT_BUTTON)
2313 ep->time -= delta;
2314 else
2315 ep->time += delta;
2316 }
2317 }
2318
2319 /* Re-sort the events, to avoid screwing up the event display */
2320 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2321
2322 /* De-select tracks */
2323 deselect_tracks();
2324
2325out:
2326 view1_display_when_idle();
2327}
2328
Dave Barach52642c32016-02-11 19:28:19 -05002329/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05002330* view1_button_click_callback
Dave Barach52642c32016-02-11 19:28:19 -05002331****************************************************************************/
2332
2333static void view1_button_click_callback(GtkButton *item, gpointer data)
2334{
2335 enum view1_button_click click = (enum view1_button_click) data;
2336 event_t *ep;
2337 ulonglong event_incdec;
2338 ulonglong current_width;
2339 ulonglong zoom_delta;
2340
Dave Barach52642c32016-02-11 19:28:19 -05002341 current_width = s_v1->maxvistime - s_v1->minvistime;
2342 event_incdec = (current_width) / 3;
2343
2344 if (event_incdec == 0LL)
2345 event_incdec = 1;
2346
2347 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2348
2349 switch(click) {
2350 case TOP_BUTTON:
2351 /* First PID to top of window */
2352 s_v1->first_pid_index = 0;
2353 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2354 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2355 break;
2356
2357 case BOTTOM_BUTTON:
2358 s_v1->first_pid_index = g_npids - s_v1->npids;
2359 if (s_v1->first_pid_index < 0)
2360 s_v1->first_pid_index = 0;
2361 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2362 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2363 break;
2364
2365 case SNAP_BUTTON:
2366 add_snapshot();
2367 break;
2368
2369 case NEXT_BUTTON:
2370 next_snapshot();
2371 break;
2372
2373 case DEL_BUTTON:
2374 del_snapshot();
2375 break;
2376
2377 case CHASE_EVENT_BUTTON:
2378 chase_event_etc(CHASE_EVENT);
2379 break;
2380
2381 case CHASE_DATUM_BUTTON:
2382 chase_event_etc(CHASE_DATUM);
2383 break;
2384
2385 case CHASE_TRACK_BUTTON:
2386 chase_event_etc(CHASE_TRACK);
2387 break;
2388
2389 case UNCHASE_BUTTON:
2390 unchase_event_etc();
2391 break;
2392
2393 case START_BUTTON:
2394 start_button:
2395 s_v1->minvistime = 0LL;
2396 s_v1->maxvistime = current_width;
2397 recompute_hscrollbar();
2398 break;
2399
2400 case ZOOMIN_BUTTON:
2401 s_v1->minvistime += zoom_delta;
2402 s_v1->maxvistime -= zoom_delta;
2403 recompute_hscrollbar();
2404 break;
2405
2406 case SEARCH_AGAIN_BUTTON:
2407 if (s_srchcode) {
2408 event_search_internal();
2409 break;
2410 }
2411 /* NOTE FALLTHROUGH */
2412
2413 case SEARCH_BUTTON:
2414 event_search();
2415 break;
2416
Dave Barach9c8cfd32019-02-03 10:44:47 -05002417 case ANOMALY_THRESHOLD_BUTTON:
2418 anomaly_threshold();
2419 break;
2420
2421 case ANOMALY_NEXT_BUTTON:
2422 if (s_anomalycode) {
2423 anomaly_search_internal();
2424 break;
2425 }
2426 /* NOTE FALLTHROUGH */
2427
2428 case ANOMALY_BUTTON:
2429 anomaly_search();
2430 break;
2431
Dave Barach52642c32016-02-11 19:28:19 -05002432 case ZOOMOUT_BUTTON:
2433 if (zoom_delta == 0LL)
2434 zoom_delta = 1;
2435
2436 if (s_v1->minvistime >= zoom_delta) {
2437 s_v1->minvistime -= zoom_delta;
2438 s_v1->maxvistime += zoom_delta;
2439 } else {
2440 s_v1->minvistime = 0;
2441 s_v1->maxvistime += zoom_delta*2;
2442 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05002443
2444 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
Dave Barach52642c32016-02-11 19:28:19 -05002445 g_events[g_nevents-1].time * 9) {
2446 s_v1->minvistime = 0;
2447 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
Dave Baracha4bab9d2017-12-14 17:21:36 -05002448 /* Single event? Make window 1s wide... */
2449 if (g_nevents == 1)
Dave Barach9c8cfd32019-02-03 10:44:47 -05002450 s_v1->maxvistime = 1000000;
Dave Baracha4bab9d2017-12-14 17:21:36 -05002451
Dave Barach52642c32016-02-11 19:28:19 -05002452 }
2453 recompute_hscrollbar();
2454 break;
2455
2456 case END_BUTTON:
2457 ep = (g_events + g_nevents - 1);
2458 s_v1->maxvistime = ep->time + event_incdec/3;
2459 s_v1->minvistime = s_v1->maxvistime - current_width;
2460 if (s_v1->minvistime > s_v1->maxvistime)
2461 goto start_button;
2462 recompute_hscrollbar();
2463 break;
2464
2465 case MORE_TRACES_BUTTON:
2466 /* Reduce the strip height to fit more traces on screen */
2467 s_v1->strip_height -= 1;
2468
2469 if (s_v1->strip_height < 1) {
2470 s_v1->strip_height = 1;
2471 }
2472
2473 /* Recalculate the number of strips on the screen */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002474 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05002475 s_v1->strip_height;
2476 recompute_vscrollbar();
2477 break;
2478
2479 case LESS_TRACES_BUTTON:
2480 /* Increase the strip height to fit fewer on the screen */
2481 s_v1->strip_height += 1;
2482 if (s_v1->strip_height > 80) {
2483 s_v1->strip_height = 80;
2484 }
2485
2486 /* Recalculate the number of strips on the screen */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002487 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05002488 s_v1->strip_height;
2489 recompute_vscrollbar();
2490 break;
2491
2492 case FORWARD_BUTTON:
2493 srch_chase_dir = SRCH_CHASE_FORWARD;
2494 gtk_widget_hide (s_view1_forward_button);
2495 gtk_widget_show (s_view1_backward_button);
2496 break;
2497
2498 case BACKWARD_BUTTON:
2499 srch_chase_dir = SRCH_CHASE_BACKWARD;
2500 gtk_widget_show (s_view1_forward_button);
2501 gtk_widget_hide (s_view1_backward_button);
2502 break;
2503
2504 case SUMMARY_BUTTON:
2505 summary_mode = TRUE;
2506 gtk_widget_hide (s_view1_summary_button);
2507 gtk_widget_show (s_view1_nosummary_button);
2508 break;
2509
2510 case NOSUMMARY_BUTTON:
2511 summary_mode = FALSE;
2512 gtk_widget_show (s_view1_summary_button);
2513 gtk_widget_hide (s_view1_nosummary_button);
2514 break;
Dave Barach2c35e582017-04-03 10:22:17 -04002515
2516 case SLEW_LEFT_BUTTON:
2517 case SLEW_RIGHT_BUTTON:
2518 if (s_v1->last_time_interval < 10e-9) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002519 infobox("slew", "\nNo time interval set...\n");
Dave Barach2c35e582017-04-03 10:22:17 -04002520 break;
2521 }
2522 slew_tracks (s_v1, click);
2523 break;
Dave Barach52642c32016-02-11 19:28:19 -05002524 }
2525
2526 view1_display_when_idle();
2527}
2528
2529/****************************************************************************
2530* view1_print_callback
2531****************************************************************************/
2532
2533void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2534{
2535 modal_dialog("Print Screen (PostScript format) to file:",
2536 "Invalid file: Print Screen to file:",
2537 "g2.ps", print_screen_callback);
2538}
2539
2540/****************************************************************************
2541* view1_hscroll
2542****************************************************************************/
2543
2544static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2545{
2546 ulonglong current_width;
2547
2548 current_width = (s_v1->maxvistime - s_v1->minvistime);
2549
2550 s_v1->minvistime = (ulonglong)(adj->value);
2551 s_v1->maxvistime = s_v1->minvistime + current_width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002552
Dave Barach52642c32016-02-11 19:28:19 -05002553 view1_display_when_idle();
2554
2555#ifdef NOTDEF
2556 g_print ("adj->lower = %.2f\n", adj->lower);
2557 g_print ("adj->upper = %.2f\n", adj->upper);
2558 g_print ("adj->value = %.2f\n", adj->value);
2559 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2560 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2561 g_print ("adj->page_size = %.2f\n", adj->page_size);
2562#endif
2563}
2564
2565/****************************************************************************
2566* view1_vscroll
2567****************************************************************************/
2568
2569static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2570{
2571 s_v1->first_pid_index = (int)adj->value;
2572 view1_display_when_idle();
2573}
2574
2575void set_pid_ax_width(int width)
2576{
2577 s_v1->pid_ax_width = width;
2578 view1_display_when_idle();
2579}
2580
2581/****************************************************************************
2582* view1_init
2583****************************************************************************/
2584
2585void view1_init(void)
2586{
Dave Barach52642c32016-02-11 19:28:19 -05002587 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2588 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2589
2590 s_v1->pid_ax_width = 80;
2591 s_v1->time_ax_height = 80;
2592 s_v1->time_ax_spacing = 100;
2593 s_v1->strip_height = 25;
2594 s_v1->pop_offset = 20;
2595 s_v1->pid_ax_offset = 34;
2596 s_v1->event_offset = 40;
2597 s_v1->total_height = c_view1_draw_height;
2598 s_v1->total_width = c_view1_draw_width;
2599 s_v1->first_pid_index = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002600 s_v1->anomaly_threshold_stddevs =
2601 atof(getprop_default("anomaly_threshold_stddevs", "2.5"));
2602 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05002603 s_v1->strip_height;
2604
2605 s_v1->minvistime = 0;
2606 s_v1->maxvistime = 200;
2607
2608 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2609
2610 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2611
2612 da = gtk_drawing_area_new();
Dave Barach9c8cfd32019-02-03 10:44:47 -05002613 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
Dave Barach52642c32016-02-11 19:28:19 -05002614 c_view1_draw_height);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002615
Dave Barach52642c32016-02-11 19:28:19 -05002616#ifdef NOTDEF
2617 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2618 (GtkSignalFunc) motion_notify_event, NULL);
2619#endif
2620
2621 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2622 (GtkSignalFunc) expose_event, NULL);
2623
2624 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2625 (GtkSignalFunc) configure_event, NULL);
2626
2627 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2628 (GtkSignalFunc) button_press_event, NULL);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002629
Dave Barach52642c32016-02-11 19:28:19 -05002630 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2631 (GtkSignalFunc) button_press_event, NULL);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002632
Dave Barach52642c32016-02-11 19:28:19 -05002633 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2634 (GtkSignalFunc) button_press_event, NULL);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002635
2636 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2637 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
Dave Barach52642c32016-02-11 19:28:19 -05002638 | GDK_BUTTON_MOTION_MASK);
2639
2640
2641 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2642
2643 g_font = gdk_font_load ("8x13");
2644 if (g_font == NULL) {
2645 g_error("Couldn't load 8x13 font...\n");
2646 }
2647 gdk_font_ref(g_font);
2648
2649 /* PID axis menu */
2650 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2651
Dave Barach9c8cfd32019-02-03 10:44:47 -05002652 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
Dave Barach52642c32016-02-11 19:28:19 -05002653 0.0 /* minimum value */,
2654 2000.0 /* maximum value */,
Dave Barach9c8cfd32019-02-03 10:44:47 -05002655 0.1 /* step increment */,
2656 10.0/* page increment */,
Dave Barach52642c32016-02-11 19:28:19 -05002657 10.0/* page size */);
2658
2659 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2660
2661 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002662 GTK_SIGNAL_FUNC (view1_vscroll),
Dave Barach52642c32016-02-11 19:28:19 -05002663 (gpointer)s_view1_vscroll);
2664
2665 s_view1_topbutton = gtk_button_new_with_label("Top");
2666 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2667
2668 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002669 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002670 (gpointer) TOP_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002671
Dave Barach52642c32016-02-11 19:28:19 -05002672 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002673 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002674 (gpointer) BOTTOM_BUTTON);
2675
2676 /* More Traces button and Less Traces button */
2677 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2678 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2679 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002680 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002681 (gpointer) MORE_TRACES_BUTTON);
2682 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002683 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002684 (gpointer) LESS_TRACES_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002685
Dave Barach52642c32016-02-11 19:28:19 -05002686#ifdef NOTDEF
2687 /* Trick to bottom-justify the menu: */
2688 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2689 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2690 TRUE, FALSE, 0);
2691
2692#endif
Dave Barach9c8cfd32019-02-03 10:44:47 -05002693
Dave Barach52642c32016-02-11 19:28:19 -05002694 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2695 FALSE, FALSE, 0);
2696
2697 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2698 TRUE, TRUE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002699
Dave Barach52642c32016-02-11 19:28:19 -05002700 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2701 FALSE, FALSE, 0);
2702
2703 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2704 FALSE, FALSE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002705
Dave Barach52642c32016-02-11 19:28:19 -05002706 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2707 FALSE, FALSE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002708
Dave Barach52642c32016-02-11 19:28:19 -05002709 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2710 FALSE, FALSE, 0);
2711
2712 /* Time axis menu */
2713
2714 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002715
Dave Barach52642c32016-02-11 19:28:19 -05002716 s_view1_startbutton = gtk_button_new_with_label("Start");
2717
2718 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2719
2720 s_view1_searchbutton = gtk_button_new_with_label("Search");
Dave Barach52642c32016-02-11 19:28:19 -05002721 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2722
Dave Barach9c8cfd32019-02-03 10:44:47 -05002723 s_view1_anomalybutton = gtk_button_new_with_label("Anomaly");
2724 s_view1_anomalynextbutton = gtk_button_new_with_label("Next Anomaly");
2725 s_view1_anomalythresholdbutton =
2726 gtk_button_new_with_label ("Anomaly Threshold");
2727
Dave Barach52642c32016-02-11 19:28:19 -05002728 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2729
2730 s_view1_endbutton = gtk_button_new_with_label("End");
2731
2732 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002733 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002734 (gpointer) START_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002735
Dave Barach52642c32016-02-11 19:28:19 -05002736 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002737 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002738 (gpointer) ZOOMIN_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002739
Dave Barach52642c32016-02-11 19:28:19 -05002740 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002741 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002742 (gpointer) SEARCH_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002743
Dave Barach52642c32016-02-11 19:28:19 -05002744 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002745 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002746 (gpointer) SEARCH_AGAIN_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002747
2748 gtk_signal_connect (GTK_OBJECT(s_view1_anomalybutton), "clicked",
2749 GTK_SIGNAL_FUNC(view1_button_click_callback),
2750 (gpointer) ANOMALY_BUTTON);
2751
2752 gtk_signal_connect (GTK_OBJECT(s_view1_anomalynextbutton), "clicked",
2753 GTK_SIGNAL_FUNC(view1_button_click_callback),
2754 (gpointer) ANOMALY_NEXT_BUTTON);
2755
2756 gtk_signal_connect (GTK_OBJECT(s_view1_anomalythresholdbutton),
2757 "clicked", GTK_SIGNAL_FUNC(view1_button_click_callback),
2758 (gpointer) ANOMALY_THRESHOLD_BUTTON);
2759
Dave Barach52642c32016-02-11 19:28:19 -05002760 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002761 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002762 (gpointer) ZOOMOUT_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002763
Dave Barach52642c32016-02-11 19:28:19 -05002764 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002765 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002766 (gpointer) END_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002767
2768 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
Dave Barach52642c32016-02-11 19:28:19 -05002769 0.0 /* minimum value */,
2770 2000.0 /* maximum value */,
Dave Barach9c8cfd32019-02-03 10:44:47 -05002771 0.1 /* step increment */,
2772 10.0/* page increment */,
Dave Barach52642c32016-02-11 19:28:19 -05002773 10.0/* page size */);
2774
2775 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2776
2777 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002778 GTK_SIGNAL_FUNC (view1_hscroll),
Dave Barach52642c32016-02-11 19:28:19 -05002779 (gpointer)s_view1_hscroll);
2780
2781 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2782 FALSE, FALSE, 0);
2783
2784 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2785 TRUE, TRUE, 0);
2786
2787 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2788 FALSE, FALSE, 0);
2789
2790 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2791 FALSE, FALSE, 0);
2792
Dave Barach9c8cfd32019-02-03 10:44:47 -05002793 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalybutton,
2794 FALSE, FALSE, 0);
2795 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalynextbutton,
2796 FALSE, FALSE, 0);
Dave Barach52642c32016-02-11 19:28:19 -05002797 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2798 FALSE, FALSE, 0);
2799
2800 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2801 FALSE, FALSE, 0);
2802
2803 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2804 FALSE, FALSE, 0);
2805
Dave Barach9c8cfd32019-02-03 10:44:47 -05002806 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
Dave Barach52642c32016-02-11 19:28:19 -05002807 TRUE, TRUE, 0);
2808
2809 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2810 FALSE, FALSE, 0);
2811
2812
2813 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2814
2815 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2816
2817 s_view1_nextbutton = gtk_button_new_with_label("Next");
2818
2819 s_view1_delbutton = gtk_button_new_with_label("Del");
2820
2821 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2822
2823 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2824
2825 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2826
2827 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2828
2829 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2830 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2831
2832 s_view1_summary_button = gtk_button_new_with_label("Summary");
2833 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2834
Dave Barach2c35e582017-04-03 10:22:17 -04002835 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2836 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2837
Dave Barach52642c32016-02-11 19:28:19 -05002838 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002839 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002840 (gpointer) SNAP_BUTTON);
2841
2842 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002843 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002844 (gpointer) NEXT_BUTTON);
2845
2846 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002847 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002848 (gpointer) DEL_BUTTON);
2849
2850 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002851 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002852 (gpointer) CHASE_EVENT_BUTTON);
2853
2854 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002855 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002856 (gpointer) CHASE_DATUM_BUTTON);
2857
2858 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002859 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002860 (gpointer) CHASE_TRACK_BUTTON);
2861
2862 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002863 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002864 (gpointer) UNCHASE_BUTTON);
2865
2866 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002867 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002868 (gpointer) FORWARD_BUTTON);
2869
2870 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002871 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002872 (gpointer) BACKWARD_BUTTON);
2873
2874 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002875 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002876 (gpointer) SUMMARY_BUTTON);
2877
2878 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002879 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002880 (gpointer) NOSUMMARY_BUTTON);
2881
Dave Barach2c35e582017-04-03 10:22:17 -04002882 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002883 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach2c35e582017-04-03 10:22:17 -04002884 (gpointer) SLEW_LEFT_BUTTON);
2885
2886 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002887 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach2c35e582017-04-03 10:22:17 -04002888 (gpointer) SLEW_RIGHT_BUTTON);
2889
Dave Barach52642c32016-02-11 19:28:19 -05002890 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2891 FALSE, FALSE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002892
Dave Barach52642c32016-02-11 19:28:19 -05002893 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2894 FALSE, FALSE, 0);
2895
2896 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2897 FALSE, FALSE, 0);
2898
2899 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2900 FALSE, FALSE, 0);
2901
2902 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2903 FALSE, FALSE, 0);
2904
2905 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2906 FALSE, FALSE, 0);
2907
2908 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2909 FALSE, FALSE, 0);
2910
2911 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2912 FALSE, FALSE, 0);
2913
2914 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2915 FALSE, FALSE, 0);
2916
2917 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2918 FALSE, FALSE, 0);
2919
2920 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2921 FALSE, FALSE, 0);
2922
2923 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2924 FALSE, FALSE, 0);
2925
Dave Barach9c8cfd32019-02-03 10:44:47 -05002926 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
Dave Barach2c35e582017-04-03 10:22:17 -04002927 s_view1_time_slew_left_button,
2928 FALSE, FALSE, 0);
2929
Dave Barach9c8cfd32019-02-03 10:44:47 -05002930 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
Dave Barach2c35e582017-04-03 10:22:17 -04002931 s_view1_time_slew_right_button,
2932 FALSE, FALSE, 0);
2933
Dave Barach9c8cfd32019-02-03 10:44:47 -05002934 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2935 s_view1_anomalythresholdbutton,
2936 FALSE, FALSE, 0);
2937
Dave Barach52642c32016-02-11 19:28:19 -05002938 s_view1_label = gtk_label_new(NULL);
2939
2940 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2941 FALSE, FALSE, 0);
2942
2943 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2944 TRUE, TRUE, 0);
2945
2946 gtk_widget_show_all (s_view1_vbox);
2947 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2948 gtk_widget_grab_focus(da);
2949
2950 gtk_widget_hide (s_view1_forward_button);
2951 gtk_widget_hide (summary_mode ? s_view1_summary_button
2952 : s_view1_nosummary_button);
2953
Dave Barach9c8cfd32019-02-03 10:44:47 -05002954 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
Dave Barach52642c32016-02-11 19:28:19 -05002955 zi_height);
2956 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2957 zi_height);
2958
Dave Barach9c8cfd32019-02-03 10:44:47 -05002959 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
Dave Barach52642c32016-02-11 19:28:19 -05002960 zi_mask, &fg_black,
2961 &bg_white, zi_x_hot,
2962 zi_y_hot);
2963 gdk_pixmap_unref (zi_source);
2964 gdk_pixmap_unref (zi_mask);
2965
2966 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2967}
2968
2969/****************************************************************************
2970* line_print
2971****************************************************************************/
2972
2973void line_print (int x1, int y1, int x2, int y2)
2974{
2975 fprintf(s_printfp, "newpath\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05002976 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
Dave Barach52642c32016-02-11 19:28:19 -05002977 yrt(x1, s_v1->total_height - y1));
2978
2979 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2980 yrt (x2, s_v1->total_height - y2));
2981 fprintf(s_printfp, "1 setlinewidth\n");
2982 fprintf(s_printfp, "stroke\n");
2983}
2984
2985/****************************************************************************
2986* tbox_print
2987****************************************************************************/
2988GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2989 GdkRectangle *rp)
2990{
2991 if (function == TBOX_PRINT_BOXED) {
2992 rp->width -= 4;
2993 }
2994
2995 if ((function == TBOX_PRINT_BOXED) ||
2996 (function == TBOX_PRINT_EVENT)) {
2997
2998 fprintf(s_printfp, "newpath\n");
2999 fprintf(s_printfp, "0 setlinewidth\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05003000 fprintf(s_printfp, "%d %d moveto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003001 xrt(rp->x, s_v1->total_height - rp->y),
3002 yrt(rp->x, s_v1->total_height - rp->y));
Dave Barach9c8cfd32019-02-03 10:44:47 -05003003
3004 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003005 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
3006 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
3007
Dave Barach9c8cfd32019-02-03 10:44:47 -05003008 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003009 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
3010 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
3011
Dave Barach9c8cfd32019-02-03 10:44:47 -05003012 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003013 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
3014 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
3015
Dave Barach9c8cfd32019-02-03 10:44:47 -05003016 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003017 xrt(rp->x, s_v1->total_height - rp->y),
3018 yrt(rp->x, s_v1->total_height - rp->y));
3019
3020 fprintf(s_printfp, "stroke\n");
3021 }
3022
3023 if ((function == TBOX_PRINT_BOXED) ||
3024 (function == TBOX_PRINT_PLAIN)) {
3025
3026 fprintf(s_printfp, "newpath\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05003027 fprintf(s_printfp, "%d %d moveto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003028 xrt(x, s_v1->total_height - (y-2)),
3029 yrt(x, s_v1->total_height - (y-2)));
3030 fprintf(s_printfp, "gsave\n");
3031 fprintf(s_printfp, "90 rotate\n");
3032 fprintf(s_printfp, "(%s) show\n", s);
3033 fprintf(s_printfp, "grestore\n");
3034 }
3035
3036 return(rp);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003037}
Dave Barach52642c32016-02-11 19:28:19 -05003038
3039/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05003040* tbox - draws an optionally boxed string whose lower lefthand
Dave Barach52642c32016-02-11 19:28:19 -05003041* corner is at (x, y). As usual, Y is backwards.
3042****************************************************************************/
3043
3044GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
3045{
3046 static GdkRectangle update_rect;
3047 gint lbearing, rbearing, width, ascent, descent;
3048
3049 gdk_string_extents (g_font, s,
3050 &lbearing, &rbearing,
3051 &width, &ascent, &descent);
3052
3053 /*
3054 * If we have enough room to display full size events, then just
3055 * use the BOXED function instead of the EVENT function.
3056 */
3057 if (s_v1->strip_height > 9) {
3058 switch (function) {
3059 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
3060 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
3061 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
3062 default:
3063 break;
3064 /* Nothing */
3065 }
3066 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003067
Dave Barach52642c32016-02-11 19:28:19 -05003068 switch (function) {
3069 case TBOX_DRAW_BOXED:
3070 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
Dave Barach9c8cfd32019-02-03 10:44:47 -05003071 x, y - (ascent+descent+3), width + 2,
Dave Barach52642c32016-02-11 19:28:19 -05003072 ascent + descent + 3);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003073
Dave Barach52642c32016-02-11 19:28:19 -05003074 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
Dave Barach9c8cfd32019-02-03 10:44:47 -05003075 x, y - (ascent+descent+3), width + 2,
Dave Barach52642c32016-02-11 19:28:19 -05003076 ascent + descent + 3);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003077
Dave Barach52642c32016-02-11 19:28:19 -05003078 gdk_draw_string (pm, g_font, da->style->black_gc,
3079 x + 1, y - 1, (const gchar *)s);
3080 /* NOTE FALLTHROUGH */
3081 case TBOX_GETRECT_BOXED:
3082 update_rect.x = x;
3083 update_rect.y = y -(ascent+descent+3);
3084 update_rect.width = width + 3;
3085 update_rect.height = ascent + descent + 4;
3086 if (function == TBOX_DRAW_BOXED)
3087 gtk_widget_draw (da, &update_rect);
3088 break;
3089
3090 case TBOX_DRAW_EVENT:
3091 /* We have a small event to draw...no text */
3092 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3093 x, y - 1, 3, 3);
3094 /* NOTE FALLTHROUGH */
3095 case TBOX_GETRECT_EVENT:
3096 update_rect.x = x;
3097 update_rect.y = y - 1;
3098 update_rect.width = 4;
3099 update_rect.height = 4;
3100 if (function == TBOX_DRAW_EVENT)
3101 gtk_widget_draw (da, &update_rect);
3102 break;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003103
3104
Dave Barach52642c32016-02-11 19:28:19 -05003105 case TBOX_DRAW_PLAIN:
Dave Barach9c8cfd32019-02-03 10:44:47 -05003106
Dave Barach52642c32016-02-11 19:28:19 -05003107 gdk_draw_string (pm, g_font, da->style->black_gc,
3108 x + 1, y - 1, (const gchar *)s);
3109 /* NOTE FALLTHROUGH */
3110 case TBOX_GETRECT_PLAIN:
3111 update_rect.x = x;
3112 update_rect.y = y -(ascent+descent+1);
3113 update_rect.width = width;
3114 update_rect.height = ascent + descent;
3115 if (function == TBOX_DRAW_PLAIN)
3116 gtk_widget_draw (da, &update_rect);
3117 break;
3118
3119 case TBOX_PRINT_BOXED:
3120 update_rect.x = x;
3121 update_rect.y = y -(ascent+descent+3);
3122 update_rect.width = width + 3;
3123 update_rect.height = ascent + descent + 4;
3124 /* note fallthrough */
3125 case TBOX_PRINT_PLAIN:
3126 return(tbox_print(s, x, y, function, &update_rect));
3127
3128 case TBOX_PRINT_EVENT:
3129 /* We have a small event box to print...no text */
3130 update_rect.x = x;
3131 update_rect.y = y - 1;
3132 update_rect.width = 4;
3133 update_rect.height = 4;
3134 return(tbox_print(s, x, y, function, &update_rect));
3135 }
3136 return(&update_rect);
3137}
3138
3139/****************************************************************************
3140* line
3141*
3142* For lines there is a primitive batching facility, that doesn't update
3143* the drawing area until the batch is complete. This is handy for drawing
3144* the pid axis and for summary mode.
3145*
3146* line_batch_mode contains the state for this:
3147*
3148* BATCH_OFF: no batching, update for every line
3149* BATCH_NEW: just entered a batch, so initialize the area to update from
3150* scratch
3151* BATCH_EXISTING: have drawn at least one line in batch mode, so the update
3152* area should only be expanded from now on to include the
3153* union of the "rectangular hull" of all lines
3154****************************************************************************/
3155
3156static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
3157static int line_batch_count;
3158static int line_minx, line_miny, line_maxx, line_maxy;
3159
3160void line_batch_start (void)
3161{
3162 line_batch_mode = BATCH_NEW;
3163 line_batch_count = 0;
3164}
3165
3166void line_batch_end (void)
3167{
3168 GdkRectangle update_rect;
3169 if (line_batch_count > 0) {
3170 update_rect.x = line_minx;
3171 update_rect.y = line_miny;
3172 update_rect.width = (line_maxx - line_minx) + 1;
3173 update_rect.height = (line_maxy - line_miny) + 1;
3174 gtk_widget_draw (da, &update_rect);
3175 }
3176 line_batch_mode = BATCH_OFF;
3177}
3178
3179void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
3180{
3181 GdkRectangle update_rect;
3182 GdkGC *gc = NULL;
3183
3184 switch(function) {
3185 case LINE_DRAW_BLACK:
3186 gc = da->style->black_gc;
3187 break;
3188
3189 case LINE_DRAW_WHITE:
3190 gc = da->style->white_gc;
3191 break;
3192
3193 case LINE_PRINT:
3194 line_print (x1, y1, x2, y2);
3195 return;
3196 }
3197
3198 gdk_draw_line (pm, gc, x1, y1, x2, y2);
3199
3200 switch (line_batch_mode) {
3201 case BATCH_OFF:
3202 update_rect.x = x1;
3203 update_rect.y = y1;
3204 update_rect.width = (x2-x1) + 1;
3205 update_rect.height = (y2-y1) + 1;
3206 gtk_widget_draw (da, &update_rect);
3207 break;
3208
3209 case BATCH_NEW:
3210 line_minx = x1;
3211 line_maxx = x2;
3212 line_miny = y1;
3213 line_maxy = y2;
3214 line_batch_mode = BATCH_EXISTING;
3215 line_batch_count = 1;
3216 break;
3217
3218 case BATCH_EXISTING:
3219 if (line_minx > x1)
3220 line_minx = x1;
3221 if (line_miny > y1)
3222 line_miny = y1;
3223 if (line_maxx < x2)
3224 line_maxx = x2;
3225 if (line_maxy < y2)
3226 line_maxy = y2;
3227 line_batch_count++;
3228 break;
3229 }
3230}
3231
3232
3233/****************************************************************************
3234* display_pid_axis
3235****************************************************************************/
3236
3237static void display_pid_axis(v1_geometry_t *vp)
3238{
3239 int y, i, label_tick;
3240 int last_printed_y = -vp->strip_height;
3241 pid_sort_t *pp;
3242 int pid_index;
3243 char *label_fmt;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003244 char tmpbuf [128];
Dave Barach52642c32016-02-11 19:28:19 -05003245
3246 /* No pids yet? Outta here */
3247 if (g_pids == NULL)
3248 return;
3249
3250 line_batch_start();
3251
3252 for (i = 0; i < vp->npids; i++) {
3253 pid_index = vp->first_pid_index + i;
3254 if (pid_index >= g_npids)
3255 break;
3256
Dave Barach52642c32016-02-11 19:28:19 -05003257 pp = (g_pids + pid_index);
3258
Dave Barach2c35e582017-04-03 10:22:17 -04003259 set_color(pid_index);
3260
Dave Barach52642c32016-02-11 19:28:19 -05003261 label_fmt = get_track_label(pp->pid_value);
3262 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
3263
3264 y = i*vp->strip_height + vp->pid_ax_offset;
3265
3266 /*
3267 * Have we incremented enough space to have another label not
3268 * overlap the previous label?
3269 */
3270 if (y - last_printed_y > 9) {
3271 /* Draw label */
3272 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
3273
3274 last_printed_y = y;
3275
3276 /*
3277 * And let the line stick out a bit more to indicate this label
3278 * relates to the following line.
3279 */
3280 label_tick = 4;
3281 }
3282 else {
3283 label_tick = 0;
3284 }
3285
3286 /* Draw axis line, but only if the lines aren't too close together */
3287 if (vp->strip_height > 4) {
3288 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
3289 vp->total_width, y+4*s_print_offset,
3290 LINE_DRAW_BLACK+s_print_offset);
3291 }
3292 }
3293
3294 set_color(COLOR_DEFAULT);
3295 line_batch_end();
3296}
3297
3298/****************************************************************************
3299* view1_read_events_callback
3300* New event data just showed up, reset a few things.
3301****************************************************************************/
3302
3303void view1_read_events_callback(void)
3304{
3305 int max_vis_index;
3306
3307 s_v1->first_pid_index = 0;
3308
3309 max_vis_index = 300;
3310 if (max_vis_index > g_nevents)
3311 max_vis_index = g_nevents-1;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003312
Dave Barach52642c32016-02-11 19:28:19 -05003313 s_v1->minvistime = 0LL;
3314 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
Dave Baracha4bab9d2017-12-14 17:21:36 -05003315 /* Single event? Make the initial display 1s wide */
3316 if (g_nevents == 1)
3317 s_v1->maxvistime = 1000000;
Dave Barach52642c32016-02-11 19:28:19 -05003318 s_srchindex = 0;
3319 s_srchcode = 0;
3320 s_last_selected_event = 0;
3321
3322 init_track_colors();
3323
3324 recompute_hscrollbar();
3325 recompute_vscrollbar();
3326}
3327
3328/****************************************************************************
3329* display_event_data
3330****************************************************************************/
3331
3332static void display_event_data(v1_geometry_t *vp)
3333{
3334 int start_index;
3335 int pid_index;
3336 int x, y;
3337 event_t *ep;
3338 event_def_t *edp;
3339 double time_per_pixel;
3340 char tmpbuf[1024];
3341 GdkRectangle *print_rect;
3342 int *last_x_used;
3343
3344 /* Happens if one loads the event def header first, for example. */
3345 if (g_nevents == 0)
3346 return;
3347
3348 time_per_pixel = dtime_per_pixel(vp);
3349
3350 start_index = find_event_index (vp->minvistime);
3351
3352 /* Scrolled too far right? */
3353 if (start_index >= g_nevents)
3354 return;
3355
3356 ep = (g_events + start_index);
3357
3358 if (s_print_offset || summary_mode) {
3359 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3360 } else {
3361 last_x_used = NULL;
3362 }
3363
3364 line_batch_start();
3365
3366 while (ep < (g_events + g_nevents) &&
3367 (ep->time < vp->maxvistime)) {
3368 pid_index = ep->pid->pid_index;
3369 set_color(pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003370
Dave Barach52642c32016-02-11 19:28:19 -05003371 /* First filter: pid out of range */
3372 if ((pid_index < vp->first_pid_index) ||
3373 (pid_index >= vp->first_pid_index + vp->npids)) {
3374 ep++;
3375 continue;
3376 }
3377
3378 /* Second filter: event hidden */
3379 edp = find_event_definition (ep->code);
3380 if (!edp->selected) {
3381 ep++;
3382 continue;
3383 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003384
Dave Barach52642c32016-02-11 19:28:19 -05003385 /* Display it... */
3386
3387 pid_index -= vp->first_pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003388
Dave Barach52642c32016-02-11 19:28:19 -05003389 y = pid_index*vp->strip_height + vp->event_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003390
3391 x = vp->pid_ax_width +
Dave Barach52642c32016-02-11 19:28:19 -05003392 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3393
3394 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3395 ep++;
3396 continue;
3397 }
3398
3399 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3400 if (ep->flags & EVENT_FLAG_SELECT) {
3401 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3402#ifdef NOTDEF
3403 sprintf(tmpbuf, edp->name);
3404 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3405 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3406#endif
3407 } else {
3408 sprintf(tmpbuf, "SEARCH RESULT");
3409 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003410 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05003411 TBOX_DRAW_BOXED+s_print_offset);
3412 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3413 if (last_x_used != NULL)
3414 last_x_used[pid_index] = x + print_rect->width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003415 }
Dave Barach52642c32016-02-11 19:28:19 -05003416 if (summary_mode) {
3417 int delta = vp->strip_height / 3;
3418 if (delta < 1)
3419 delta = 1;
3420 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3421 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3422 last_x_used[pid_index] = x + 1;
3423 } else {
3424 sprintf(tmpbuf, "%ld", ep->code);
3425 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3426 if (last_x_used != NULL)
3427 last_x_used[pid_index] = x + print_rect->width;
3428 }
3429
3430 ep++;
3431 }
3432 if (last_x_used)
3433 g_free(last_x_used);
3434 line_batch_end();
3435 set_color(COLOR_DEFAULT);
3436}
3437
3438/****************************************************************************
3439* display_clear
3440****************************************************************************/
3441
3442static void display_clear(void)
3443{
3444 GdkRectangle update_rect;
3445
3446 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3447 0, 0, da->allocation.width,
3448 da->allocation.height);
3449
3450 update_rect.x = 0;
3451 update_rect.y = 0;
3452 update_rect.width = da->allocation.width;
3453 update_rect.height = da->allocation.height;
3454
3455 gtk_widget_draw (da, &update_rect);
3456}
3457
3458/****************************************************************************
3459* display_time_axis
3460****************************************************************************/
3461
3462static void display_time_axis(v1_geometry_t *vp)
3463{
3464 int x, y, i;
3465 int xoffset, nticks;
3466 char tmpbuf [128];
3467 double unit_divisor;
3468 double time;
3469 char *units;
3470 double time_per_pixel;
3471
3472 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3473
3474 x = vp->pid_ax_width;
3475
3476 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3477
3478 time_per_pixel = dtime_per_pixel(vp);
3479
3480 units = "ns";
3481 unit_divisor = 1.00;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003482
Dave Barach52642c32016-02-11 19:28:19 -05003483 if ((vp->maxvistime / unit_divisor) > 1000) {
3484 units = "us";
3485 unit_divisor = 1000.00;
3486 }
3487
3488 if ((vp->maxvistime / unit_divisor) > 1000) {
3489 units = "ms";
3490 unit_divisor = 1000.00*1000.00;
3491 }
3492 if ((vp->maxvistime / unit_divisor) > 1000) {
3493 units = "s";
3494 unit_divisor = 1000.00*1000.00*1000.00;
3495 }
3496
3497 /* Draw line */
3498 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3499
3500 xoffset = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003501
Dave Barach52642c32016-02-11 19:28:19 -05003502 for (i = 0; i < nticks; i++) {
3503 /* Tick mark */
3504 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3505
3506 time = (double)(x + xoffset - vp->pid_ax_width);
3507 time *= time_per_pixel;
3508 time += (double)(vp->minvistime);
3509 time /= unit_divisor;
3510
3511 sprintf (tmpbuf, "%.2f%s", time, units);
3512
3513 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003514
Dave Barach52642c32016-02-11 19:28:19 -05003515 xoffset += vp->time_ax_spacing;
3516 }
3517}
3518
3519/****************************************************************************
3520* clear_scoreboard
3521* Forget about any temporary displays, they're gone now...
3522****************************************************************************/
3523
3524static void clear_scoreboard(void)
3525{
3526 s_result_up = FALSE;
3527}
3528
3529/****************************************************************************
3530* view1_display
3531****************************************************************************/
3532
3533void view1_display(void)
3534{
3535 display_clear();
3536 display_pid_axis(s_v1);
3537 display_event_data(s_v1);
3538 display_time_axis(s_v1);
3539 clear_scoreboard();
3540}
3541
3542static gint idle_tag;
3543
3544/****************************************************************************
3545* view1_display_eventually
3546****************************************************************************/
3547
3548static void view1_display_eventually(void)
3549{
3550 gtk_idle_remove(idle_tag);
3551 idle_tag = 0;
3552 view1_display();
3553}
3554
3555
3556/****************************************************************************
3557* view1_display_when_idle
3558****************************************************************************/
3559
3560void view1_display_when_idle(void)
3561{
3562 if (idle_tag == 0) {
3563 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3564 }
3565}
3566
3567/****************************************************************************
3568* view1_about
3569****************************************************************************/
3570
3571void view1_about (char *tmpbuf)
3572{
3573 int nsnaps;
3574 snapshot_t *snaps;
3575
3576 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3577 s_v1->minvistime, s_v1->maxvistime);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003578 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
Dave Barach52642c32016-02-11 19:28:19 -05003579 s_v1->strip_height);
3580
3581 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3582 nsnaps++;
3583 }
3584 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);
3585}