blob: 7a6ae714e3fb9fa9a8d413c0f5ef6065d4cc1495 [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
Dave Barach52642c32016-02-11 19:28:19 -0500439 if (ep->flags & EVENT_FLAG_CLIB) {
440 elog_event_t *eep;
441 u8 *s;
442
443 eep = get_clib_event (ep->datum);
Dave Barach9c8cfd32019-02-03 10:44:47 -0500444
Dave Barach52642c32016-02-11 19:28:19 -0500445 s = format (0, "%U", format_elog_event, &elog_main, eep);
446 memcpy (tmpbuf, s, vec_len(s));
447 tmpbuf[vec_len(s)] = 0;
448 vec_free(s);
449 return;
450 }
451
452 snprintf(tmpbuf, len, "%s", edp->name);
453 fp = edp->format;
454 /* Make sure there's a real format string. If so, add it */
455 while (fp && *fp) {
456 if (*fp != ' ') {
457 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": ");
458 /* %s only supported for cpel files */
459 if (fp[1] == 's') {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500460 snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf),
Dave Barach52642c32016-02-11 19:28:19 -0500461 edp->format, strtab_ref(ep->datum));
462 } else {
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, ep->datum);
465 }
466 return;
467 }
468 fp++;
469 }
470}
471
472/****************************************************************************
473 * add_snapshot
474 ****************************************************************************/
475
476static void add_snapshot(void)
477{
478 int i;
479 snapshot_t *new = g_malloc(sizeof(snapshot_t));
480
481 memcpy(&new->geometry, s_v1, sizeof(new->geometry));
482 for (i = 0; i < NEVENTS; i++) {
483 new->show_event[i] = g_eventdefs[i].selected;
484 }
485 new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids);
486 memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids);
487 new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value;
488 new->summary_mode = summary_mode;
489 new->color_mode = color_mode;
490
491 if (s_snapshots) {
492 new->next = s_snapshots;
493 s_snapshots = new;
494 } else {
495 new->next = 0;
496 s_snapshots = new;
497 }
498 s_cursnap = new;
499}
500
501/****************************************************************************
502 * next_snapshot
503 ****************************************************************************/
504
505static void next_snapshot(void)
506{
507 snapshot_t *next;
508 int i;
509 pid_sort_t *psp;
510 pid_data_t *pp;
511
512 if (!s_snapshots) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500513 infobox("No snapshots", "\nNo snapshots in the ring...\n");
Dave Barach52642c32016-02-11 19:28:19 -0500514 return;
515 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500516
Dave Barach52642c32016-02-11 19:28:19 -0500517 next = s_cursnap->next;
518 if (next == 0)
519 next = s_snapshots;
520
521 s_cursnap = next;
522
523 memcpy(s_v1, &next->geometry, sizeof(next->geometry));
524 for (i = 0; i < NEVENTS; i++) {
525 g_eventdefs[i].selected = next->show_event[i];
526 }
527 memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids);
528 color_mode = next->color_mode;
529 /*
530 * Update summary mode via a button push so that the button state is
531 * updated accordingly. (Should ideally clean up the view/controller
532 * separation properly one day.)
533 */
534 if (summary_mode != next->summary_mode) {
535 view1_button_click_callback
536 (NULL, (gpointer)(unsigned long long)
537 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
538 }
539
540 /* Fix the pid structure index mappings */
541 psp = g_pids;
542
543 for (i = 0; i < g_npids; i++) {
544 pp = psp->pid;
545 pp->pid_index = i;
546 psp++;
547 }
548 GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value;
549 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
550 recompute_hscrollbar();
551 pointsel_next_snapshot();
552 view1_display_when_idle();
553}
554
555
556/****************************************************************************
557 * del_snapshot
558 ****************************************************************************/
559
560static void del_snapshot(void)
561{
562 snapshot_t *prev;
563 snapshot_t *this;
564
565 if (!s_snapshots) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500566 infobox("No snapshots", "\nNo snapshots to delete...\n");
Dave Barach52642c32016-02-11 19:28:19 -0500567 return;
568 }
569
570 prev = NULL;
571 this = s_snapshots;
572
573 while (this && this != s_cursnap) {
574 prev = this;
575 this = this->next;
576 }
577
578 if (this != s_cursnap) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500579 infobox("BUG", "\nSnapshot AWOL!\n");
Dave Barach52642c32016-02-11 19:28:19 -0500580 return;
581 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500582
Dave Barach52642c32016-02-11 19:28:19 -0500583 s_cursnap = this->next;
584
585 /* middle of the list? */
586 if (prev) {
587 prev->next = this->next;
588 g_free(this->pidvec);
589 g_free(this);
590 } else { /* start of the list */
591 s_snapshots = this->next;
592 g_free(this->pidvec);
593 g_free(this);
594 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500595
Dave Barach52642c32016-02-11 19:28:19 -0500596 /* Note: both will be NULL after last delete */
597 if (s_cursnap == NULL)
598 s_cursnap = s_snapshots;
599}
600
601/****************************************************************************
602 * write_snapshot
603 *
604 * VERY primitive right now - not endian or version independent, and only
605 * writes to "snapshots.g2" in the current directory
606 ****************************************************************************/
607static void write_snapshot(void)
608{
609 FILE *file = NULL;
610 snapshot_t *snap;
611 char *error = NULL;
612 int records = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500613
Dave Barach52642c32016-02-11 19:28:19 -0500614 if (s_snapshots == NULL) {
615 error = "No snapshots defined";
616 errno = 0;
617 }
618
619 if (!error) {
620 file = fopen("snapshots.g2", "w");
621 if (file == NULL) {
622 error = "Unable to open snapshots.g2";
623 }
624 }
625
626 /*
627 * Simply serialize the arch-dependent binary data, without a care in the
628 * world. Don't come running to me if you try to read it and crash.
629 */
630 for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500631 if (fwrite(&snap->geometry,
Dave Barach52642c32016-02-11 19:28:19 -0500632 sizeof(snap->geometry), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500633 fwrite(&snap->show_event,
Dave Barach52642c32016-02-11 19:28:19 -0500634 sizeof(snap->show_event), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500635 fwrite(snap->pidvec,
Dave Barach52642c32016-02-11 19:28:19 -0500636 sizeof(pid_sort_t) * g_npids, 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500637 fwrite(&snap->vscroll_value,
Dave Barach52642c32016-02-11 19:28:19 -0500638 sizeof(snap->vscroll_value), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500639 fwrite(&snap->summary_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500640 sizeof(snap->summary_mode), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500641 fwrite(&snap->color_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500642 sizeof(snap->color_mode), 1, file) != 1) {
643 error = "Error writing data";
644 }
645 records++;
646 }
647
648 if (!error) {
649 if (fclose(file)) {
650 error = "Unable to close file";
651 }
652 }
653
654 if (error) {
655 infobox(error, strerror(errno));
656 } else {
657 char buf[64];
Dave Barach9c8cfd32019-02-03 10:44:47 -0500658 snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2",
Dave Barach52642c32016-02-11 19:28:19 -0500659 records);
660 message_line(buf);
661 }
662}
663
664/****************************************************************************
665 * read_snapshot
666 *
667 * VERY primitive right now - not endian or version independent, and only reads
668 * from "snapshots.g2" in the current directory
669 ****************************************************************************/
670static void read_snapshot(void)
671{
672 FILE *file;
673 snapshot_t *snap, *next_snap;
674 snapshot_t *new_snaps = NULL;
675 char *error = NULL;
676 int len, i, records = 0;
677 pid_data_t *pp;
678
679 file = fopen("snapshots.g2", "r");
680 if (file == NULL) {
681 error = "Unable to open snapshots.g2";
682 }
683
684 /*
685 * Read in the snapshots and link them together. We insert them backwards,
686 * but that's tolerable. If the data is in anyway not what we expect, we'll
687 * probably crash. Sorry.
688 */
689 while (!error && !feof(file)) {
690 snap = g_malloc(sizeof(*snap));
691 snap->pidvec = NULL; /* so we can free this if there's an error */
692
693 len = fread(&snap->geometry, sizeof(snap->geometry), 1, file);
694 if (len == 0) {
695 /* EOF */
696 g_free(snap);
697 break;
698 } else {
699 /* insert into list straight away */
700 snap->next = new_snaps;
701 new_snaps = snap;
702 }
703 if (len != 1) {
704 error = "Problem reading first item from file";
705 break;
706 }
707 if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) {
708 error = "Problem reading second item from file";
709 break;
710 }
711 len = sizeof(pid_sort_t) * g_npids;
712 snap->pidvec = g_malloc(len);
713 if (fread(snap->pidvec, len, 1, file) != 1) {
714 error = "Problem reading third item from file";
715 break;
716 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500717 if (fread(&snap->vscroll_value,
Dave Barach52642c32016-02-11 19:28:19 -0500718 sizeof(snap->vscroll_value), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500719 fread(&snap->summary_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500720 sizeof(snap->summary_mode), 1, file) != 1 ||
Dave Barach9c8cfd32019-02-03 10:44:47 -0500721 fread(&snap->color_mode,
Dave Barach52642c32016-02-11 19:28:19 -0500722 sizeof(snap->color_mode), 1, file) != 1) {
723 error = "Problem reading final items from file";
724 break;
725 }
726
727 /*
728 * Fix up the pointers from the sorted pid vector back into our pid
729 * data objects, by walking the linked list of pid_data_t objects for
730 * every one looking for a match. This is O(n^2) grossness, but in real
731 * life there aren't that many pids, and it seems zippy enough.
732 */
733 for (i = 0; i < g_npids; i++) {
734 for (pp = g_pid_data_list; pp != NULL; pp = pp->next) {
735 if (pp->pid_value == snap->pidvec[i].pid_value) {
736 break;
737 }
738 }
739 if (pp != NULL) {
740 snap->pidvec[i].pid = pp;
741 } else {
742 error = "Snapshot file referenced unknown pids";
743 break;
744 }
745 }
746
747 records++;
748 }
749
750 if (!error) {
751 if (fclose(file)) {
752 error = "Unable to close file";
753 }
754 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500755
Dave Barach52642c32016-02-11 19:28:19 -0500756 if (error) {
757 /*
758 * Problem - clear up any detritus
759 */
760 infobox(error, strerror(errno));
761 for (snap = new_snaps; snap != NULL; snap = next_snap) {
762 next_snap = snap->next;
763 g_free(snap);
764 g_free(snap->pidvec);
765 }
766 } else {
767 /*
768 * Success! trash the old snapshots and replace with the new
769 */
770 for (snap = s_snapshots; snap != NULL; snap = next_snap) {
771 next_snap = snap->next;
772 g_free(snap->pidvec);
773 g_free(snap);
774 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500775
Dave Barach52642c32016-02-11 19:28:19 -0500776 s_cursnap = s_snapshots = new_snaps;
777 }
778
779 if (error) {
780 infobox(error, strerror(errno));
781 } else {
782 char buf[64];
Dave Barach9c8cfd32019-02-03 10:44:47 -0500783 snprintf(buf, sizeof(buf),
Dave Barach52642c32016-02-11 19:28:19 -0500784 "Read %d snapshots from snapshots.g2", records);
785 message_line(buf);
786 }
787}
788
789/****************************************************************************
790* set_color
791*
792* Set the color for the specified pid_index, or COLOR_DEFAULT to return it
793* to the usual black.
794****************************************************************************/
795#define COLOR_DEFAULT (-1)
796static void set_color(int pid_index)
797{
Dave Barach2c35e582017-04-03 10:22:17 -0400798 pid_sort_t *psp;
799
800 psp = (g_pids + pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -0500801
Dave Barach2c35e582017-04-03 10:22:17 -0400802 if (psp->selected)
803 gdk_gc_set_foreground(da->style->black_gc, &s_color[0]);
804 else if (pid_index == COLOR_DEFAULT || !color_mode) {
Dave Barach52642c32016-02-11 19:28:19 -0500805 gdk_gc_set_foreground(da->style->black_gc, &fg_black);
806 } else {
Dave Barach9c8cfd32019-02-03 10:44:47 -0500807 gdk_gc_set_foreground(da->style->black_gc,
Dave Barach52642c32016-02-11 19:28:19 -0500808 &s_color[g_pids[pid_index].color_index]);
809 }
810}
811
812/****************************************************************************
813* toggle_event_select
814****************************************************************************/
815
Dave Barach2c35e582017-04-03 10:22:17 -0400816static int toggle_event_select(GdkEventButton *event, v1_geometry_t *vp)
Dave Barach52642c32016-02-11 19:28:19 -0500817{
818 int pid_index, start_index;
819 int x, y;
820 GdkRectangle *rp;
821 GdkRectangle hit_rect;
Dave Barach11fb09e2020-08-06 12:10:09 -0400822 GdkRectangle placeholder;
Dave Barach52642c32016-02-11 19:28:19 -0500823 event_t *ep;
824 event_def_t *edp;
825 char tmpbuf [1024];
826 double time_per_pixel;
827
828 if (g_nevents == 0)
Dave Barach2c35e582017-04-03 10:22:17 -0400829 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500830
831 time_per_pixel = dtime_per_pixel(vp);
832
833 start_index = find_event_index (vp->minvistime);
834
835 /* Too far right? */
836 if (start_index >= g_nevents)
Dave Barach2c35e582017-04-03 10:22:17 -0400837 return 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500838
839 /*
Dave Barach52642c32016-02-11 19:28:19 -0500840 * To see if the mouse hit a visible event, use a variant
841 * of the event display loop.
842 */
843
844 hit_rect.x = (int)event->x;
845 hit_rect.y = (int)event->y;
846 hit_rect.width = 1;
847 hit_rect.height = 1;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500848
Dave Barach52642c32016-02-11 19:28:19 -0500849 ep = (g_events + start_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -0500850
851 while ((ep->time < vp->maxvistime) &&
Dave Barach52642c32016-02-11 19:28:19 -0500852 (ep < (g_events + g_nevents))) {
853 pid_index = ep->pid->pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500854
Dave Barach52642c32016-02-11 19:28:19 -0500855 /* First filter: pid out of range */
856 if ((pid_index < vp->first_pid_index) ||
857 (pid_index >= vp->first_pid_index + vp->npids)) {
858 ep++;
859 continue;
860 }
861
862 /* Second filter: event hidden */
863 edp = find_event_definition (ep->code);
864 if (!edp->selected) {
865 ep++;
866 continue;
867 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500868
869 /*
Dave Barach52642c32016-02-11 19:28:19 -0500870 * At this point, we know that the point is at least on the
Dave Barach9c8cfd32019-02-03 10:44:47 -0500871 * screen. See if the mouse hit within the bounding box
Dave Barach52642c32016-02-11 19:28:19 -0500872 */
873
Dave Barach9c8cfd32019-02-03 10:44:47 -0500874 /*
Dave Barach52642c32016-02-11 19:28:19 -0500875 * $$$$ maybe keep looping until off the edge,
876 * maintain a "best hit", then declare that one the winner?
877 */
878
879 pid_index -= vp->first_pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500880
Dave Barach52642c32016-02-11 19:28:19 -0500881 y = pid_index*vp->strip_height + vp->event_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500882
883 x = vp->pid_ax_width +
Dave Barach52642c32016-02-11 19:28:19 -0500884 (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel);
885
886 /* Perhaps we're trying to toggle the detail box? */
887 if (ep->flags & EVENT_FLAG_SELECT) {
888 /* Figure out the dimensions of the detail box */
889 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
890 rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED);
Dave Barach11fb09e2020-08-06 12:10:09 -0400891 if (gdk_rectangle_intersect(rp, &hit_rect, &placeholder)) {
Dave Barach52642c32016-02-11 19:28:19 -0500892 ep->flags &= ~EVENT_FLAG_SELECT;
893 view1_display_when_idle();
Dave Barach2c35e582017-04-03 10:22:17 -0400894 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500895 }
Dave Barach9c8cfd32019-02-03 10:44:47 -0500896 }
Dave Barach52642c32016-02-11 19:28:19 -0500897
Dave Barach3e07a4a2020-04-04 10:05:48 -0400898 snprintf(tmpbuf, sizeof(tmpbuf), "%ld", ep->code);
Dave Barach52642c32016-02-11 19:28:19 -0500899
900 /* Figure out the dimensions of the regular box */
901 rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT);
902
Dave Barach11fb09e2020-08-06 12:10:09 -0400903 if (gdk_rectangle_intersect(rp, &hit_rect, &placeholder)) {
Dave Barach52642c32016-02-11 19:28:19 -0500904 /* we hit the rectangle. */
905 if (ep->flags & EVENT_FLAG_SELECT) {
906 ep->flags &= ~EVENT_FLAG_SELECT;
907 view1_display_when_idle();
Dave Barach2c35e582017-04-03 10:22:17 -0400908 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500909 } else {
910 set_color(ep->pid->pid_index);
911
912 /* It wasn't selected, so put up the detail box */
913 format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp);
914 tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED);
915 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK);
916 ep->flags |= EVENT_FLAG_SELECT;
917 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
918 s_last_selected_event = ep;
919 }
Dave Barach2c35e582017-04-03 10:22:17 -0400920 return 0;
Dave Barach52642c32016-02-11 19:28:19 -0500921 }
922 ep++;
923 }
Dave Barach2c35e582017-04-03 10:22:17 -0400924 return -1;
Dave Barach52642c32016-02-11 19:28:19 -0500925}
926
927/****************************************************************************
Dave Barach2c35e582017-04-03 10:22:17 -0400928* toggle_track_select
929****************************************************************************/
930
Dave Barach9c8cfd32019-02-03 10:44:47 -0500931static void toggle_track_select (GdkEventButton *event,
Dave Barach2c35e582017-04-03 10:22:17 -0400932 v1_geometry_t *vp)
933{
934 int i;
935 int pid_index;
936 int y, delta_y;
937 pid_sort_t *psp;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500938
Dave Barach2c35e582017-04-03 10:22:17 -0400939 if (g_nevents == 0)
940 return;
941
942 /* Scan pid/track axis locations, looking for a match */
943 for (i = 0; i < vp->npids; i++) {
944 y = i*vp->strip_height + vp->pid_ax_offset;
945 delta_y = y - event->y;
946 if (delta_y < 0)
947 delta_y = -delta_y;
948 if (delta_y < 10) {
949 goto found;
950 }
951
952 }
953 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
954 return;
Dave Barach9c8cfd32019-02-03 10:44:47 -0500955
Dave Barach2c35e582017-04-03 10:22:17 -0400956 found:
957 pid_index = i + vp->first_pid_index;
958 psp = (g_pids + pid_index);
959 psp->selected ^= 1;
960 view1_display_when_idle();
961}
962
963/****************************************************************************
964* deselect_tracks
965****************************************************************************/
966static void deselect_tracks (void)
967{
968 int i;
969
970 for (i = 0; i < g_npids; i++)
971 g_pids[i].selected = 0;
972
973}
974
975
976/****************************************************************************
Dave Barach52642c32016-02-11 19:28:19 -0500977* move_current_track
978****************************************************************************/
979
980typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type;
981
Dave Barach9c8cfd32019-02-03 10:44:47 -0500982static void move_current_track(GdkEventButton *event,
Dave Barach52642c32016-02-11 19:28:19 -0500983 v1_geometry_t *vp,
984 move_type type)
985{
986 int i;
987 int pid_index;
988 int y, delta_y;
989 pid_sort_t *new_pidvec;
990 pid_sort_t *psp;
991 pid_sort_t *pold, *pnew;
992 pid_data_t *pp;
993
994 if (g_nevents == 0)
995 return;
996
997 /* Scan pid/track axis locations, looking for a match */
998 for (i = 0; i < vp->npids; i++) {
999 y = i*vp->strip_height + vp->pid_ax_offset;
1000 delta_y = y - event->y;
1001 if (delta_y < 0)
1002 delta_y = -delta_y;
1003 if (delta_y < 10) {
1004 goto found;
1005 }
1006
1007 }
1008 infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again");
1009 return;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001010
Dave Barach52642c32016-02-11 19:28:19 -05001011 found:
1012 pid_index = i + vp->first_pid_index;
1013
Dave Baracha8ed6bd2017-04-04 08:00:23 -04001014 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001015 pold = g_pids;
1016 pnew = new_pidvec;
1017
1018 if (type == MOVE_TOP) {
1019 /* move to top */
1020 *pnew++ = g_pids[pid_index];
1021 for (i = 0; i < pid_index; i++)
1022 *pnew++ = *pold++;
1023 pold++;
1024 i++;
1025 for (; i < g_npids; i++)
1026 *pnew++ = *pold++;
1027 } else {
1028 /* move to bottom */
1029 for (i = 0; i < pid_index; i++)
1030 *pnew++ = *pold++;
1031 pold++;
1032 i++;
1033 for (; i < g_npids; i++)
1034 *pnew++ = *pold++;
1035 *pnew = g_pids[pid_index];
1036 }
1037
1038 g_free(g_pids);
1039 g_pids = new_pidvec;
1040
1041 /*
Dave Barach9c8cfd32019-02-03 10:44:47 -05001042 * Revert the pid_index mapping to an identity map,
Dave Barach52642c32016-02-11 19:28:19 -05001043 */
1044 psp = g_pids;
1045
1046 for (i = 0; i < g_npids; i++) {
1047 pp = psp->pid;
1048 pp->pid_index = i;
1049 psp++;
1050 }
1051 view1_display_when_idle();
1052}
1053
1054/****************************************************************************
1055* zoom_event
Dave Barach9c8cfd32019-02-03 10:44:47 -05001056* Process a zoom gesture. The use of doubles is required to avoid
Dave Barach52642c32016-02-11 19:28:19 -05001057* truncating the various variable values, which in turn would lead to
1058* some pretty random-looking zoom responses.
1059****************************************************************************/
1060
1061void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp)
1062{
1063 double xrange;
1064 double time_per_pixel;
1065 double width_in_pixels;
1066 double center_on_time, width_in_time;
1067 double center_on_pixel;
1068
Dave Barach9c8cfd32019-02-03 10:44:47 -05001069 /*
1070 * Clip the zoom area to the event display area.
Dave Barach52642c32016-02-11 19:28:19 -05001071 * Otherwise, center_on_time - width_in_time is in hyperspace
Dave Barach9c8cfd32019-02-03 10:44:47 -05001072 * to the left of zero
Dave Barach52642c32016-02-11 19:28:19 -05001073 */
Dave Barach9c8cfd32019-02-03 10:44:47 -05001074
Dave Barach52642c32016-02-11 19:28:19 -05001075 if (e1->x < vp->pid_ax_width)
1076 e1->x = vp->pid_ax_width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001077
Dave Barach52642c32016-02-11 19:28:19 -05001078 if (e2->x < vp->pid_ax_width)
1079 e2->x = vp->pid_ax_width;
1080
1081 if (e2->x == e1->x)
1082 goto loser_zoom_repaint;
1083
1084 xrange = (double) (e2->x - e1->x);
1085 if (xrange < 0.00)
1086 xrange = -xrange;
1087
1088 /* Actually, width in pixels of half the zoom area */
1089 width_in_pixels = xrange / 2.00;
1090 time_per_pixel = dtime_per_pixel(vp);
1091 width_in_time = width_in_pixels * time_per_pixel;
1092
1093 /* Center the screen on the center of the zoom area */
Dave Barach9c8cfd32019-02-03 10:44:47 -05001094 center_on_pixel = (double)((e2->x + e1->x) / 2.00) -
Dave Barach52642c32016-02-11 19:28:19 -05001095 (double)vp->pid_ax_width;
1096 center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime;
1097
1098 /*
1099 * Transform back to 64-bit integer microseconds, reset the
Dave Barach9c8cfd32019-02-03 10:44:47 -05001100 * scrollbar, schedule a repaint.
Dave Barach52642c32016-02-11 19:28:19 -05001101 */
1102 vp->minvistime = (ulonglong)(center_on_time - width_in_time);
1103 vp->maxvistime = (ulonglong)(center_on_time + width_in_time);
1104
1105loser_zoom_repaint:
1106 recompute_hscrollbar();
Dave Barach9c8cfd32019-02-03 10:44:47 -05001107
Dave Barach52642c32016-02-11 19:28:19 -05001108 view1_display_when_idle();
1109}
1110
1111/****************************************************************************
1112* scroll_y
1113*
1114* Scroll up or down by the specified delta
1115*
1116****************************************************************************/
1117static void scroll_y(int delta)
1118{
1119 int new_index = s_v1->first_pid_index + delta;
1120 if (new_index + s_v1->npids > g_npids)
1121 new_index = g_npids - s_v1->npids;
1122 if (new_index < 0)
1123 new_index = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001124
Dave Barach52642c32016-02-11 19:28:19 -05001125 if (new_index != s_v1->first_pid_index) {
1126 s_v1->first_pid_index = new_index;
1127 GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index;
1128 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1129 view1_display_when_idle();
1130 }
1131}
1132
1133/****************************************************************************
1134* view1_handle_key_press_event
1135* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1136*
1137* This routine implements hotkeys for the Quake generation:
1138*
1139* W - zoom in
1140* S - zoom out
1141* A - pan left
1142* D - pan right
1143* R - pan up
1144* F - pan down
1145* T - more traces
1146* G - fewer traces
1147*
1148* E - toggle summary mode
1149* C - toggle color mode
1150*
1151* X - take snapshot
1152* Z - next snapshot
1153* P - persist snapshots to file
1154* L - load snapshots from file
1155*
1156* ctrl-Q - exit
1157*
1158****************************************************************************/
1159gint
1160view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event)
1161{
1162 long long delta;
1163
1164 switch (event->keyval) {
1165 case GDK_w: // zoom in
1166 view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON);
1167 break;
1168
1169 case GDK_s: // zoom out
1170 view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON);
1171 break;
1172
1173 case GDK_a: // pan left
1174 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1175 if (s_v1->minvistime < delta) {
1176 delta = s_v1->minvistime;
1177 }
1178 s_v1->minvistime -= delta;
1179 s_v1->maxvistime -= delta;
1180 recompute_hscrollbar();
1181 break;
1182
1183 case GDK_d: // pan right
1184 delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
1185 if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) {
1186 /*
1187 * @@@ this doesn't seem to quite reach the far right hand
1188 * side correctly - not sure why.
1189 */
1190 delta = g_events[g_nevents - 1].time - s_v1->maxvistime;
1191 }
1192 s_v1->minvistime += delta;
1193 s_v1->maxvistime += delta;
1194 recompute_hscrollbar();
1195 break;
1196
1197 case GDK_r: // pan up
1198 scroll_y(-1);
1199 break;
1200
1201 case GDK_f: // pan down
1202 scroll_y(+1);
1203 break;
1204
1205 case GDK_t: // fewer tracks
1206 view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON);
1207 break;
1208
1209 case GDK_g: // more tracks
1210 view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON);
1211 break;
1212
1213 case GDK_e: // toggle summary mode
1214 view1_button_click_callback
1215 (NULL, (gpointer)(unsigned long long)
1216 (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON));
1217 break;
1218
1219 case GDK_c: // toggle color mode
1220 color_mode ^= 1;
1221 view1_display_when_idle();
1222 break;
1223
1224 case GDK_p: // persist snapshots
1225 write_snapshot();
1226 break;
1227
1228 case GDK_l: // load snapshots
1229 read_snapshot();
1230 break;
1231
1232 case GDK_x: // take snapshot
1233 view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON);
1234 break;
1235
1236 case GDK_z: // next snapshot
1237 view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON);
1238 break;
1239
1240 case GDK_q: // ctrl-q is exit
1241 if (event->state & GDK_CONTROL_MASK) {
1242 gtk_main_quit();
1243 }
1244 break;
1245 }
1246 return TRUE;
1247}
1248
1249/****************************************************************************
1250* button_press_event
1251* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h
1252*
1253* This routine implements three functions: zoom-to-area, time ruler, and
Dave Barach9c8cfd32019-02-03 10:44:47 -05001254* show/hide event detail popup.
Dave Barach52642c32016-02-11 19:28:19 -05001255*
Dave Barach9c8cfd32019-02-03 10:44:47 -05001256* The left mouse button (button 1) has two simultaneous functions: event
Dave Barach52642c32016-02-11 19:28:19 -05001257* detail popup, and zoom-to-area. If the press and release events occur
1258* within a small delta-x, it's a detail popup event. Otherwise, it's
1259* an area zoom.
1260*
1261* The right mouse button (button 3) implements the time ruler.
1262****************************************************************************/
1263
1264static gint
1265button_press_event (GtkWidget *widget, GdkEventButton *event)
1266{
1267 static GdkEventButton press1_event;
1268 static boolean press1_valid;
1269 static GdkEventButton press3_event;
1270 static guint32 last_truler_time;
1271 static boolean press3_valid;
1272 static boolean zoom_bar_up;
1273 int time_ax_y, xdelta;
1274 char tmpbuf [128];
1275 double time_per_pixel;
1276
1277 time_ax_y = 0;
1278
1279 switch(event->type) {
1280 case GDK_BUTTON_PRESS:
1281 /* Capture the appropriate starting point */
1282 if (event->button == 1) {
1283 press1_valid = TRUE;
1284 press1_event = *event;
1285 return(TRUE);
1286 }
1287 if (event->button == 3) {
1288 press3_valid = TRUE;
1289 press3_event = *event;
1290 return(TRUE);
1291 }
1292 return(TRUE);
1293
1294 case GDK_BUTTON_RELEASE:
1295 /* Time ruler */
1296 if (press3_valid) {
1297 press3_valid = FALSE;
1298 /* Fix the cursor, and repaint the screen from scratch */
1299 gdk_window_set_cursor (da->window, norm_cursor);
1300 view1_display_when_idle();
1301 return(TRUE);
1302 }
1303 /* Event select / zoom-to-area */
1304 if (press1_valid) {
1305 press1_valid = FALSE;
1306 xdelta = (int)(press1_event.x - event->x);
1307 if (xdelta < 0)
1308 xdelta = -xdelta;
1309
1310 /* is the mouse more or less where it started? */
1311 if (xdelta < 10) {
1312 /* Control-left-mouse => sink the track */
1313 /* Shift-left-mouse => raise the track */
1314 if ((press1_event.state & GDK_CONTROL_MASK) ==
1315 GDK_CONTROL_MASK) {
1316 move_current_track(event, s_v1, MOVE_BOTTOM);
1317 } else if ((press1_event.state & GDK_SHIFT_MASK) ==
1318 GDK_SHIFT_MASK) {
1319 move_current_track(event, s_v1, MOVE_TOP);
1320 } else {
Dave Barach2c35e582017-04-03 10:22:17 -04001321 /* No modifiers: toggle the event / select track */
1322 if (toggle_event_select(event, s_v1))
1323 toggle_track_select(event, s_v1);
Dave Barach52642c32016-02-11 19:28:19 -05001324 }
1325 /* Repaint to get rid of the zoom bar */
1326 if (zoom_bar_up) {
1327 /* Fix the cursor and leave. No zoom */
1328 gdk_window_set_cursor (da->window, norm_cursor);
1329 zoom_bar_up = FALSE;
1330 break;
1331 }
1332 } else { /* mouse moved enough to zoom */
1333 zoom_event(&press1_event, event, s_v1);
1334 gdk_window_set_cursor (da->window, norm_cursor);
1335 zoom_bar_up = FALSE;
1336 }
1337 } else if (event->button == 4) {
1338 /* scroll wheel up */
1339 scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1);
1340 } else if (event->button == 5) {
1341 /* scroll wheel down */
1342 scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1);
1343 }
1344 return(TRUE);
1345
1346 case GDK_MOTION_NOTIFY:
1347 /* Button one followed by motion: draw zoom fence and fix cursor */
1348 if (press1_valid) {
1349 /* Fence, cursor already set */
1350 if (zoom_bar_up)
1351 return(TRUE);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001352
Dave Barach52642c32016-02-11 19:28:19 -05001353 xdelta = (int)(press1_event.x - event->x);
1354 if (xdelta < 0)
1355 xdelta = -xdelta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001356
Dave Barach52642c32016-02-11 19:28:19 -05001357 /* Haven't moved enough to declare a zoom sequence yet */
Dave Barach9c8cfd32019-02-03 10:44:47 -05001358 if (xdelta < 10)
Dave Barach52642c32016-02-11 19:28:19 -05001359 return(TRUE);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001360
Dave Barach52642c32016-02-11 19:28:19 -05001361 /* Draw the zoom fence, use the key-down X coordinate */
1362 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001363
1364 line((int)(press1_event.x), s_v1->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05001365 (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK);
1366 tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset,
1367 TBOX_DRAW_BOXED);
1368 gdk_window_set_cursor(da->window, zi_cursor);
1369 zoom_bar_up = TRUE;
1370 return(TRUE);
1371 }
1372 if (press3_valid) {
1373 double nsec;
1374
1375 gdk_window_set_cursor(da->window, zi_cursor);
1376
Dave Barach9c8cfd32019-02-03 10:44:47 -05001377 /*
Dave Barach52642c32016-02-11 19:28:19 -05001378 * Some filtration is needed on Solaris, or the server will hang
1379 */
1380 if (event->time - last_truler_time < 75)
1381 return(TRUE);
1382
1383 last_truler_time = event->time;
1384
Dave Barach9c8cfd32019-02-03 10:44:47 -05001385 line((int)(press3_event.x), s_v1->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05001386 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1387
1388 xdelta = (int)(press3_event.x - event->x);
1389 if (xdelta < 0)
1390 xdelta = -xdelta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001391
1392 time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) /
1393 ((double)(s_v1->total_width - s_v1->pid_ax_width));
Dave Barach52642c32016-02-11 19:28:19 -05001394
1395 time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset;
1396
Dave Barach9c8cfd32019-02-03 10:44:47 -05001397 line((int)(press3_event.x), s_v1->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05001398 (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK);
1399 /*
1400 * Note: use a fixed-width format so it looks like we're
Dave Barach9c8cfd32019-02-03 10:44:47 -05001401 * erasing and redrawing the box.
Dave Barach52642c32016-02-11 19:28:19 -05001402 */
1403 nsec = ((double)xdelta)*time_per_pixel;
1404 if (nsec >1e9) {
Dave Barach3e07a4a2020-04-04 10:05:48 -04001405 snprintf(tmpbuf, sizeof(tmpbuf), "%8.3f sec ", nsec/1e9);
Dave Barach52642c32016-02-11 19:28:19 -05001406 } else if (nsec > 1e6) {
Dave Barach3e07a4a2020-04-04 10:05:48 -04001407 snprintf(tmpbuf, sizeof(tmpbuf), "%8.3f msec", nsec/1e6);
Dave Barach52642c32016-02-11 19:28:19 -05001408 } else if (nsec > 1e3) {
Dave Barach3e07a4a2020-04-04 10:05:48 -04001409 snprintf(tmpbuf, sizeof(tmpbuf), "%8.3f usec", nsec/1e3);
Dave Barach52642c32016-02-11 19:28:19 -05001410 } else {
Dave Barach3e07a4a2020-04-04 10:05:48 -04001411 snprintf(tmpbuf, sizeof(tmpbuf), "%8.0f nsec", nsec);
Dave Barach52642c32016-02-11 19:28:19 -05001412 }
Dave Barach2c35e582017-04-03 10:22:17 -04001413 s_v1->last_time_interval = nsec;
Dave Barach52642c32016-02-11 19:28:19 -05001414 tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset,
1415 TBOX_DRAW_BOXED);
1416 return(TRUE);
1417 }
1418
1419 default:
1420 break;
1421#ifdef DEBUG
1422 g_print("button:\ttype = %d\n", event->type);
1423 g_print("\twindow = 0x%x\n", event->window);
1424 g_print("\tsend_event = %d\n", event->send_event);
1425 g_print("\ttime = %d\n", event->time);
1426 g_print("\tx = %6.2f\n", event->x);
1427 g_print("\ty = %6.2f\n", event->y);
1428 g_print("\tpressure = %6.2f\n", event->pressure);
1429 g_print("\txtilt = %6.2f\n", event->xtilt);
1430 g_print("\tytilt = %6.2f\n", event->ytilt);
1431 g_print("\tstate = %d\n", event->state);
1432 g_print("\tbutton = %d\n", event->button);
1433 g_print("\tsource = %d\n", event->source);
1434 g_print("\tdeviceid = %d\n", event->deviceid);
1435 g_print("\tx_root = %6.2f\n", event->x_root);
1436 g_print("\ty_root = %6.2f\n", event->y_root);
1437 return(TRUE);
1438#endif
1439 }
1440
1441 view1_display_when_idle();
1442
1443 return(TRUE);
1444}
1445
1446/****************************************************************************
1447* configure_event
1448* Happens when the window manager resizes the viewer's main window.
1449****************************************************************************/
1450
1451static gint
1452configure_event (GtkWidget *widget, GdkEventConfigure *event)
1453{
1454 /* Toss the previous drawing area backing store pixmap */
1455 if (pm)
1456 gdk_pixmap_unref(pm);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001457
Dave Barach52642c32016-02-11 19:28:19 -05001458 /* Create a new pixmap, paint it */
1459 pm = gdk_pixmap_new(widget->window,
1460 widget->allocation.width,
1461 widget->allocation.height,
1462 -1);
1463 gdk_draw_rectangle (pm,
1464 widget->style->white_gc,
1465 TRUE,
1466 0, 0,
1467 widget->allocation.width,
1468 widget->allocation.height);
1469
1470 /* Reset the view geometry parameters, as required */
1471 s_v1->total_width = widget->allocation.width;
1472 s_v1->total_height = widget->allocation.height;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001473 s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) /
Dave Barach52642c32016-02-11 19:28:19 -05001474 s_v1->strip_height;
1475
1476 /* Schedule a repaint */
1477 view1_display_when_idle();
1478 return(TRUE);
1479}
1480
1481/****************************************************************************
1482* expose_event
1483* Use backing store to fix the screen.
1484****************************************************************************/
1485static gint expose_event (GtkWidget *widget, GdkEventExpose *event)
1486{
1487 gdk_draw_pixmap(widget->window,
1488 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1489 pm,
1490 event->area.x, event->area.y,
1491 event->area.x, event->area.y,
1492 event->area.width, event->area.height);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001493
Dave Barach52642c32016-02-11 19:28:19 -05001494 return(FALSE);
1495}
1496
1497/****************************************************************************
1498* event_search_internal
1499* This routine searches forward from s_srchindex, looking for s_srchcode;
1500* wraps at the end of the buffer.
1501****************************************************************************/
1502
1503boolean event_search_internal (void)
1504{
1505 event_t *ep;
1506 int i;
1507 int index;
1508 int pid_index;
1509 boolean full_redisplay = FALSE;
1510 ulonglong current_width;
1511 char tmpbuf [64];
1512
1513 /* No events yet? Act like the search worked, to avoid a loop */
1514 if (g_nevents == 0)
1515 return(TRUE);
1516
1517 ep = (g_events + s_srchindex);
1518 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1519
Dave Barach9c8cfd32019-02-03 10:44:47 -05001520 /*
Dave Barach52642c32016-02-11 19:28:19 -05001521 * Assume the user wants to search [plus or minus]
1522 * from where they are.
1523 */
1524#ifdef notdef
1525 if (ep->time < s_v1->minvistime)
1526 s_srchindex = find_event_index (s_v1->minvistime);
1527#endif
1528
1529 for (i = 1; i <= g_nevents; i++) {
1530 index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ?
1531 (s_srchindex - i) % g_nevents :
1532 (i + s_srchindex) % g_nevents;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001533
Dave Barach52642c32016-02-11 19:28:19 -05001534 ep = (g_events + index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001535
Dave Barach52642c32016-02-11 19:28:19 -05001536 if (ep->code == s_srchcode) {
1537 if (s_srchfail_up)
1538 message_line("");
1539 s_srchindex = index;
1540 pid_index = ep->pid->pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001541
Dave Barach52642c32016-02-11 19:28:19 -05001542 /* Need a vertical scroll? */
1543 if ((pid_index < s_v1->first_pid_index) ||
1544 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1545 if (pid_index > (g_npids - s_v1->npids))
1546 pid_index = (g_npids - s_v1->npids);
1547 s_v1->first_pid_index = pid_index;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001548 GTK_ADJUSTMENT(s_view1_vsadj)->value =
Dave Barach52642c32016-02-11 19:28:19 -05001549 (gdouble)s_v1->first_pid_index;
1550 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1551 full_redisplay = TRUE;
1552 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05001553
Dave Barach52642c32016-02-11 19:28:19 -05001554 /* Need a horizontal scroll? */
1555 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1556 current_width = (s_v1->maxvistime - s_v1->minvistime);
1557 if (ep->time < ((current_width+1) / 2)) {
1558 s_v1->minvistime = 0ll;
1559 s_v1->maxvistime = current_width;
1560 } else {
1561 s_v1->minvistime = ep->time - ((current_width+1)/2);
1562 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1563 }
1564 recompute_hscrollbar();
1565 full_redisplay = TRUE;
1566 }
1567 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1568 full_redisplay = TRUE;
1569
1570#ifdef NOTDEF
1571 if (!full_redisplay){
1572 if (!s_result_up) {
1573 s_result_up = TRUE;
1574 time_per_pixel = dtime_per_pixel(s_v1);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001575
Dave Barach52642c32016-02-11 19:28:19 -05001576 y = pid_index*s_v1->strip_height + s_v1->event_offset;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001577 x = s_v1->pid_ax_width +
1578 (int)(((double)(ep->time - s_v1->minvistime)) /
Dave Barach52642c32016-02-11 19:28:19 -05001579 time_per_pixel);
Dave Barach3e07a4a2020-04-04 10:05:48 -04001580 snprintf(tmpbuf, sizeof(tmpbuf), "SEARCH RESULT");
Dave Barach52642c32016-02-11 19:28:19 -05001581 tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED);
1582 line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK);
1583 } else {
1584 full_redisplay = TRUE;
1585 }
1586 }
1587#endif
1588
1589 if (full_redisplay)
1590 view1_display_when_idle();
1591 return(TRUE);
1592 }
1593 }
Dave Barach3e07a4a2020-04-04 10:05:48 -04001594 snprintf (tmpbuf, sizeof(tmpbuf),
1595 "Search for event %ld failed...\n", s_srchcode);
Dave Barach52642c32016-02-11 19:28:19 -05001596 message_line(tmpbuf);
1597 s_srchfail_up = TRUE;
1598 return(TRUE);
1599}
1600
1601/****************************************************************************
1602* event_search_callback
1603****************************************************************************/
1604
1605boolean event_search_callback (char *s)
1606{
1607 /* No events yet? Act like the search worked, to avoid a loop */
1608 if (g_nevents == 0)
1609 return(TRUE);
1610
1611 s_srchcode = atol(s);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001612
Dave Barach52642c32016-02-11 19:28:19 -05001613 if (s_srchcode == 0)
1614 return(FALSE);
1615
1616 return(event_search_internal());
1617}
1618
Dave Barach9c8cfd32019-02-03 10:44:47 -05001619
1620/****************************************************************************
1621* anomaly_statistics_init
1622****************************************************************************/
1623
1624static int anomaly_statistics_init (void)
1625{
1626 elog_event_t *eep;
1627 u32 data;
1628 event_t *ep;
1629 pid_data_t *pid;
1630 int i;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001631 f64 fdata;
1632
1633 /* Gather summary statistics... */
1634 ep = g_events;
1635
1636 vec_reset_length (s_v1->means);
1637 vec_reset_length (s_v1->matches);
1638 vec_reset_length (s_v1->variances);
1639 vec_reset_length (s_v1->two_stddevs);
Dave Barach3117ad82019-02-04 17:41:29 -05001640 vec_reset_length (s_v1->mins);
1641 vec_reset_length (s_v1->maxes);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001642
1643 for (i = 0; i < g_nevents; i++) {
1644 if (ep->code != s_anomalycode) {
1645 ep++;
1646 continue;
1647 }
1648 pid = ep->pid;
Dave Barach9c8cfd32019-02-03 10:44:47 -05001649 vec_validate_init_empty (s_v1->matches, pid->pid_index, 0);
Dave Barach3117ad82019-02-04 17:41:29 -05001650 vec_validate_init_empty (s_v1->means, pid->pid_index, 0.0);
1651 vec_validate_init_empty (s_v1->mins, pid->pid_index, 0.0);
1652 vec_validate_init_empty (s_v1->maxes, pid->pid_index, 0.0);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001653 eep = get_clib_event (ep->datum);
1654 data = clib_mem_unaligned (eep->data, u32);
1655 fdata = data;
1656 s_v1->means[pid->pid_index] += fdata;
1657 s_v1->matches[pid->pid_index] += 1;
Dave Barach3117ad82019-02-04 17:41:29 -05001658 /* First data point? set min, max */
1659 if (PREDICT_FALSE(s_v1->matches[pid->pid_index] == 1)) {
1660 s_v1->mins[pid->pid_index] = fdata;
1661 s_v1->maxes[pid->pid_index] = fdata;
1662 } else {
1663 s_v1->mins[pid->pid_index] = (fdata < s_v1->mins[pid->pid_index]) ?
1664 fdata : s_v1->mins[pid->pid_index];
1665 s_v1->maxes[pid->pid_index] =
1666 (fdata > s_v1->maxes[pid->pid_index]) ?
1667 fdata : s_v1->maxes[pid->pid_index];
1668 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05001669 ep++;
1670 }
1671 if (vec_len (s_v1->matches) == 0)
1672 return -1;
1673
1674 /* Compute s_v1->means */
1675 for (i = 0; i < vec_len (s_v1->means); i++)
1676 s_v1->means[i] = s_v1->matches[i]
1677 ? (s_v1->means[i] / (f64) s_v1->matches[i]) : 0.0;
1678
1679 /* Compute s_v1->variances */
1680 ep = g_events;
1681 for (i = 0; i < g_nevents; i++) {
1682 if (ep->code != s_anomalycode) {
1683 ep++;
1684 continue;
1685 }
1686 pid = ep->pid;
1687 vec_validate_init_empty (s_v1->variances, pid->pid_index, 0);
1688 eep = get_clib_event (ep->datum);
1689 data = clib_mem_unaligned (eep->data, u32);
1690 fdata = data;
1691 s_v1->variances[pid->pid_index] +=
1692 (fdata - s_v1->means[pid->pid_index])
1693 * (fdata - s_v1->means[pid->pid_index]);
1694 ep++;
1695 }
1696
1697 /* Normalize variances */
1698 for (i = 0; i < vec_len (s_v1->variances); i++)
1699 s_v1->variances[i] = s_v1->matches[i]
1700 ? (s_v1->variances[i] / (f64) s_v1->matches[i]) : 0.0;
1701
1702 /* Compute the anomaly threshold, by default 2.5*stddev */
1703 for (i = 0; i < vec_len (s_v1->variances); i++)
1704 vec_add1 (s_v1->two_stddevs,
1705 s_v1->anomaly_threshold_stddevs * sqrt(s_v1->variances[i]));
1706 return 0;
1707}
1708
1709/****************************************************************************
1710* anomaly_search_internal
1711* This routine searches forward from s_srchindex, looking for s_srchcode;
1712* wraps at the end of the buffer.
1713****************************************************************************/
1714
1715boolean anomaly_search_internal (void)
1716{
1717 elog_event_t *eep;
1718 u32 data;
1719 event_t *ep;
1720 pid_data_t *pid;
1721 int i;
1722 int index;
1723 int pid_index;
1724 boolean full_redisplay = FALSE;
1725 ulonglong current_width;
1726 char tmpbuf [64];
1727 f64 fdata;
1728
1729 if (vec_len (s_v1->matches) == 0)
1730 anomaly_statistics_init();
1731
1732 ep = (g_events + s_srchindex);
1733 ep->flags &= ~EVENT_FLAG_SEARCHRSLT;
1734
1735 /*
1736 * If the user rearranged the screen, start from the minimum
1737 * visible time
1738 */
1739 if (ep->time < s_v1->minvistime)
1740 s_srchindex = find_event_index (s_v1->minvistime);
1741
1742 for (i = 1; i <= g_nevents; i++) {
1743 index = (i + s_srchindex) % g_nevents;
1744
1745 ep = (g_events + index);
1746 if (ep->code != s_anomalycode)
1747 continue;
1748 pid = ep->pid;
1749
1750 eep = get_clib_event (ep->datum);
1751 data = clib_mem_unaligned (eep->data, u32);
1752 fdata = data;
1753
1754 /*
1755 * Found an anomaly? Define an anomaly as a datum
1756 * greater than 2*stddev above average.
1757 */
1758 if ((fdata - s_v1->means[pid->pid_index]) >
1759 s_v1->two_stddevs[pid->pid_index]) {
1760 u8 *s;
1761
Dave Barach3117ad82019-02-04 17:41:29 -05001762 s = format (0, "%.1f*stddev {min,max,mean,threshold}: ",
Dave Barach9c8cfd32019-02-03 10:44:47 -05001763 s_v1->anomaly_threshold_stddevs);
1764
1765 for (i = 0; i < vec_len (s_v1->means); i++) {
Dave Barach3117ad82019-02-04 17:41:29 -05001766 if (s_v1->matches[i] > 0)
1767 s = format (s, "{%.0f, %.0f, %.0f, %.0f} ",
1768 s_v1->mins[i], s_v1->maxes[i],
1769 s_v1->means[i],
1770 s_v1->means[i]+s_v1->two_stddevs[i]);
1771 else
1772 s = format (s, "{no match} ");
Dave Barach9c8cfd32019-02-03 10:44:47 -05001773 }
1774
1775 message_line ((char *)s);
1776 vec_free (s);
1777
1778 s_srchindex = index;
1779 pid_index = ep->pid->pid_index;
1780
1781 /* Need a vertical scroll? */
1782 if ((pid_index < s_v1->first_pid_index) ||
1783 (pid_index >= s_v1->first_pid_index + s_v1->npids)) {
1784 if (pid_index > (g_npids - s_v1->npids))
1785 pid_index = (g_npids - s_v1->npids);
1786 s_v1->first_pid_index = pid_index;
1787 GTK_ADJUSTMENT(s_view1_vsadj)->value =
1788 (gdouble)s_v1->first_pid_index;
1789 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
1790 full_redisplay = TRUE;
1791 }
1792
1793 /* Need a horizontal scroll? */
1794 if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) {
1795 current_width = (s_v1->maxvistime - s_v1->minvistime);
1796 if (ep->time < ((current_width+1) / 2)) {
1797 s_v1->minvistime = 0ll;
1798 s_v1->maxvistime = current_width;
1799 } else {
1800 s_v1->minvistime = ep->time - ((current_width+1)/2);
1801 s_v1->maxvistime = ep->time + ((current_width+1)/2);
1802 }
1803 recompute_hscrollbar();
1804 full_redisplay = TRUE;
1805 }
1806 ep->flags |= EVENT_FLAG_SEARCHRSLT;
1807 full_redisplay = TRUE;
1808
1809 if (full_redisplay)
1810 view1_display_when_idle();
1811
1812 return(TRUE);
1813 }
1814 }
Dave Barach3e07a4a2020-04-04 10:05:48 -04001815 snprintf (tmpbuf, sizeof(tmpbuf),
1816 "Search for an anomalous event %ld failed...\n",
1817 s_anomalycode);
Dave Barach9c8cfd32019-02-03 10:44:47 -05001818 message_line(tmpbuf);
1819 s_srchfail_up = TRUE;
1820 return(TRUE);
1821}
1822
1823/****************************************************************************
1824* anomaly_search_callback
1825****************************************************************************/
1826
1827boolean anomaly_search_callback (char *s)
1828{
1829 ulong new_anomalycode;
1830
1831 /* No events yet? Act like the search worked, to avoid a loop */
1832 if (g_nevents == 0)
1833 return(TRUE);
1834
1835 new_anomalycode = atol(s);
1836
1837 if (new_anomalycode == 0)
1838 return(FALSE);
1839
1840 if (new_anomalycode != s_anomalycode ||
1841 vec_len (s_v1->matches) == 0) {
1842 s_anomalycode = new_anomalycode;
1843 if (anomaly_statistics_init()) {
1844 u8 *s;
1845
1846 s = format (0, "Search for an anomalous event %ld failed...\n",
1847 s_anomalycode);
1848 message_line ((char *) s);
1849 vec_free (s);
1850 return (TRUE);
1851 }
1852 }
1853 return(anomaly_search_internal());
1854}
1855
1856/****************************************************************************
1857* anomaly_threshold_callback
1858****************************************************************************/
1859
1860boolean anomaly_threshold_callback (char *s)
1861{
1862 f64 new_threshold;
1863
1864 /* No events yet? Act like the search worked, to avoid a loop */
1865 if (g_nevents == 0)
1866 return(TRUE);
1867
1868 new_threshold = atof (s);
1869
1870 if (new_threshold == 0.0 || new_threshold > 10.0)
1871 return(FALSE);
1872
1873 s_v1->anomaly_threshold_stddevs = new_threshold;
1874
1875 vec_reset_length (s_v1->means);
1876 vec_reset_length (s_v1->matches);
1877 vec_reset_length (s_v1->variances);
1878 vec_reset_length (s_v1->two_stddevs);
1879 return (TRUE);
1880}
1881
Dave Barach52642c32016-02-11 19:28:19 -05001882/****************************************************************************
1883* event_search
1884****************************************************************************/
1885
1886static void event_search (void)
1887{
1888 modal_dialog ("Event Search: Please Enter Event Code",
1889 "Invalid: Please Reenter Event Code", NULL,
1890 event_search_callback);
1891}
1892
1893/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05001894* anomaly_search
1895****************************************************************************/
1896
1897static void anomaly_search (void)
1898{
1899 modal_dialog ("Anomaly Search: Please Enter Event Code",
1900 "Invalid: Please Reenter Event Code", NULL,
1901 anomaly_search_callback);
1902}
1903
1904/****************************************************************************
1905* anomaly_threshold
1906****************************************************************************/
1907
1908static void anomaly_threshold (void)
1909{
1910 modal_dialog ("Anomaly Threshold: Please Enter Threshold",
1911 "Invalid: Please Reenter Threshold in Standard Deviations",
1912 NULL, anomaly_threshold_callback);
1913}
1914
1915/****************************************************************************
Dave Barach52642c32016-02-11 19:28:19 -05001916* init_track_colors
1917****************************************************************************/
1918static void init_track_colors(void)
1919{
1920 int i;
1921 unsigned hash;
1922 char *label_char;
1923 unsigned RGB[3];
1924 gboolean dont_care[g_npids];
1925
1926 /*
1927 * If we've already allocated the colors once, then in theory we should
1928 * just be able to re-order the GCs already created to match the new track
1929 * order; the track -> color mapping doesn't currently change at runtime.
1930 * However, it's easier just to allocate everything from fresh. As a nod in
1931 * the direction of politeness towards our poor abused X server, we at
1932 * least mop up the previously allocated GCs first, although in practice
Dave Barach9c8cfd32019-02-03 10:44:47 -05001933 * even omitting this didn't seem to cause a problem.
Dave Barach52642c32016-02-11 19:28:19 -05001934 */
1935 if (s_color != NULL ) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05001936 gdk_colormap_free_colors(gtk_widget_get_colormap(da),
Dave Barach52642c32016-02-11 19:28:19 -05001937 s_color, g_npids);
Dave Barachb7b92992018-10-17 10:38:51 -04001938 clib_memset(s_color, 0, sizeof(GdkColor) * g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05001939 } else {
1940 /*
1941 * First time through: allocate the array to hold the GCs.
1942 */
Dave Barach2c35e582017-04-03 10:22:17 -04001943 s_color = g_malloc(sizeof(GdkColor) * (g_npids+1));
Dave Barach52642c32016-02-11 19:28:19 -05001944 }
1945
1946 /*
1947 * Go through and assign a color for each track.
1948 */
Dave Barach2c35e582017-04-03 10:22:17 -04001949 /* Setup entry 0 in the colormap as pure red (for selection) */
1950 s_color[0] = fg_red;
1951
1952 for (i = 1; i < g_npids; i++) {
Dave Barach52642c32016-02-11 19:28:19 -05001953 /*
1954 * We compute the color from a hash of the thread name. That way we get
1955 * a distribution of different colors, and the same thread has the same
1956 * color across multiple data sets. Unfortunately, even though the
1957 * process name and thread id are invariant across data sets, the
1958 * process id isn't, so we want to exclude that from the hash. Since
1959 * the pid appears in parentheses after the process name and tid, we
1960 * can just stop at the '(' character.
1961 *
1962 * We could create a substring and use the CLIB Jenkins hash, but given
1963 * we're hashing ascii data, a suitable Bernstein hash is pretty much
1964 * just as good, and it's easiest just to compute it inline.
1965 */
1966 label_char = get_track_label(g_pids[i].pid_value);
1967 hash = 0;
1968 while (*label_char != '\0' && *label_char != '(') {
1969 hash = hash * 33 + *label_char++;
1970 }
1971 hash += hash >> 5; /* even out the lower order bits a touch */
1972
1973 /*
1974 * OK, now we have our hash. We get the color by using the first three
1975 * bytes of the hash for the RGB values (expanded from 8 to 16 bits),
1976 * and then use the fourth byte to choose one of R, G, B and mask this
1977 * one down. This ensures the color can't be too close to white and
1978 * therefore hard to see.
1979 *
1980 * We also drop the top bit of the green, since bright green on its own
1981 * is hard to see against white. Generally we err on the side of
1982 * keeping it dark, rather than using the full spectrum of colors. This
1983 * does result in something of a preponderance of muddy colors and a
1984 * bit of a lack of cheery bright ones, but at least you can read
1985 * everything. It would be nice to do better.
1986 */
1987 RGB[0] = (hash & 0xff000000) >> 16;
1988 RGB[1] = (hash & 0x007f0000) >> 8;
1989 RGB[2] = (hash & 0x0000ff00);
1990 RGB[hash % 3] &= 0x1fff;
1991
1992 {
1993 GdkColor color = {0, RGB[0], RGB[1], RGB[2]};
1994 s_color[i] = color;
1995 g_pids[i].color_index = i;
1996 }
1997 }
1998
1999 /*
2000 * Actually allocate the colors in one bulk operation. We ignore the return
2001 * values.
2002 */
Dave Barach9c8cfd32019-02-03 10:44:47 -05002003 gdk_colormap_alloc_colors(gtk_widget_get_colormap(da),
Dave Barach2c35e582017-04-03 10:22:17 -04002004 s_color, g_npids+1, FALSE, TRUE, dont_care);
Dave Barach52642c32016-02-11 19:28:19 -05002005}
2006
2007
2008/****************************************************************************
2009* chase_event_etc
2010* Reorder the pid_index fields so the viewer "chases" the last selected
2011* event.
2012****************************************************************************/
2013
2014static void chase_event_etc(enum chase_mode mode)
2015{
2016 pid_sort_t *psp, *new_pidvec;
2017 pid_data_t *pp;
2018 event_t *ep;
2019 int pids_mapped;
2020 ulong code_to_chase;
2021 ulong datum_to_chase;
2022 ulong pid_to_chase;
2023 int i;
2024 int winner;
2025
2026 if (!s_last_selected_event) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002027 infobox("No selected event",
Dave Barach52642c32016-02-11 19:28:19 -05002028 "\nPlease select an event and try again...\n");
2029 return;
2030 }
2031
2032 /* Clear all index assignments */
2033 psp = g_pids;
2034 for (i = 0; i < g_npids; i++) {
2035 pp = psp->pid;
2036 pp->pid_index = 0xFFFFFFFF;
2037 psp++;
2038 }
2039
2040 ep = s_last_selected_event;
2041 code_to_chase = ep->code;
2042 datum_to_chase = ep->datum;
2043 pid_to_chase = ep->pid->pid_value;
2044 pids_mapped = 0;
Dave Baracha8ed6bd2017-04-04 08:00:23 -04002045 new_pidvec = g_malloc0(sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05002046
2047 while (1) {
2048 if (srch_chase_dir == SRCH_CHASE_FORWARD) {
2049 if (ep >= g_events + g_nevents)
2050 break;
2051 } else {
2052 if (ep < g_events)
2053 break;
2054 }
2055
2056 winner = 0;
2057 switch(mode) {
2058 case CHASE_EVENT:
2059 if (ep->code == code_to_chase) {
2060 winner = 1;
2061 }
2062 break;
2063
2064 case CHASE_DATUM:
2065 if (ep->datum == datum_to_chase) {
2066 winner = 1;
2067 }
2068 break;
2069
2070 case CHASE_TRACK:
2071 if (ep->pid->pid_value == pid_to_chase) {
2072 winner = 1;
2073 }
2074 break;
2075
2076 default:
2077 infobox("BUG", "unknown mode in chase_event_etc\n");
2078 break;
2079 }
2080
2081 if (winner) {
2082 if (ep->pid->pid_index == 0xFFFFFFFF) {
2083 ep->pid->pid_index = pids_mapped;
2084 new_pidvec[pids_mapped].pid = ep->pid;
2085 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2086 new_pidvec[pids_mapped].color_index = 0;
2087 pids_mapped++;
2088 if (pids_mapped == g_npids)
2089 break;
2090 }
2091 }
2092 if (srch_chase_dir == SRCH_CHASE_FORWARD)
2093 ep++;
2094 else
2095 ep--;
2096 }
2097
2098 /* Pass 2, first-to-last, to collect stragglers */
2099 ep = g_events;
2100
2101 while (ep < g_events + g_nevents) {
2102 if (ep->pid->pid_index == 0xFFFFFFFF) {
2103 ep->pid->pid_index = pids_mapped;
2104 new_pidvec[pids_mapped].pid = ep->pid;
2105 new_pidvec[pids_mapped].pid_value = ep->pid->pid_value;
2106 new_pidvec[pids_mapped].color_index = 0;
2107 pids_mapped++;
2108 if (pids_mapped == g_npids)
2109 break;
2110 }
2111 ep++;
2112 }
2113
2114 if (pids_mapped != g_npids) {
2115 infobox("BUG", "\nDidn't map all pids in chase_event_etc\n");
2116 }
2117
2118 g_free (g_pids);
2119 g_pids = new_pidvec;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002120
Dave Barach52642c32016-02-11 19:28:19 -05002121 /*
2122 * The new g_pids vector contains the "chase" sort, so we revert
Dave Barach9c8cfd32019-02-03 10:44:47 -05002123 * the pid_index mapping to an identity map
Dave Barach52642c32016-02-11 19:28:19 -05002124 */
2125 psp = g_pids;
2126
2127 for (i = 0; i < g_npids; i++) {
2128 pp = psp->pid;
2129 pp->pid_index = i;
2130 psp++;
2131 }
2132
2133 /* AutoScroll the PID axis so we show the first "chased" event */
2134 s_v1->first_pid_index = 0;
2135 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2136 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2137 init_track_colors();
2138 view1_display_when_idle();
2139}
2140
2141/****************************************************************************
2142* unchase_event_etc
2143* Copy g_original_pids to g_pids, revert index mapping
2144****************************************************************************/
2145static void unchase_event_etc(void)
2146{
2147 int i;
2148 pid_sort_t *psp;
2149 pid_data_t *pp;
2150
Dave Barach9c8cfd32019-02-03 10:44:47 -05002151 memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids);
Dave Barach52642c32016-02-11 19:28:19 -05002152
2153 /* Fix the pid structure index mappings */
2154 psp = g_pids;
2155
2156 for (i = 0; i < g_npids; i++) {
2157 pp = psp->pid;
2158 pp->pid_index = i;
2159 psp++;
2160 }
2161
2162 /* Scroll PID axis to the top */
2163 s_v1->first_pid_index = 0;
2164 GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00;
2165 gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj));
2166 init_track_colors();
2167 view1_display_when_idle();
2168}
2169
2170/****************************************************************************
2171* print_ps_header
2172* To fit a reasonable-sized landscape mode plot onto letter-size paper,
2173* scale everything by .75.
2174****************************************************************************/
2175
2176static void print_ps_header (v1_geometry_t *vp, char *filename)
2177{
2178 time_t now;
2179
2180 now = time(0);
2181
2182 fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n");
2183 fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n");
2184 fprintf(s_printfp, "%%%%Title: %s\n", filename);
2185 fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now));
2186 fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n");
2187 fprintf(s_printfp, "%%%%Origin: 0 0\n");
Dave Barach9c8cfd32019-02-03 10:44:47 -05002188 fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height,
Dave Barach52642c32016-02-11 19:28:19 -05002189 vp->total_width);
2190 fprintf(s_printfp, "%%%%LanguageLevel: 2\n");
2191 fprintf(s_printfp, "%%%%Pages: 1\n");
2192 fprintf(s_printfp, "%%%%Page: 1 1\n");
2193 fprintf(s_printfp, "%%%%EOF\n");
2194 fprintf(s_printfp, "/Times-Roman findfont\n");
2195 fprintf(s_printfp, "12 scalefont\n");
2196 fprintf(s_printfp, "setfont\n");
2197 fprintf(s_printfp, ".75 .75 scale\n");
2198}
2199
2200/****************************************************************************
2201* xrt
2202* Xcoordinate rotate and translate. We need to emit postscript that
2203* has a reasonable aspect ratio for printing. To do that, we rotate the
Dave Barach9c8cfd32019-02-03 10:44:47 -05002204* intended picture by 90 degrees, using the standard 2D rotation
Dave Barach52642c32016-02-11 19:28:19 -05002205* formula:
Dave Barach9c8cfd32019-02-03 10:44:47 -05002206*
Dave Barach52642c32016-02-11 19:28:19 -05002207* Xr = x*cos(theta) - y*sin(theta);
2208* Yr = x*sin(theta) + y*cos(theta);
2209*
2210* If we let theta = 90, this reduces to
2211* Xr = -y
2212* Yr = x
2213*
2214* Translate back to the origin in X by adding Ymax, yielding
2215* Xrt = Ymax - y
2216****************************************************************************/
2217
2218static inline int xrt(int x, int y)
2219{
2220 return (s_v1->total_height - y);
2221}
2222
2223static inline int yrt(int x, int y)
2224{
2225 return(x);
2226}
2227
2228/****************************************************************************
2229* print_screen_callback
2230****************************************************************************/
2231
2232static boolean print_screen_callback(char *filename)
2233{
2234 s_printfp = fopen (filename, "wt");
2235
2236 if (s_printfp == NULL)
2237 return(FALSE);
2238
2239 /*
2240 * This variable allows us to magically turn the view1 display
2241 * code into a print-driver, with a minimum of fuss. The idea is to
2242 * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding
2243 * the required value, aka s_print_offset.
2244 * Make sure to fix g2.h if you mess here, or vice versa.
2245 */
2246 s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN;
2247
2248 print_ps_header(s_v1, filename);
2249
2250 display_pid_axis(s_v1);
2251 display_event_data(s_v1);
2252 display_time_axis(s_v1);
2253
2254 fclose (s_printfp);
2255 s_printfp = 0;
2256 s_print_offset = 0;
2257
2258 /* For tactile feedback */
2259 view1_display_when_idle();
2260 return(TRUE);
2261}
2262
Dave Barach2c35e582017-04-03 10:22:17 -04002263int event_time_cmp (const void *a, const void *b)
2264{
2265 const event_t *e1 = a;
2266 const event_t *e2 = b;
2267
2268 if (e1->time < e2->time)
2269 return -1;
2270 else if (e1->time > e2->time)
2271 return 1;
2272 return 0;
2273}
2274
2275/****************************************************************************
2276* slew_tracks
2277****************************************************************************/
2278static void slew_tracks (v1_geometry_t *vp, enum view1_button_click which)
2279{
2280 event_t *ep;
2281 pid_sort_t *pp;
2282 int pid_index;
2283 ulonglong delta;
Dave Barach9c8cfd32019-02-03 10:44:47 -05002284
Dave Barach2c35e582017-04-03 10:22:17 -04002285 delta = (ulonglong) (vp->last_time_interval);
2286
2287 /* Make sure we don't push events to the left of the big bang */
2288 if (which == SLEW_LEFT_BUTTON) {
2289 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2290 pid_index = ep->pid->pid_index;
2291 pp = (g_pids + pid_index);
Dave Barach9c8cfd32019-02-03 10:44:47 -05002292
Dave Barach2c35e582017-04-03 10:22:17 -04002293 if (pp->selected) {
2294 if (ep->time < delta) {
Dave Barach9c8cfd32019-02-03 10:44:47 -05002295 infobox("Slew Range Error",
Dave Barach2c35e582017-04-03 10:22:17 -04002296 "\nCan't slew selected data left that far..."
2297 "\nEvents would preceed the Big Bang (t=0)...");
2298 goto out;
2299 }
2300 }
2301 }
2302 }
2303
2304 for (ep = g_events; ep < (g_events + g_nevents); ep++) {
2305 pid_index = ep->pid->pid_index;
2306 pp = (g_pids + pid_index);
2307
2308 if (pp->selected) {
2309 if (which == SLEW_LEFT_BUTTON)
2310 ep->time -= delta;
2311 else
2312 ep->time += delta;
2313 }
2314 }
2315
2316 /* Re-sort the events, to avoid screwing up the event display */
2317 qsort (g_events, g_nevents, sizeof(event_t), event_time_cmp);
2318
2319 /* De-select tracks */
2320 deselect_tracks();
2321
2322out:
2323 view1_display_when_idle();
2324}
2325
Dave Barach52642c32016-02-11 19:28:19 -05002326/****************************************************************************
Dave Barach9c8cfd32019-02-03 10:44:47 -05002327* view1_button_click_callback
Dave Barach52642c32016-02-11 19:28:19 -05002328****************************************************************************/
2329
2330static void view1_button_click_callback(GtkButton *item, gpointer data)
2331{
Florin Corasd7f0dae2024-04-10 18:31:57 -07002332 enum view1_button_click click = (enum view1_button_click) (long int) data;
2333 event_t *ep;
2334 ulonglong event_incdec;
2335 ulonglong current_width;
2336 ulonglong zoom_delta;
Dave Barach52642c32016-02-11 19:28:19 -05002337
Florin Corasd7f0dae2024-04-10 18:31:57 -07002338 current_width = s_v1->maxvistime - s_v1->minvistime;
2339 event_incdec = (current_width) / 3;
Dave Barach52642c32016-02-11 19:28:19 -05002340
Florin Corasd7f0dae2024-04-10 18:31:57 -07002341 if (event_incdec == 0LL)
2342 event_incdec = 1;
Dave Barach52642c32016-02-11 19:28:19 -05002343
Florin Corasd7f0dae2024-04-10 18:31:57 -07002344 zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6;
Dave Barach52642c32016-02-11 19:28:19 -05002345
Florin Corasd7f0dae2024-04-10 18:31:57 -07002346 switch (click)
2347 {
Dave Barach52642c32016-02-11 19:28:19 -05002348 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);
Dave Barach52642c32016-02-11 19:28:19 -05003400 } else {
Dave Barach3e07a4a2020-04-04 10:05:48 -04003401 snprintf(tmpbuf, sizeof(tmpbuf), "SEARCH RESULT");
Dave Barach52642c32016-02-11 19:28:19 -05003402 }
Dave Barach9c8cfd32019-02-03 10:44:47 -05003403 print_rect = tbox(tmpbuf, x, y - vp->pop_offset,
Dave Barach52642c32016-02-11 19:28:19 -05003404 TBOX_DRAW_BOXED+s_print_offset);
3405 line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset);
3406 if (last_x_used != NULL)
3407 last_x_used[pid_index] = x + print_rect->width;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003408 }
Dave Barach52642c32016-02-11 19:28:19 -05003409 if (summary_mode) {
3410 int delta = vp->strip_height / 3;
3411 if (delta < 1)
3412 delta = 1;
3413 y = pid_index*vp->strip_height + vp->pid_ax_offset;
3414 line(x, y - delta, x, y + delta, LINE_DRAW_BLACK);
3415 last_x_used[pid_index] = x + 1;
3416 } else {
Dave Barach3e07a4a2020-04-04 10:05:48 -04003417 snprintf(tmpbuf, sizeof(tmpbuf), "%ld", ep->code);
Dave Barach52642c32016-02-11 19:28:19 -05003418 print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset);
3419 if (last_x_used != NULL)
3420 last_x_used[pid_index] = x + print_rect->width;
3421 }
3422
3423 ep++;
3424 }
3425 if (last_x_used)
3426 g_free(last_x_used);
3427 line_batch_end();
3428 set_color(COLOR_DEFAULT);
3429}
3430
3431/****************************************************************************
3432* display_clear
3433****************************************************************************/
3434
3435static void display_clear(void)
3436{
3437 GdkRectangle update_rect;
3438
3439 gdk_draw_rectangle (pm, da->style->white_gc, TRUE,
3440 0, 0, da->allocation.width,
3441 da->allocation.height);
3442
3443 update_rect.x = 0;
3444 update_rect.y = 0;
3445 update_rect.width = da->allocation.width;
3446 update_rect.height = da->allocation.height;
3447
3448 gtk_widget_draw (da, &update_rect);
3449}
3450
3451/****************************************************************************
3452* display_time_axis
3453****************************************************************************/
3454
3455static void display_time_axis(v1_geometry_t *vp)
3456{
3457 int x, y, i;
3458 int xoffset, nticks;
3459 char tmpbuf [128];
3460 double unit_divisor;
3461 double time;
3462 char *units;
3463 double time_per_pixel;
3464
3465 y = vp->npids * vp->strip_height + vp->pid_ax_offset;
3466
3467 x = vp->pid_ax_width;
3468
3469 nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing;
3470
3471 time_per_pixel = dtime_per_pixel(vp);
3472
3473 units = "ns";
3474 unit_divisor = 1.00;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003475
Dave Barach52642c32016-02-11 19:28:19 -05003476 if ((vp->maxvistime / unit_divisor) > 1000) {
3477 units = "us";
3478 unit_divisor = 1000.00;
3479 }
3480
3481 if ((vp->maxvistime / unit_divisor) > 1000) {
3482 units = "ms";
3483 unit_divisor = 1000.00*1000.00;
3484 }
3485 if ((vp->maxvistime / unit_divisor) > 1000) {
3486 units = "s";
3487 unit_divisor = 1000.00*1000.00*1000.00;
3488 }
3489
3490 /* Draw line */
3491 line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset);
3492
3493 xoffset = 0;
Dave Barach9c8cfd32019-02-03 10:44:47 -05003494
Dave Barach52642c32016-02-11 19:28:19 -05003495 for (i = 0; i < nticks; i++) {
3496 /* Tick mark */
3497 line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset);
3498
3499 time = (double)(x + xoffset - vp->pid_ax_width);
3500 time *= time_per_pixel;
3501 time += (double)(vp->minvistime);
3502 time /= unit_divisor;
3503
Dave Barach3e07a4a2020-04-04 10:05:48 -04003504 snprintf (tmpbuf, sizeof(tmpbuf), "%.2f%s", time, units);
Dave Barach52642c32016-02-11 19:28:19 -05003505
3506 tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset);
Dave Barach9c8cfd32019-02-03 10:44:47 -05003507
Dave Barach52642c32016-02-11 19:28:19 -05003508 xoffset += vp->time_ax_spacing;
3509 }
3510}
3511
3512/****************************************************************************
3513* clear_scoreboard
3514* Forget about any temporary displays, they're gone now...
3515****************************************************************************/
3516
3517static void clear_scoreboard(void)
3518{
3519 s_result_up = FALSE;
3520}
3521
3522/****************************************************************************
3523* view1_display
3524****************************************************************************/
3525
3526void view1_display(void)
3527{
3528 display_clear();
3529 display_pid_axis(s_v1);
3530 display_event_data(s_v1);
3531 display_time_axis(s_v1);
3532 clear_scoreboard();
3533}
3534
3535static gint idle_tag;
3536
3537/****************************************************************************
3538* view1_display_eventually
3539****************************************************************************/
3540
3541static void view1_display_eventually(void)
3542{
3543 gtk_idle_remove(idle_tag);
3544 idle_tag = 0;
3545 view1_display();
3546}
3547
3548
3549/****************************************************************************
3550* view1_display_when_idle
3551****************************************************************************/
3552
3553void view1_display_when_idle(void)
3554{
3555 if (idle_tag == 0) {
3556 idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0);
3557 }
3558}
3559
3560/****************************************************************************
3561* view1_about
3562****************************************************************************/
3563
3564void view1_about (char *tmpbuf)
3565{
3566 int nsnaps;
3567 snapshot_t *snaps;
3568
Dave Barach3e07a4a2020-04-04 10:05:48 -04003569 snprintf(tmpbuf+strlen(tmpbuf), 128, "Minvistime %lld\nMaxvistime %lld\n",
Dave Barach52642c32016-02-11 19:28:19 -05003570 s_v1->minvistime, s_v1->maxvistime);
Dave Barach3e07a4a2020-04-04 10:05:48 -04003571 snprintf(tmpbuf+strlen(tmpbuf), 128, "Strip Height %d\n",
Dave Barach52642c32016-02-11 19:28:19 -05003572 s_v1->strip_height);
3573
3574 for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) {
3575 nsnaps++;
3576 }
Dave Barach3e07a4a2020-04-04 10:05:48 -04003577 snprintf(tmpbuf+strlen(tmpbuf), 128, "%d snapshots in the ring\n", nsnaps);
Dave Barach52642c32016-02-11 19:28:19 -05003578}