blob: a0cff900dbf91d1cc4e78869247e463361f2f23e [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;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001633 f64 fdata;
1634
1635 /* Gather summary statistics... */
1636 ep = g_events;
1637
1638 vec_reset_length (s_v1->means);
1639 vec_reset_length (s_v1->matches);
1640 vec_reset_length (s_v1->variances);
1641 vec_reset_length (s_v1->two_stddevs);
Dave Barach3117ad82019-02-04 17:41:29 -05001642 vec_reset_length (s_v1->mins);
1643 vec_reset_length (s_v1->maxes);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001644
1645 for (i = 0; i < g_nevents; i++) {
1646 if (ep->code != s_anomalycode) {
1647 ep++;
1648 continue;
1649 }
1650 pid = ep->pid;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001651 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
Dave Barach3117ad82019-02-04 17:41:29 -05001652 vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
1653 vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
1654 vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001655 eep = get_clib_event (ep->datum);
1656 data = clib_mem_unaligned (eep->data, u32);
1657 fdata = data;
1658 s_v1->means[pid->pid_index] += fdata;
1659 s_v1->matches[pid->pid_index] += 1;
Dave Barach3117ad82019-02-04 17:41:29 -05001660 /* First data point? set min, max */
1661 if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
1662 s_v1->mins[pid->pid_index] = fdata;
1663 s_v1->maxes[pid->pid_index] = fdata;
1664 } else {
1665 s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
1666 fdata : s_v1->mins[pid->pid_index];
1667 s_v1->maxes[pid->pid_index] =
1668 (fdata > s_v1->maxes[pid->pid_index]) ?
1669 fdata : s_v1->maxes[pid->pid_index];
1670 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05001671 ep++;
1672 }
1673 if (vec_len (s_v1->matches) == 0)
1674 return -1;
1675
1676 /* Compute s_v1->means */
1677 for (i = 0; i < vec_len (s_v1->means); i++)
1678 s_v1->means[i] = s_v1->matches[i]
1679 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1680
1681 /* Compute s_v1->variances */
1682 ep = g_events;
1683 for (i = 0; i < g_nevents; i++) {
1684 if (ep->code != s_anomalycode) {
1685 ep++;
1686 continue;
1687 }
1688 pid = ep->pid;
1689 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1690 eep = get_clib_event (ep->datum);
1691 data = clib_mem_unaligned (eep->data, u32);
1692 fdata = data;
1693 s_v1->variances[pid->pid_index] +=
1694 (fdata - s_v1->means[pid->pid_index])
1695 * (fdata - s_v1->means[pid->pid_index]);
1696 ep++;
1697 }
1698
1699 /* Normalize variances */
1700 for (i = 0; i < vec_len (s_v1->variances); i++)
1701 s_v1->variances[i] = s_v1->matches[i]
1702 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1703
1704 /* Compute the anomaly threshold, by default 2.5*stddev */
1705 for (i = 0; i < vec_len (s_v1->variances); i++)
1706 vec_add1 (s_v1->two_stddevs,
1707 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1708 return 0;
1709}
1710
1711/****************************************************************************
1712* anomaly_search_internal
1713* This routine searches forward from s_srchindex, looking for s_srchcode;
1714* wraps at the end of the buffer.
1715****************************************************************************/
1716
1717boolean anomaly_search_internal (void)
1718{
1719 elog_event_t *eep;
1720 u32 data;
1721 event_t *ep;
1722 pid_data_t *pid;
1723 int i;
1724 int index;
1725 int pid_index;
1726 boolean full_redisplay = FALSE;
1727 ulonglong current_width;
1728 char tmpbuf [64];
1729 f64 fdata;
1730
1731 if (vec_len (s_v1->matches) == 0)
1732 anomaly_statistics_init();
1733
1734 ep = (g_events + s_srchindex);
1735 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1736
1737 /*
1738 * If the user rearranged the screen, start from the minimum
1739 * visible time
1740 */
1741 if (ep->time < s_v1->minvistime)
1742 s_srchindex = find_event_index (s_v1->minvistime);
1743
1744 for (i = 1; i <= g_nevents; i++) {
1745 index = (i + s_srchindex) % g_nevents;
1746
1747 ep = (g_events + index);
1748 if (ep->code != s_anomalycode)
1749 continue;
1750 pid = ep->pid;
1751
1752 eep = get_clib_event (ep->datum);
1753 data = clib_mem_unaligned (eep->data, u32);
1754 fdata = data;
1755
1756 /*
1757 * Found an anomaly? Define an anomaly as a datum
1758 * greater than 2*stddev above average.
1759 */
1760 if ((fdata - s_v1->means[pid->pid_index]) >
1761 s_v1->two_stddevs[pid->pid_index]) {
1762 u8 *s;
1763
Dave Barach3117ad82019-02-04 17:41:29 -05001764 s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
Dave Barach9c8cfd32019-02-03 10:44:47 -05001765 s_v1->anomaly_threshold_stddevs);
1766
1767 for (i = 0; i < vec_len (s_v1->means); i++) {
Dave Barach3117ad82019-02-04 17:41:29 -05001768 if (s_v1->matches[i] > 0)
1769 s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
1770 s_v1->mins[i], s_v1->maxes[i],
1771 s_v1->means[i],
1772 s_v1->means[i]+s_v1->two_stddevs[i]);
1773 else
1774 s = format (s, "{no match} ");
Dave Barach9c8cfd32019-02-03 10:44:47 -05001775 }
1776
1777 message_line ((char *)s);
1778 vec_free (s);
1779
1780 s_srchindex = index;
1781 pid_index = ep->pid->pid_index;
1782
1783 /* Need a vertical scroll? */
1784 if ((pid_index < s_v1->first_pid_index) ||
1785 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1786 if (pid_index > (g_npids - s_v1->npids))
1787 pid_index = (g_npids - s_v1->npids);
1788 s_v1->first_pid_index = pid_index;
1789 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1790 (gdouble)s_v1->first_pid_index;
1791 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1792 full_redisplay = TRUE;
1793 }
1794
1795 /* Need a horizontal scroll? */
1796 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1797 current_width = (s_v1->maxvistime - s_v1->minvistime);
1798 if (ep->time < ((current_width+1) / 2)) {
1799 s_v1->minvistime = 0ll;
1800 s_v1->maxvistime = current_width;
1801 } else {
1802 s_v1->minvistime = ep->time - ((current_width+1)/2);
1803 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1804 }
1805 recompute_hscrollbar();
1806 full_redisplay = TRUE;
1807 }
1808 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1809 full_redisplay = TRUE;
1810
1811 if (full_redisplay)
1812 view1_display_when_idle();
1813
1814 return(TRUE);
1815 }
1816 }
1817 sprintf (tmpbuf, "Search for an anomalous event %ld failed...\n",
1818 s_anomalycode);
1819 message_line(tmpbuf);
1820 s_srchfail_up = TRUE;
1821 return(TRUE);
1822}
1823
1824/****************************************************************************
1825* anomaly_search_callback
1826****************************************************************************/
1827
1828boolean anomaly_search_callback (char *s)
1829{
1830 ulong new_anomalycode;
1831
1832 /* No events yet? Act like the search worked, to avoid a loop */
1833 if (g_nevents == 0)
1834 return(TRUE);
1835
1836 new_anomalycode = atol(s);
1837
1838 if (new_anomalycode == 0)
1839 return(FALSE);
1840
1841 if (new_anomalycode != s_anomalycode ||
1842 vec_len (s_v1->matches) == 0) {
1843 s_anomalycode = new_anomalycode;
1844 if (anomaly_statistics_init()) {
1845 u8 *s;
1846
1847 s = format (0, "Search for an anomalous event %ld failed...\n",
1848 s_anomalycode);
1849 message_line ((char *) s);
1850 vec_free (s);
1851 return (TRUE);
1852 }
1853 }
1854 return(anomaly_search_internal());
1855}
1856
1857/****************************************************************************
1858* anomaly_threshold_callback
1859****************************************************************************/
1860
1861boolean anomaly_threshold_callback (char *s)
1862{
1863 f64 new_threshold;
1864
1865 /* No events yet? Act like the search worked, to avoid a loop */
1866 if (g_nevents == 0)
1867 return(TRUE);
1868
1869 new_threshold = atof (s);
1870
1871 if (new_threshold == 0.0 || new_threshold > 10.0)
1872 return(FALSE);
1873
1874 s_v1->anomaly_threshold_stddevs = new_threshold;
1875
1876 vec_reset_length (s_v1->means);
1877 vec_reset_length (s_v1->matches);
1878 vec_reset_length (s_v1->variances);
1879 vec_reset_length (s_v1->two_stddevs);
1880 return (TRUE);
1881}
1882
Dave Barach52642c32016-02-11 19:28:19 -05001883/****************************************************************************
1884* event_search
1885****************************************************************************/
1886
1887static void event_search (void)
1888{
1889 modal_dialog ("Event Search: Please Enter Event Code",
1890 "Invalid: Please Reenter Event Code", NULL,
1891 event_search_callback);
1892}
1893
1894/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05001895* anomaly_search
1896****************************************************************************/
1897
1898static void anomaly_search (void)
1899{
1900 modal_dialog ("Anomaly Search: Please Enter Event Code",
1901 "Invalid: Please Reenter Event Code", NULL,
1902 anomaly_search_callback);
1903}
1904
1905/****************************************************************************
1906* anomaly_threshold
1907****************************************************************************/
1908
1909static void anomaly_threshold (void)
1910{
1911 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1912 "Invalid: Please Reenter Threshold in Standard Deviations",
1913 NULL, anomaly_threshold_callback);
1914}
1915
1916/****************************************************************************
Dave Barach52642c32016-02-11 19:28:19 -05001917* init_track_colors
1918****************************************************************************/
1919static void init_track_colors(void)
1920{
1921 int i;
1922 unsigned hash;
1923 char *label_char;
1924 unsigned RGB[3];
1925 gboolean dont_care[g_npids];
1926
1927 /*
1928 * If we've already allocated the colors once, then in theory we should
1929 * just be able to re-order the GCs already created to match the new track
1930 * order; the track -> color mapping doesn't currently change at runtime.
1931 * However, it's easier just to allocate everything from fresh. As a nod in
1932 * the direction of politeness towards our poor abused X server, we at
1933 * least mop up the previously allocated GCs first, although in practice
Dave Barach9c8cfd32019-02-03 10:44:47 -05001934 * even omitting this didn't seem to cause a problem.
Dave Barach52642c32016-02-11 19:28:19 -05001935 */
1936 if (s_color != NULL ) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05001937 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
Dave Barach52642c32016-02-11 19:28:19 -05001938 s_color, g_npids);
Dave Barachb7b92992018-10-17 10:38:51 -04001939 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001940 } else {
1941 /*
1942 * First time through: allocate the array to hold the GCs.
1943 */
Dave Barach2c35e582017-04-03 10:22:17 -04001944 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
Dave Barach52642c32016-02-11 19:28:19 -05001945 }
1946
1947 /*
1948 * Go through and assign a color for each track.
1949 */
Dave Barach2c35e582017-04-03 10:22:17 -04001950 /* Setup entry 0 in the colormap as pure red (for selection) */
1951 s_color[0] = fg_red;
1952
1953 for (i = 1; i < g_npids; i++) {
Dave Barach52642c32016-02-11 19:28:19 -05001954 /*
1955 * We compute the color from a hash of the thread name. That way we get
1956 * a distribution of different colors, and the same thread has the same
1957 * color across multiple data sets. Unfortunately, even though the
1958 * process name and thread id are invariant across data sets, the
1959 * process id isn't, so we want to exclude that from the hash. Since
1960 * the pid appears in parentheses after the process name and tid, we
1961 * can just stop at the '(' character.
1962 *
1963 * We could create a substring and use the CLIB Jenkins hash, but given
1964 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1965 * just as good, and it's easiest just to compute it inline.
1966 */
1967 label_char = get_track_label(g_pids[i].pid_value);
1968 hash = 0;
1969 while (*label_char != '\0' && *label_char != '(') {
1970 hash = hash * 33 + *label_char++;
1971 }
1972 hash += hash >> 5; /* even out the lower order bits a touch */
1973
1974 /*
1975 * OK, now we have our hash. We get the color by using the first three
1976 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1977 * and then use the fourth byte to choose one of R, G, B and mask this
1978 * one down. This ensures the color can't be too close to white and
1979 * therefore hard to see.
1980 *
1981 * We also drop the top bit of the green, since bright green on its own
1982 * is hard to see against white. Generally we err on the side of
1983 * keeping it dark, rather than using the full spectrum of colors. This
1984 * does result in something of a preponderance of muddy colors and a
1985 * bit of a lack of cheery bright ones, but at least you can read
1986 * everything. It would be nice to do better.
1987 */
1988 RGB[0] = (hash & 0xff000000) >> 16;
1989 RGB[1] = (hash & 0x007f0000) >> 8;
1990 RGB[2] = (hash & 0x0000ff00);
1991 RGB[hash % 3] &= 0x1fff;
1992
1993 {
1994 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1995 s_color[i] = color;
1996 g_pids[i].color_index = i;
1997 }
1998 }
1999
2000 /*
2001 * Actually allocate the colors in one bulk operation. We ignore the return
2002 * values.
2003 */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002004 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
Dave Barach2c35e582017-04-03 10:22:17 -04002005 s_color, g_npids+1, FALSE, TRUE, dont_care);
Dave Barach52642c32016-02-11 19:28:19 -05002006}
2007
2008
2009/****************************************************************************
2010* chase_event_etc
2011* Reorder the pid_index fields so the viewer "chases" the last selected
2012* event.
2013****************************************************************************/
2014
2015static void chase_event_etc(enum chase_mode mode)
2016{
2017 pid_sort_t *psp, *new_pidvec;
2018 pid_data_t *pp;
2019 event_t *ep;
2020 int pids_mapped;
2021 ulong code_to_chase;
2022 ulong datum_to_chase;
2023 ulong pid_to_chase;
2024 int i;
2025 int winner;
2026
2027 if (!s_last_selected_event) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002028 infobox("No selected event",
Dave Barach52642c32016-02-11 19:28:19 -05002029 "\nPlease select an event and try again...\n");
2030 return;
2031 }
2032
2033 /* Clear all index assignments */
2034 psp = g_pids;
2035 for (i = 0; i < g_npids; i++) {
2036 pp = psp->pid;
2037 pp->pid_index = 0xFFFFFFFF;
2038 psp++;
2039 }
2040
2041 ep = s_last_selected_event;
2042 code_to_chase = ep->code;
2043 datum_to_chase = ep->datum;
2044 pid_to_chase = ep->pid->pid_value;
2045 pids_mapped = 0;
Dave Baracha8ed6bd2017-04-04 08:00:23 -04002046 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05002047
2048 while (1) {
2049 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2050 if (ep >= g_events + g_nevents)
2051 break;
2052 } else {
2053 if (ep < g_events)
2054 break;
2055 }
2056
2057 winner = 0;
2058 switch(mode) {
2059 case CHASE_EVENT:
2060 if (ep->code == code_to_chase) {
2061 winner = 1;
2062 }
2063 break;
2064
2065 case CHASE_DATUM:
2066 if (ep->datum == datum_to_chase) {
2067 winner = 1;
2068 }
2069 break;
2070
2071 case CHASE_TRACK:
2072 if (ep->pid->pid_value == pid_to_chase) {
2073 winner = 1;
2074 }
2075 break;
2076
2077 default:
2078 infobox("BUG", "unknown mode in chase_event_etc\n");
2079 break;
2080 }
2081
2082 if (winner) {
2083 if (ep->pid->pid_index == 0xFFFFFFFF) {
2084 ep->pid->pid_index = pids_mapped;
2085 new_pidvec[pids_mapped].pid = ep->pid;
2086 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2087 new_pidvec[pids_mapped].color_index = 0;
2088 pids_mapped++;
2089 if (pids_mapped == g_npids)
2090 break;
2091 }
2092 }
2093 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2094 ep++;
2095 else
2096 ep--;
2097 }
2098
2099 /* Pass 2, first-to-last, to collect stragglers */
2100 ep = g_events;
2101
2102 while (ep < g_events + g_nevents) {
2103 if (ep->pid->pid_index == 0xFFFFFFFF) {
2104 ep->pid->pid_index = pids_mapped;
2105 new_pidvec[pids_mapped].pid = ep->pid;
2106 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2107 new_pidvec[pids_mapped].color_index = 0;
2108 pids_mapped++;
2109 if (pids_mapped == g_npids)
2110 break;
2111 }
2112 ep++;
2113 }
2114
2115 if (pids_mapped != g_npids) {
2116 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2117 }
2118
2119 g_free (g_pids);
2120 g_pids = new_pidvec;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002121
Dave Barach52642c32016-02-11 19:28:19 -05002122 /*
2123 * The new g_pids vector contains the "chase" sort, so we revert
Dave Barach9c8cfd32019-02-03 10:44:47 -05002124 * the pid_index mapping to an identity map
Dave Barach52642c32016-02-11 19:28:19 -05002125 */
2126 psp = g_pids;
2127
2128 for (i = 0; i < g_npids; i++) {
2129 pp = psp->pid;
2130 pp->pid_index = i;
2131 psp++;
2132 }
2133
2134 /* AutoScroll the PID axis so we show the first "chased" event */
2135 s_v1->first_pid_index = 0;
2136 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2137 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2138 init_track_colors();
2139 view1_display_when_idle();
2140}
2141
2142/****************************************************************************
2143* unchase_event_etc
2144* Copy g_original_pids to g_pids, revert index mapping
2145****************************************************************************/
2146static void unchase_event_etc(void)
2147{
2148 int i;
2149 pid_sort_t *psp;
2150 pid_data_t *pp;
2151
Dave Barach9c8cfd32019-02-03 10:44:47 -05002152 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05002153
2154 /* Fix the pid structure index mappings */
2155 psp = g_pids;
2156
2157 for (i = 0; i < g_npids; i++) {
2158 pp = psp->pid;
2159 pp->pid_index = i;
2160 psp++;
2161 }
2162
2163 /* Scroll PID axis to the top */
2164 s_v1->first_pid_index = 0;
2165 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2166 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2167 init_track_colors();
2168 view1_display_when_idle();
2169}
2170
2171/****************************************************************************
2172* print_ps_header
2173* To fit a reasonable-sized landscape mode plot onto letter-size paper,
2174* scale everything by .75.
2175****************************************************************************/
2176
2177static void print_ps_header (v1_geometry_t *vp, char *filename)
2178{
2179 time_t now;
2180
2181 now = time(0);
2182
2183 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2184 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2185 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2186 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2187 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2188 fprintf(s_printfp, "%%%%Origin: 0 0\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05002189 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
Dave Barach52642c32016-02-11 19:28:19 -05002190 vp->total_width);
2191 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2192 fprintf(s_printfp, "%%%%Pages: 1\n");
2193 fprintf(s_printfp, "%%%%Page: 1 1\n");
2194 fprintf(s_printfp, "%%%%EOF\n");
2195 fprintf(s_printfp, "/Times-Roman findfont\n");
2196 fprintf(s_printfp, "12 scalefont\n");
2197 fprintf(s_printfp, "setfont\n");
2198 fprintf(s_printfp, ".75 .75 scale\n");
2199}
2200
2201/****************************************************************************
2202* xrt
2203* Xcoordinate rotate and translate. We need to emit postscript that
2204* has a reasonable aspect ratio for printing. To do that, we rotate the
Dave Barach9c8cfd32019-02-03 10:44:47 -05002205* intended picture by 90 degrees, using the standard 2D rotation
Dave Barach52642c32016-02-11 19:28:19 -05002206* formula:
Dave Barach9c8cfd32019-02-03 10:44:47 -05002207*
Dave Barach52642c32016-02-11 19:28:19 -05002208* Xr = x*cos(theta) - y*sin(theta);
2209* Yr = x*sin(theta) + y*cos(theta);
2210*
2211* If we let theta = 90, this reduces to
2212* Xr = -y
2213* Yr = x
2214*
2215* Translate back to the origin in X by adding Ymax, yielding
2216* Xrt = Ymax - y
2217****************************************************************************/
2218
2219static inline int xrt(int x, int y)
2220{
2221 return (s_v1->total_height - y);
2222}
2223
2224static inline int yrt(int x, int y)
2225{
2226 return(x);
2227}
2228
2229/****************************************************************************
2230* print_screen_callback
2231****************************************************************************/
2232
2233static boolean print_screen_callback(char *filename)
2234{
2235 s_printfp = fopen (filename, "wt");
2236
2237 if (s_printfp == NULL)
2238 return(FALSE);
2239
2240 /*
2241 * This variable allows us to magically turn the view1 display
2242 * code into a print-driver, with a minimum of fuss. The idea is to
2243 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2244 * the required value, aka s_print_offset.
2245 * Make sure to fix g2.h if you mess here, or vice versa.
2246 */
2247 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2248
2249 print_ps_header(s_v1, filename);
2250
2251 display_pid_axis(s_v1);
2252 display_event_data(s_v1);
2253 display_time_axis(s_v1);
2254
2255 fclose (s_printfp);
2256 s_printfp = 0;
2257 s_print_offset = 0;
2258
2259 /* For tactile feedback */
2260 view1_display_when_idle();
2261 return(TRUE);
2262}
2263
Dave Barach2c35e582017-04-03 10:22:17 -04002264int event_time_cmp (const void *a, const void *b)
2265{
2266 const event_t *e1 = a;
2267 const event_t *e2 = b;
2268
2269 if (e1->time < e2->time)
2270 return -1;
2271 else if (e1->time > e2->time)
2272 return 1;
2273 return 0;
2274}
2275
2276/****************************************************************************
2277* slew_tracks
2278****************************************************************************/
2279static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2280{
2281 event_t *ep;
2282 pid_sort_t *pp;
2283 int pid_index;
2284 ulonglong delta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002285
Dave Barach2c35e582017-04-03 10:22:17 -04002286 delta = (ulonglong) (vp->last_time_interval);
2287
2288 /* Make sure we don't push events to the left of the big bang */
2289 if (which == SLEW_LEFT_BUTTON) {
2290 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2291 pid_index = ep->pid->pid_index;
2292 pp = (g_pids + pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002293
Dave Barach2c35e582017-04-03 10:22:17 -04002294 if (pp->selected) {
2295 if (ep->time < delta) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002296 infobox("Slew Range Error",
Dave Barach2c35e582017-04-03 10:22:17 -04002297 "\nCan't slew selected data left that far..."
2298 "\nEvents would preceed the Big Bang (t=0)...");
2299 goto out;
2300 }
2301 }
2302 }
2303 }
2304
2305 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2306 pid_index = ep->pid->pid_index;
2307 pp = (g_pids + pid_index);
2308
2309 if (pp->selected) {
2310 if (which == SLEW_LEFT_BUTTON)
2311 ep->time -= delta;
2312 else
2313 ep->time += delta;
2314 }
2315 }
2316
2317 /* Re-sort the events, to avoid screwing up the event display */
2318 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2319
2320 /* De-select tracks */
2321 deselect_tracks();
2322
2323out:
2324 view1_display_when_idle();
2325}
2326
Dave Barach52642c32016-02-11 19:28:19 -05002327/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05002328* view1_button_click_callback
Dave Barach52642c32016-02-11 19:28:19 -05002329****************************************************************************/
2330
2331static void view1_button_click_callback(GtkButton *item, gpointer data)
2332{
2333 enum view1_button_click click = (enum view1_button_click) data;
2334 event_t *ep;
2335 ulonglong event_incdec;
2336 ulonglong current_width;
2337 ulonglong zoom_delta;
2338
Dave Barach52642c32016-02-11 19:28:19 -05002339 current_width = s_v1->maxvistime - s_v1->minvistime;
2340 event_incdec = (current_width) / 3;
2341
2342 if (event_incdec == 0LL)
2343 event_incdec = 1;
2344
2345 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
2346
2347 switch(click) {
2348 case TOP_BUTTON:
2349 /* First PID to top of window */
2350 s_v1->first_pid_index = 0;
2351 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2352 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2353 break;
2354
2355 case BOTTOM_BUTTON:
2356 s_v1->first_pid_index = g_npids - s_v1->npids;
2357 if (s_v1->first_pid_index < 0)
2358 s_v1->first_pid_index = 0;
2359 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index;
2360 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2361 break;
2362
2363 case SNAP_BUTTON:
2364 add_snapshot();
2365 break;
2366
2367 case NEXT_BUTTON:
2368 next_snapshot();
2369 break;
2370
2371 case DEL_BUTTON:
2372 del_snapshot();
2373 break;
2374
2375 case CHASE_EVENT_BUTTON:
2376 chase_event_etc(CHASE_EVENT);
2377 break;
2378
2379 case CHASE_DATUM_BUTTON:
2380 chase_event_etc(CHASE_DATUM);
2381 break;
2382
2383 case CHASE_TRACK_BUTTON:
2384 chase_event_etc(CHASE_TRACK);
2385 break;
2386
2387 case UNCHASE_BUTTON:
2388 unchase_event_etc();
2389 break;
2390
2391 case START_BUTTON:
2392 start_button:
2393 s_v1->minvistime = 0LL;
2394 s_v1->maxvistime = current_width;
2395 recompute_hscrollbar();
2396 break;
2397
2398 case ZOOMIN_BUTTON:
2399 s_v1->minvistime += zoom_delta;
2400 s_v1->maxvistime -= zoom_delta;
2401 recompute_hscrollbar();
2402 break;
2403
2404 case SEARCH_AGAIN_BUTTON:
2405 if (s_srchcode) {
2406 event_search_internal();
2407 break;
2408 }
2409 /* NOTE FALLTHROUGH */
2410
2411 case SEARCH_BUTTON:
2412 event_search();
2413 break;
2414
Dave Barach9c8cfd32019-02-03 10:44:47 -05002415 case ANOMALY_THRESHOLD_BUTTON:
2416 anomaly_threshold();
2417 break;
2418
2419 case ANOMALY_NEXT_BUTTON:
2420 if (s_anomalycode) {
2421 anomaly_search_internal();
2422 break;
2423 }
2424 /* NOTE FALLTHROUGH */
2425
2426 case ANOMALY_BUTTON:
2427 anomaly_search();
2428 break;
2429
Dave Barach52642c32016-02-11 19:28:19 -05002430 case ZOOMOUT_BUTTON:
2431 if (zoom_delta == 0LL)
2432 zoom_delta = 1;
2433
2434 if (s_v1->minvistime >= zoom_delta) {
2435 s_v1->minvistime -= zoom_delta;
2436 s_v1->maxvistime += zoom_delta;
2437 } else {
2438 s_v1->minvistime = 0;
2439 s_v1->maxvistime += zoom_delta*2;
2440 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05002441
2442 if ((s_v1->maxvistime - s_v1->minvistime) * 8 >
Dave Barach52642c32016-02-11 19:28:19 -05002443 g_events[g_nevents-1].time * 9) {
2444 s_v1->minvistime = 0;
2445 s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8;
Dave Baracha4bab9d2017-12-14 17:21:36 -05002446 /* Single event? Make window 1s wide... */
2447 if (g_nevents == 1)
Dave Barach9c8cfd32019-02-03 10:44:47 -05002448 s_v1->maxvistime = 1000000;
Dave Baracha4bab9d2017-12-14 17:21:36 -05002449
Dave Barach52642c32016-02-11 19:28:19 -05002450 }
2451 recompute_hscrollbar();
2452 break;
2453
2454 case END_BUTTON:
2455 ep = (g_events + g_nevents - 1);
2456 s_v1->maxvistime = ep->time + event_incdec/3;
2457 s_v1->minvistime = s_v1->maxvistime - current_width;
2458 if (s_v1->minvistime > s_v1->maxvistime)
2459 goto start_button;
2460 recompute_hscrollbar();
2461 break;
2462
2463 case MORE_TRACES_BUTTON:
2464 /* Reduce the strip height to fit more traces on screen */
2465 s_v1->strip_height -= 1;
2466
2467 if (s_v1->strip_height < 1) {
2468 s_v1->strip_height = 1;
2469 }
2470
2471 /* Recalculate the number of strips on the screen */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002472 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05002473 s_v1->strip_height;
2474 recompute_vscrollbar();
2475 break;
2476
2477 case LESS_TRACES_BUTTON:
2478 /* Increase the strip height to fit fewer on the screen */
2479 s_v1->strip_height += 1;
2480 if (s_v1->strip_height > 80) {
2481 s_v1->strip_height = 80;
2482 }
2483
2484 /* Recalculate the number of strips on the screen */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002485 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05002486 s_v1->strip_height;
2487 recompute_vscrollbar();
2488 break;
2489
2490 case FORWARD_BUTTON:
2491 srch_chase_dir = SRCH_CHASE_FORWARD;
2492 gtk_widget_hide (s_view1_forward_button);
2493 gtk_widget_show (s_view1_backward_button);
2494 break;
2495
2496 case BACKWARD_BUTTON:
2497 srch_chase_dir = SRCH_CHASE_BACKWARD;
2498 gtk_widget_show (s_view1_forward_button);
2499 gtk_widget_hide (s_view1_backward_button);
2500 break;
2501
2502 case SUMMARY_BUTTON:
2503 summary_mode = TRUE;
2504 gtk_widget_hide (s_view1_summary_button);
2505 gtk_widget_show (s_view1_nosummary_button);
2506 break;
2507
2508 case NOSUMMARY_BUTTON:
2509 summary_mode = FALSE;
2510 gtk_widget_show (s_view1_summary_button);
2511 gtk_widget_hide (s_view1_nosummary_button);
2512 break;
Dave Barach2c35e582017-04-03 10:22:17 -04002513
2514 case SLEW_LEFT_BUTTON:
2515 case SLEW_RIGHT_BUTTON:
2516 if (s_v1->last_time_interval < 10e-9) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002517 infobox("slew", "\nNo time interval set...\n");
Dave Barach2c35e582017-04-03 10:22:17 -04002518 break;
2519 }
2520 slew_tracks (s_v1, click);
2521 break;
Dave Barach52642c32016-02-11 19:28:19 -05002522 }
2523
2524 view1_display_when_idle();
2525}
2526
2527/****************************************************************************
2528* view1_print_callback
2529****************************************************************************/
2530
2531void view1_print_callback (GtkToggleButton *notused, gpointer nu2)
2532{
2533 modal_dialog("Print Screen (PostScript format) to file:",
2534 "Invalid file: Print Screen to file:",
2535 "g2.ps", print_screen_callback);
2536}
2537
2538/****************************************************************************
2539* view1_hscroll
2540****************************************************************************/
2541
2542static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused)
2543{
2544 ulonglong current_width;
2545
2546 current_width = (s_v1->maxvistime - s_v1->minvistime);
2547
2548 s_v1->minvistime = (ulonglong)(adj->value);
2549 s_v1->maxvistime = s_v1->minvistime + current_width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002550
Dave Barach52642c32016-02-11 19:28:19 -05002551 view1_display_when_idle();
2552
2553#ifdef NOTDEF
2554 g_print ("adj->lower = %.2f\n", adj->lower);
2555 g_print ("adj->upper = %.2f\n", adj->upper);
2556 g_print ("adj->value = %.2f\n", adj->value);
2557 g_print ("adj->step_increment = %.2f\n", adj->step_increment);
2558 g_print ("adj->page_increment = %.2f\n", adj->page_increment);
2559 g_print ("adj->page_size = %.2f\n", adj->page_size);
2560#endif
2561}
2562
2563/****************************************************************************
2564* view1_vscroll
2565****************************************************************************/
2566
2567static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused)
2568{
2569 s_v1->first_pid_index = (int)adj->value;
2570 view1_display_when_idle();
2571}
2572
2573void set_pid_ax_width(int width)
2574{
2575 s_v1->pid_ax_width = width;
2576 view1_display_when_idle();
2577}
2578
2579/****************************************************************************
2580* view1_init
2581****************************************************************************/
2582
2583void view1_init(void)
2584{
Dave Barach52642c32016-02-11 19:28:19 -05002585 c_view1_draw_width = atol(getprop_default("drawbox_width", "700"));
2586 c_view1_draw_height = atol(getprop_default("drawbox_height", "400"));
2587
2588 s_v1->pid_ax_width = 80;
2589 s_v1->time_ax_height = 80;
2590 s_v1->time_ax_spacing = 100;
2591 s_v1->strip_height = 25;
2592 s_v1->pop_offset = 20;
2593 s_v1->pid_ax_offset = 34;
2594 s_v1->event_offset = 40;
2595 s_v1->total_height = c_view1_draw_height;
2596 s_v1->total_width = c_view1_draw_width;
2597 s_v1->first_pid_index = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002598 s_v1->anomaly_threshold_stddevs =
2599 atof(getprop_default("anomaly_threshold_stddevs", "2.5"));
2600 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05002601 s_v1->strip_height;
2602
2603 s_v1->minvistime = 0;
2604 s_v1->maxvistime = 200;
2605
2606 s_view1_vbox = gtk_vbox_new(FALSE, 5);
2607
2608 s_view1_hbox = gtk_hbox_new(FALSE, 5);
2609
2610 da = gtk_drawing_area_new();
Dave Barach9c8cfd32019-02-03 10:44:47 -05002611 gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width,
Dave Barach52642c32016-02-11 19:28:19 -05002612 c_view1_draw_height);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002613
Dave Barach52642c32016-02-11 19:28:19 -05002614#ifdef NOTDEF
2615 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2616 (GtkSignalFunc) motion_notify_event, NULL);
2617#endif
2618
2619 gtk_signal_connect (GTK_OBJECT (da), "expose_event",
2620 (GtkSignalFunc) expose_event, NULL);
2621
2622 gtk_signal_connect (GTK_OBJECT(da),"configure_event",
2623 (GtkSignalFunc) configure_event, NULL);
2624
2625 gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
2626 (GtkSignalFunc) button_press_event, NULL);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002627
Dave Barach52642c32016-02-11 19:28:19 -05002628 gtk_signal_connect (GTK_OBJECT (da), "button_release_event",
2629 (GtkSignalFunc) button_press_event, NULL);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002630
Dave Barach52642c32016-02-11 19:28:19 -05002631 gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
2632 (GtkSignalFunc) button_press_event, NULL);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002633
2634 gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK
2635 | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK
Dave Barach52642c32016-02-11 19:28:19 -05002636 | GDK_BUTTON_MOTION_MASK);
2637
2638
2639 gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0);
2640
2641 g_font = gdk_font_load ("8x13");
2642 if (g_font == NULL) {
2643 g_error("Couldn't load 8x13 font...\n");
2644 }
2645 gdk_font_ref(g_font);
2646
2647 /* PID axis menu */
2648 s_view1_vmenubox = gtk_vbox_new(FALSE, 5);
2649
Dave Barach9c8cfd32019-02-03 10:44:47 -05002650 s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */,
Dave Barach52642c32016-02-11 19:28:19 -05002651 0.0 /* minimum value */,
2652 2000.0 /* maximum value */,
Dave Barach9c8cfd32019-02-03 10:44:47 -05002653 0.1 /* step increment */,
2654 10.0/* page increment */,
Dave Barach52642c32016-02-11 19:28:19 -05002655 10.0/* page size */);
2656
2657 s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj));
2658
2659 gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002660 GTK_SIGNAL_FUNC (view1_vscroll),
Dave Barach52642c32016-02-11 19:28:19 -05002661 (gpointer)s_view1_vscroll);
2662
2663 s_view1_topbutton = gtk_button_new_with_label("Top");
2664 s_view1_bottombutton = gtk_button_new_with_label("Bottom");
2665
2666 gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002667 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002668 (gpointer) TOP_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002669
Dave Barach52642c32016-02-11 19:28:19 -05002670 gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002671 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002672 (gpointer) BOTTOM_BUTTON);
2673
2674 /* More Traces button and Less Traces button */
2675 s_view1_more_traces_button = gtk_button_new_with_label("More Traces");
2676 s_view1_less_traces_button = gtk_button_new_with_label("Less Traces");
2677 gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002678 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002679 (gpointer) MORE_TRACES_BUTTON);
2680 gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002681 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002682 (gpointer) LESS_TRACES_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002683
Dave Barach52642c32016-02-11 19:28:19 -05002684#ifdef NOTDEF
2685 /* Trick to bottom-justify the menu: */
2686 s_view1_pad1 = gtk_vbox_new(FALSE, 0);
2687 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1,
2688 TRUE, FALSE, 0);
2689
2690#endif
Dave Barach9c8cfd32019-02-03 10:44:47 -05002691
Dave Barach52642c32016-02-11 19:28:19 -05002692 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton,
2693 FALSE, FALSE, 0);
2694
2695 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll,
2696 TRUE, TRUE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002697
Dave Barach52642c32016-02-11 19:28:19 -05002698 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton,
2699 FALSE, FALSE, 0);
2700
2701 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button,
2702 FALSE, FALSE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002703
Dave Barach52642c32016-02-11 19:28:19 -05002704 gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button,
2705 FALSE, FALSE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002706
Dave Barach52642c32016-02-11 19:28:19 -05002707 gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox,
2708 FALSE, FALSE, 0);
2709
2710 /* Time axis menu */
2711
2712 s_view1_hmenubox = gtk_hbox_new(FALSE, 5);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002713
Dave Barach52642c32016-02-11 19:28:19 -05002714 s_view1_startbutton = gtk_button_new_with_label("Start");
2715
2716 s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn");
2717
2718 s_view1_searchbutton = gtk_button_new_with_label("Search");
Dave Barach52642c32016-02-11 19:28:19 -05002719 s_view1_srchagainbutton = gtk_button_new_with_label("Search Again");
2720
Dave Barach9c8cfd32019-02-03 10:44:47 -05002721 s_view1_anomalybutton = gtk_button_new_with_label("Anomaly");
2722 s_view1_anomalynextbutton = gtk_button_new_with_label("Next Anomaly");
2723 s_view1_anomalythresholdbutton =
2724 gtk_button_new_with_label ("Anomaly Threshold");
2725
Dave Barach52642c32016-02-11 19:28:19 -05002726 s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut");
2727
2728 s_view1_endbutton = gtk_button_new_with_label("End");
2729
2730 gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002731 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002732 (gpointer) START_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002733
Dave Barach52642c32016-02-11 19:28:19 -05002734 gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002735 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002736 (gpointer) ZOOMIN_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002737
Dave Barach52642c32016-02-11 19:28:19 -05002738 gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002739 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002740 (gpointer) SEARCH_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002741
Dave Barach52642c32016-02-11 19:28:19 -05002742 gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002743 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002744 (gpointer) SEARCH_AGAIN_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002745
2746 gtk_signal_connect (GTK_OBJECT(s_view1_anomalybutton), "clicked",
2747 GTK_SIGNAL_FUNC(view1_button_click_callback),
2748 (gpointer) ANOMALY_BUTTON);
2749
2750 gtk_signal_connect (GTK_OBJECT(s_view1_anomalynextbutton), "clicked",
2751 GTK_SIGNAL_FUNC(view1_button_click_callback),
2752 (gpointer) ANOMALY_NEXT_BUTTON);
2753
2754 gtk_signal_connect (GTK_OBJECT(s_view1_anomalythresholdbutton),
2755 "clicked", GTK_SIGNAL_FUNC(view1_button_click_callback),
2756 (gpointer) ANOMALY_THRESHOLD_BUTTON);
2757
Dave Barach52642c32016-02-11 19:28:19 -05002758 gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002759 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002760 (gpointer) ZOOMOUT_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002761
Dave Barach52642c32016-02-11 19:28:19 -05002762 gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002763 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002764 (gpointer) END_BUTTON);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002765
2766 s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */,
Dave Barach52642c32016-02-11 19:28:19 -05002767 0.0 /* minimum value */,
2768 2000.0 /* maximum value */,
Dave Barach9c8cfd32019-02-03 10:44:47 -05002769 0.1 /* step increment */,
2770 10.0/* page increment */,
Dave Barach52642c32016-02-11 19:28:19 -05002771 10.0/* page size */);
2772
2773 s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj));
2774
2775 gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002776 GTK_SIGNAL_FUNC (view1_hscroll),
Dave Barach52642c32016-02-11 19:28:19 -05002777 (gpointer)s_view1_hscroll);
2778
2779 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton,
2780 FALSE, FALSE, 0);
2781
2782 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll,
2783 TRUE, TRUE, 0);
2784
2785 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton,
2786 FALSE, FALSE, 0);
2787
2788 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton,
2789 FALSE, FALSE, 0);
2790
Dave Barach9c8cfd32019-02-03 10:44:47 -05002791 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalybutton,
2792 FALSE, FALSE, 0);
2793 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_anomalynextbutton,
2794 FALSE, FALSE, 0);
Dave Barach52642c32016-02-11 19:28:19 -05002795 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton,
2796 FALSE, FALSE, 0);
2797
2798 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton,
2799 FALSE, FALSE, 0);
2800
2801 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton,
2802 FALSE, FALSE, 0);
2803
Dave Barach9c8cfd32019-02-03 10:44:47 -05002804 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox,
Dave Barach52642c32016-02-11 19:28:19 -05002805 TRUE, TRUE, 0);
2806
2807 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox,
2808 FALSE, FALSE, 0);
2809
2810
2811 s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5);
2812
2813 s_view1_snapbutton = gtk_button_new_with_label("Snap");
2814
2815 s_view1_nextbutton = gtk_button_new_with_label("Next");
2816
2817 s_view1_delbutton = gtk_button_new_with_label("Del");
2818
2819 s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent");
2820
2821 s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum");
2822
2823 s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack");
2824
2825 s_view1_unchasebutton = gtk_button_new_with_label("NoChase");
2826
2827 s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)");
2828 s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)");
2829
2830 s_view1_summary_button = gtk_button_new_with_label("Summary");
2831 s_view1_nosummary_button = gtk_button_new_with_label("NoSummary");
2832
Dave Barach2c35e582017-04-03 10:22:17 -04002833 s_view1_time_slew_left_button = gtk_button_new_with_label("<-TimeSlew");
2834 s_view1_time_slew_right_button = gtk_button_new_with_label("TimeSlew->");
2835
Dave Barach52642c32016-02-11 19:28:19 -05002836 gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002837 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002838 (gpointer) SNAP_BUTTON);
2839
2840 gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002841 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002842 (gpointer) NEXT_BUTTON);
2843
2844 gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002845 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002846 (gpointer) DEL_BUTTON);
2847
2848 gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002849 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002850 (gpointer) CHASE_EVENT_BUTTON);
2851
2852 gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002853 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002854 (gpointer) CHASE_DATUM_BUTTON);
2855
2856 gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002857 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002858 (gpointer) CHASE_TRACK_BUTTON);
2859
2860 gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002861 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002862 (gpointer) UNCHASE_BUTTON);
2863
2864 gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002865 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002866 (gpointer) FORWARD_BUTTON);
2867
2868 gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002869 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002870 (gpointer) BACKWARD_BUTTON);
2871
2872 gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002873 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002874 (gpointer) SUMMARY_BUTTON);
2875
2876 gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002877 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach52642c32016-02-11 19:28:19 -05002878 (gpointer) NOSUMMARY_BUTTON);
2879
Dave Barach2c35e582017-04-03 10:22:17 -04002880 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_left_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002881 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach2c35e582017-04-03 10:22:17 -04002882 (gpointer) SLEW_LEFT_BUTTON);
2883
2884 gtk_signal_connect (GTK_OBJECT(s_view1_time_slew_right_button), "clicked",
Dave Barach9c8cfd32019-02-03 10:44:47 -05002885 GTK_SIGNAL_FUNC(view1_button_click_callback),
Dave Barach2c35e582017-04-03 10:22:17 -04002886 (gpointer) SLEW_RIGHT_BUTTON);
2887
Dave Barach52642c32016-02-11 19:28:19 -05002888 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2,
2889 FALSE, FALSE, 0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002890
Dave Barach52642c32016-02-11 19:28:19 -05002891 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton,
2892 FALSE, FALSE, 0);
2893
2894 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton,
2895 FALSE, FALSE, 0);
2896
2897 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton,
2898 FALSE, FALSE, 0);
2899
2900 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button,
2901 FALSE, FALSE, 0);
2902
2903 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button,
2904 FALSE, FALSE, 0);
2905
2906 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button,
2907 FALSE, FALSE, 0);
2908
2909 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton,
2910 FALSE, FALSE, 0);
2911
2912 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button,
2913 FALSE, FALSE, 0);
2914
2915 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button,
2916 FALSE, FALSE, 0);
2917
2918 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button,
2919 FALSE, FALSE, 0);
2920
2921 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button,
2922 FALSE, FALSE, 0);
2923
Dave Barach9c8cfd32019-02-03 10:44:47 -05002924 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
Dave Barach2c35e582017-04-03 10:22:17 -04002925 s_view1_time_slew_left_button,
2926 FALSE, FALSE, 0);
2927
Dave Barach9c8cfd32019-02-03 10:44:47 -05002928 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
Dave Barach2c35e582017-04-03 10:22:17 -04002929 s_view1_time_slew_right_button,
2930 FALSE, FALSE, 0);
2931
Dave Barach9c8cfd32019-02-03 10:44:47 -05002932 gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2),
2933 s_view1_anomalythresholdbutton,
2934 FALSE, FALSE, 0);
2935
Dave Barach52642c32016-02-11 19:28:19 -05002936 s_view1_label = gtk_label_new(NULL);
2937
2938 gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label,
2939 FALSE, FALSE, 0);
2940
2941 gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox,
2942 TRUE, TRUE, 0);
2943
2944 gtk_widget_show_all (s_view1_vbox);
2945 GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS);
2946 gtk_widget_grab_focus(da);
2947
2948 gtk_widget_hide (s_view1_forward_button);
2949 gtk_widget_hide (summary_mode ? s_view1_summary_button
2950 : s_view1_nosummary_button);
2951
Dave Barach9c8cfd32019-02-03 10:44:47 -05002952 zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width,
Dave Barach52642c32016-02-11 19:28:19 -05002953 zi_height);
2954 zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width,
2955 zi_height);
2956
Dave Barach9c8cfd32019-02-03 10:44:47 -05002957 zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source,
Dave Barach52642c32016-02-11 19:28:19 -05002958 zi_mask, &fg_black,
2959 &bg_white, zi_x_hot,
2960 zi_y_hot);
2961 gdk_pixmap_unref (zi_source);
2962 gdk_pixmap_unref (zi_mask);
2963
2964 norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2965}
2966
2967/****************************************************************************
2968* line_print
2969****************************************************************************/
2970
2971void line_print (int x1, int y1, int x2, int y2)
2972{
2973 fprintf(s_printfp, "newpath\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05002974 fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1),
Dave Barach52642c32016-02-11 19:28:19 -05002975 yrt(x1, s_v1->total_height - y1));
2976
2977 fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2),
2978 yrt (x2, s_v1->total_height - y2));
2979 fprintf(s_printfp, "1 setlinewidth\n");
2980 fprintf(s_printfp, "stroke\n");
2981}
2982
2983/****************************************************************************
2984* tbox_print
2985****************************************************************************/
2986GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function,
2987 GdkRectangle *rp)
2988{
2989 if (function == TBOX_PRINT_BOXED) {
2990 rp->width -= 4;
2991 }
2992
2993 if ((function == TBOX_PRINT_BOXED) ||
2994 (function == TBOX_PRINT_EVENT)) {
2995
2996 fprintf(s_printfp, "newpath\n");
2997 fprintf(s_printfp, "0 setlinewidth\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05002998 fprintf(s_printfp, "%d %d moveto\n",
Dave Barach52642c32016-02-11 19:28:19 -05002999 xrt(rp->x, s_v1->total_height - rp->y),
3000 yrt(rp->x, s_v1->total_height - rp->y));
Dave Barach9c8cfd32019-02-03 10:44:47 -05003001
3002 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003003 xrt (rp->x+rp->width, s_v1->total_height - rp->y),
3004 yrt (rp->x+rp->width, s_v1->total_height - rp->y));
3005
Dave Barach9c8cfd32019-02-03 10:44:47 -05003006 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003007 xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)),
3008 yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)));
3009
Dave Barach9c8cfd32019-02-03 10:44:47 -05003010 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003011 xrt(rp->x, s_v1->total_height - (rp->y+rp->height)),
3012 yrt(rp->x, s_v1->total_height - (rp->y+rp->height)));
3013
Dave Barach9c8cfd32019-02-03 10:44:47 -05003014 fprintf(s_printfp, "%d %d lineto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003015 xrt(rp->x, s_v1->total_height - rp->y),
3016 yrt(rp->x, s_v1->total_height - rp->y));
3017
3018 fprintf(s_printfp, "stroke\n");
3019 }
3020
3021 if ((function == TBOX_PRINT_BOXED) ||
3022 (function == TBOX_PRINT_PLAIN)) {
3023
3024 fprintf(s_printfp, "newpath\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05003025 fprintf(s_printfp, "%d %d moveto\n",
Dave Barach52642c32016-02-11 19:28:19 -05003026 xrt(x, s_v1->total_height - (y-2)),
3027 yrt(x, s_v1->total_height - (y-2)));
3028 fprintf(s_printfp, "gsave\n");
3029 fprintf(s_printfp, "90 rotate\n");
3030 fprintf(s_printfp, "(%s) show\n", s);
3031 fprintf(s_printfp, "grestore\n");
3032 }
3033
3034 return(rp);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003035}
Dave Barach52642c32016-02-11 19:28:19 -05003036
3037/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05003038* tbox - draws an optionally boxed string whose lower lefthand
Dave Barach52642c32016-02-11 19:28:19 -05003039* corner is at (x, y). As usual, Y is backwards.
3040****************************************************************************/
3041
3042GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function)
3043{
3044 static GdkRectangle update_rect;
3045 gint lbearing, rbearing, width, ascent, descent;
3046
3047 gdk_string_extents (g_font, s,
3048 &lbearing, &rbearing,
3049 &width, &ascent, &descent);
3050
3051 /*
3052 * If we have enough room to display full size events, then just
3053 * use the BOXED function instead of the EVENT function.
3054 */
3055 if (s_v1->strip_height > 9) {
3056 switch (function) {
3057 case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break;
3058 case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break;
3059 case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break;
3060 default:
3061 break;
3062 /* Nothing */
3063 }
3064 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003065
Dave Barach52642c32016-02-11 19:28:19 -05003066 switch (function) {
3067 case TBOX_DRAW_BOXED:
3068 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
Dave Barach9c8cfd32019-02-03 10:44:47 -05003069 x, y - (ascent+descent+3), width + 2,
Dave Barach52642c32016-02-11 19:28:19 -05003070 ascent + descent + 3);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003071
Dave Barach52642c32016-02-11 19:28:19 -05003072 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
Dave Barach9c8cfd32019-02-03 10:44:47 -05003073 x, y - (ascent+descent+3), width + 2,
Dave Barach52642c32016-02-11 19:28:19 -05003074 ascent + descent + 3);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003075
Dave Barach52642c32016-02-11 19:28:19 -05003076 gdk_draw_string (pm, g_font, da->style->black_gc,
3077 x + 1, y - 1, (const gchar *)s);
3078 /* NOTE FALLTHROUGH */
3079 case TBOX_GETRECT_BOXED:
3080 update_rect.x = x;
3081 update_rect.y = y -(ascent+descent+3);
3082 update_rect.width = width + 3;
3083 update_rect.height = ascent + descent + 4;
3084 if (function == TBOX_DRAW_BOXED)
3085 gtk_widget_draw (da, &update_rect);
3086 break;
3087
3088 case TBOX_DRAW_EVENT:
3089 /* We have a small event to draw...no text */
3090 gdk_draw_rectangle (pm, da->style->black_gc, FALSE,
3091 x, y - 1, 3, 3);
3092 /* NOTE FALLTHROUGH */
3093 case TBOX_GETRECT_EVENT:
3094 update_rect.x = x;
3095 update_rect.y = y - 1;
3096 update_rect.width = 4;
3097 update_rect.height = 4;
3098 if (function == TBOX_DRAW_EVENT)
3099 gtk_widget_draw (da, &update_rect);
3100 break;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003101
3102
Dave Barach52642c32016-02-11 19:28:19 -05003103 case TBOX_DRAW_PLAIN:
Dave Barach9c8cfd32019-02-03 10:44:47 -05003104
Dave Barach52642c32016-02-11 19:28:19 -05003105 gdk_draw_string (pm, g_font, da->style->black_gc,
3106 x + 1, y - 1, (const gchar *)s);
3107 /* NOTE FALLTHROUGH */
3108 case TBOX_GETRECT_PLAIN:
3109 update_rect.x = x;
3110 update_rect.y = y -(ascent+descent+1);
3111 update_rect.width = width;
3112 update_rect.height = ascent + descent;
3113 if (function == TBOX_DRAW_PLAIN)
3114 gtk_widget_draw (da, &update_rect);
3115 break;
3116
3117 case TBOX_PRINT_BOXED:
3118 update_rect.x = x;
3119 update_rect.y = y -(ascent+descent+3);
3120 update_rect.width = width + 3;
3121 update_rect.height = ascent + descent + 4;
3122 /* note fallthrough */
3123 case TBOX_PRINT_PLAIN:
3124 return(tbox_print(s, x, y, function, &update_rect));
3125
3126 case TBOX_PRINT_EVENT:
3127 /* We have a small event box to print...no text */
3128 update_rect.x = x;
3129 update_rect.y = y - 1;
3130 update_rect.width = 4;
3131 update_rect.height = 4;
3132 return(tbox_print(s, x, y, function, &update_rect));
3133 }
3134 return(&update_rect);
3135}
3136
3137/****************************************************************************
3138* line
3139*
3140* For lines there is a primitive batching facility, that doesn't update
3141* the drawing area until the batch is complete. This is handy for drawing
3142* the pid axis and for summary mode.
3143*
3144* line_batch_mode contains the state for this:
3145*
3146* BATCH_OFF: no batching, update for every line
3147* BATCH_NEW: just entered a batch, so initialize the area to update from
3148* scratch
3149* BATCH_EXISTING: have drawn at least one line in batch mode, so the update
3150* area should only be expanded from now on to include the
3151* union of the "rectangular hull" of all lines
3152****************************************************************************/
3153
3154static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode;
3155static int line_batch_count;
3156static int line_minx, line_miny, line_maxx, line_maxy;
3157
3158void line_batch_start (void)
3159{
3160 line_batch_mode = BATCH_NEW;
3161 line_batch_count = 0;
3162}
3163
3164void line_batch_end (void)
3165{
3166 GdkRectangle update_rect;
3167 if (line_batch_count > 0) {
3168 update_rect.x = line_minx;
3169 update_rect.y = line_miny;
3170 update_rect.width = (line_maxx - line_minx) + 1;
3171 update_rect.height = (line_maxy - line_miny) + 1;
3172 gtk_widget_draw (da, &update_rect);
3173 }
3174 line_batch_mode = BATCH_OFF;
3175}
3176
3177void line (int x1, int y1, int x2, int y2, enum view1_line_fn function)
3178{
3179 GdkRectangle update_rect;
3180 GdkGC *gc = NULL;
3181
3182 switch(function) {
3183 case LINE_DRAW_BLACK:
3184 gc = da->style->black_gc;
3185 break;
3186
3187 case LINE_DRAW_WHITE:
3188 gc = da->style->white_gc;
3189 break;
3190
3191 case LINE_PRINT:
3192 line_print (x1, y1, x2, y2);
3193 return;
3194 }
3195
3196 gdk_draw_line (pm, gc, x1, y1, x2, y2);
3197
3198 switch (line_batch_mode) {
3199 case BATCH_OFF:
3200 update_rect.x = x1;
3201 update_rect.y = y1;
3202 update_rect.width = (x2-x1) + 1;
3203 update_rect.height = (y2-y1) + 1;
3204 gtk_widget_draw (da, &update_rect);
3205 break;
3206
3207 case BATCH_NEW:
3208 line_minx = x1;
3209 line_maxx = x2;
3210 line_miny = y1;
3211 line_maxy = y2;
3212 line_batch_mode = BATCH_EXISTING;
3213 line_batch_count = 1;
3214 break;
3215
3216 case BATCH_EXISTING:
3217 if (line_minx > x1)
3218 line_minx = x1;
3219 if (line_miny > y1)
3220 line_miny = y1;
3221 if (line_maxx < x2)
3222 line_maxx = x2;
3223 if (line_maxy < y2)
3224 line_maxy = y2;
3225 line_batch_count++;
3226 break;
3227 }
3228}
3229
3230
3231/****************************************************************************
3232* display_pid_axis
3233****************************************************************************/
3234
3235static void display_pid_axis(v1_geometry_t *vp)
3236{
3237 int y, i, label_tick;
3238 int last_printed_y = -vp->strip_height;
3239 pid_sort_t *pp;
3240 int pid_index;
3241 char *label_fmt;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003242 char tmpbuf [128];
Dave Barach52642c32016-02-11 19:28:19 -05003243
3244 /* No pids yet? Outta here */
3245 if (g_pids == NULL)
3246 return;
3247
3248 line_batch_start();
3249
3250 for (i = 0; i < vp->npids; i++) {
3251 pid_index = vp->first_pid_index + i;
3252 if (pid_index >= g_npids)
3253 break;
3254
Dave Barach52642c32016-02-11 19:28:19 -05003255 pp = (g_pids + pid_index);
3256
Dave Barach2c35e582017-04-03 10:22:17 -04003257 set_color(pid_index);
3258
Dave Barach52642c32016-02-11 19:28:19 -05003259 label_fmt = get_track_label(pp->pid_value);
3260 snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value);
3261
3262 y = i*vp->strip_height + vp->pid_ax_offset;
3263
3264 /*
3265 * Have we incremented enough space to have another label not
3266 * overlap the previous label?
3267 */
3268 if (y - last_printed_y > 9) {
3269 /* Draw label */
3270 tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset);
3271
3272 last_printed_y = y;
3273
3274 /*
3275 * And let the line stick out a bit more to indicate this label
3276 * relates to the following line.
3277 */
3278 label_tick = 4;
3279 }
3280 else {
3281 label_tick = 0;
3282 }
3283
3284 /* Draw axis line, but only if the lines aren't too close together */
3285 if (vp->strip_height > 4) {
3286 line(vp->pid_ax_width - label_tick, y+4*s_print_offset,
3287 vp->total_width, y+4*s_print_offset,
3288 LINE_DRAW_BLACK+s_print_offset);
3289 }
3290 }
3291
3292 set_color(COLOR_DEFAULT);
3293 line_batch_end();
3294}
3295
3296/****************************************************************************
3297* view1_read_events_callback
3298* New event data just showed up, reset a few things.
3299****************************************************************************/
3300
3301void view1_read_events_callback(void)
3302{
3303 int max_vis_index;
3304
3305 s_v1->first_pid_index = 0;
3306
3307 max_vis_index = 300;
3308 if (max_vis_index > g_nevents)
3309 max_vis_index = g_nevents-1;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003310
Dave Barach52642c32016-02-11 19:28:19 -05003311 s_v1->minvistime = 0LL;
3312 s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8;
Dave Baracha4bab9d2017-12-14 17:21:36 -05003313 /* Single event? Make the initial display 1s wide */
3314 if (g_nevents == 1)
3315 s_v1->maxvistime = 1000000;
Dave Barach52642c32016-02-11 19:28:19 -05003316 s_srchindex = 0;
3317 s_srchcode = 0;
3318 s_last_selected_event = 0;
3319
3320 init_track_colors();
3321
3322 recompute_hscrollbar();
3323 recompute_vscrollbar();
3324}
3325
3326/****************************************************************************
3327* display_event_data
3328****************************************************************************/
3329
3330static void display_event_data(v1_geometry_t *vp)
3331{
3332 int start_index;
3333 int pid_index;
3334 int x, y;
3335 event_t *ep;
3336 event_def_t *edp;
3337 double time_per_pixel;
3338 char tmpbuf[1024];
3339 GdkRectangle *print_rect;
3340 int *last_x_used;
3341
3342 /* Happens if one loads the event def header first, for example. */
3343 if (g_nevents == 0)
3344 return;
3345
3346 time_per_pixel = dtime_per_pixel(vp);
3347
3348 start_index = find_event_index (vp->minvistime);
3349
3350 /* Scrolled too far right? */
3351 if (start_index >= g_nevents)
3352 return;
3353
3354 ep = (g_events + start_index);
3355
3356 if (s_print_offset || summary_mode) {
3357 last_x_used = (int *)g_malloc0(vp->npids * sizeof(int));
3358 } else {
3359 last_x_used = NULL;
3360 }
3361
3362 line_batch_start();
3363
3364 while (ep < (g_events + g_nevents) &&
3365 (ep->time < vp->maxvistime)) {
3366 pid_index = ep->pid->pid_index;
3367 set_color(pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003368
Dave Barach52642c32016-02-11 19:28:19 -05003369 /* First filter: pid out of range */
3370 if ((pid_index < vp->first_pid_index) ||
3371 (pid_index >= vp->first_pid_index + vp->npids)) {
3372 ep++;
3373 continue;
3374 }
3375
3376 /* Second filter: event hidden */
3377 edp = find_event_definition (ep->code);
3378 if (!edp->selected) {
3379 ep++;
3380 continue;
3381 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003382
Dave Barach52642c32016-02-11 19:28:19 -05003383 /* Display it... */
3384
3385 pid_index -= vp->first_pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003386
Dave Barach52642c32016-02-11 19:28:19 -05003387 y = pid_index*vp->strip_height + vp->event_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003388
3389 x = vp->pid_ax_width +
Dave Barach52642c32016-02-11 19:28:19 -05003390 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
3391
3392 if (last_x_used != NULL && x < last_x_used[pid_index]) {
3393 ep++;
3394 continue;
3395 }
3396
3397 if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) {
3398 if (ep->flags & EVENT_FLAG_SELECT) {
3399 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
3400#ifdef NOTDEF
3401 sprintf(tmpbuf, edp->name);
3402 sprintf(tmpbuf+strlen(tmpbuf), ": ");
3403 sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum);
3404#endif
3405 } else {
3406 sprintf(tmpbuf, "SEARCH RESULT");
3407 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003408 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05003409 TBOX_DRAW_BOXED+s_print_offset);
3410 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3411 if (last_x_used != NULL)
3412 last_x_used[pid_index] = x + print_rect->width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003413 }
Dave Barach52642c32016-02-11 19:28:19 -05003414 if (summary_mode) {
3415 int delta = vp->strip_height / 3;
3416 if (delta < 1)
3417 delta = 1;
3418 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3419 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3420 last_x_used[pid_index] = x + 1;
3421 } else {
3422 sprintf(tmpbuf, "%ld", ep->code);
3423 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3424 if (last_x_used != NULL)
3425 last_x_used[pid_index] = x + print_rect->width;
3426 }
3427
3428 ep++;
3429 }
3430 if (last_x_used)
3431 g_free(last_x_used);
3432 line_batch_end();
3433 set_color(COLOR_DEFAULT);
3434}
3435
3436/****************************************************************************
3437* display_clear
3438****************************************************************************/
3439
3440static void display_clear(void)
3441{
3442 GdkRectangle update_rect;
3443
3444 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3445 0, 0, da->allocation.width,
3446 da->allocation.height);
3447
3448 update_rect.x = 0;
3449 update_rect.y = 0;
3450 update_rect.width = da->allocation.width;
3451 update_rect.height = da->allocation.height;
3452
3453 gtk_widget_draw (da, &update_rect);
3454}
3455
3456/****************************************************************************
3457* display_time_axis
3458****************************************************************************/
3459
3460static void display_time_axis(v1_geometry_t *vp)
3461{
3462 int x, y, i;
3463 int xoffset, nticks;
3464 char tmpbuf [128];
3465 double unit_divisor;
3466 double time;
3467 char *units;
3468 double time_per_pixel;
3469
3470 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3471
3472 x = vp->pid_ax_width;
3473
3474 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3475
3476 time_per_pixel = dtime_per_pixel(vp);
3477
3478 units = "ns";
3479 unit_divisor = 1.00;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003480
Dave Barach52642c32016-02-11 19:28:19 -05003481 if ((vp->maxvistime / unit_divisor) > 1000) {
3482 units = "us";
3483 unit_divisor = 1000.00;
3484 }
3485
3486 if ((vp->maxvistime / unit_divisor) > 1000) {
3487 units = "ms";
3488 unit_divisor = 1000.00*1000.00;
3489 }
3490 if ((vp->maxvistime / unit_divisor) > 1000) {
3491 units = "s";
3492 unit_divisor = 1000.00*1000.00*1000.00;
3493 }
3494
3495 /* Draw line */
3496 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3497
3498 xoffset = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003499
Dave Barach52642c32016-02-11 19:28:19 -05003500 for (i = 0; i < nticks; i++) {
3501 /* Tick mark */
3502 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3503
3504 time = (double)(x + xoffset - vp->pid_ax_width);
3505 time *= time_per_pixel;
3506 time += (double)(vp->minvistime);
3507 time /= unit_divisor;
3508
3509 sprintf (tmpbuf, "%.2f%s", time, units);
3510
3511 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003512
Dave Barach52642c32016-02-11 19:28:19 -05003513 xoffset += vp->time_ax_spacing;
3514 }
3515}
3516
3517/****************************************************************************
3518* clear_scoreboard
3519* Forget about any temporary displays, they're gone now...
3520****************************************************************************/
3521
3522static void clear_scoreboard(void)
3523{
3524 s_result_up = FALSE;
3525}
3526
3527/****************************************************************************
3528* view1_display
3529****************************************************************************/
3530
3531void view1_display(void)
3532{
3533 display_clear();
3534 display_pid_axis(s_v1);
3535 display_event_data(s_v1);
3536 display_time_axis(s_v1);
3537 clear_scoreboard();
3538}
3539
3540static gint idle_tag;
3541
3542/****************************************************************************
3543* view1_display_eventually
3544****************************************************************************/
3545
3546static void view1_display_eventually(void)
3547{
3548 gtk_idle_remove(idle_tag);
3549 idle_tag = 0;
3550 view1_display();
3551}
3552
3553
3554/****************************************************************************
3555* view1_display_when_idle
3556****************************************************************************/
3557
3558void view1_display_when_idle(void)
3559{
3560 if (idle_tag == 0) {
3561 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3562 }
3563}
3564
3565/****************************************************************************
3566* view1_about
3567****************************************************************************/
3568
3569void view1_about (char *tmpbuf)
3570{
3571 int nsnaps;
3572 snapshot_t *snaps;
3573
3574 sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n",
3575 s_v1->minvistime, s_v1->maxvistime);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003576 sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n",
Dave Barach52642c32016-02-11 19:28:19 -05003577 s_v1->strip_height);
3578
3579 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3580 nsnaps++;
3581 }
3582 sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps);
3583}