A.34. Timers

/* See if qserve and nserve are running.  If not, start them. */

if ((qnx_name_locate (0, "qserve", 0) == nil) &&
    (access ("/dev/qserve", 0) != 0))
{
  system("qserve");
}

if ((qnx_name_locate (0, "sc/nserve", 0) == nil) &&
    (access ("/dev/nserve", 0) != 0))
{
  system("nserve");
}


/* Create a unique name based on the process ID for this program,
   and then initialize IPC (necessary for timers) based on that name.*/

uniq_name = string(getnid(), ".", getpid());
init_ipc(uniq_name, uniq_name);


function set_every(frequency, label)
{
  cancel(car(timers_every));
  cancel(cadr(timers_every));
  label.set_text(string("This message\nblinks on and off",
				 "\nevery ", format("%2.1f", frequency), " seconds."));
  timer1 = every(frequency, `(@label).show());      
  timer2 = every((frequency * 2), `(@label).hide());
  timers_every = list(timer1, timer2);
  timers_every;
}


function set_after(time, label)
{
  cancel(timer_after);
  label.set_text(string("This message\nwill disappear\nafter ",
		format("%2.1f", time), " seconds."));
  label.show();
  timer_after = after(time, `(@label).hide());
}


function make_at_spinner(tag, lower, upper, column, val)
{
  
  label = new(GtkLabel);
  label.set_text(tag);
  table.attach_defaults(label, column, (column + 1), 1, 2);
  
  adj = gtk_adjustment_new (0, lower, upper, 1, 1, 0);
  spinner = new(GtkSpinButton);
  spinner.configure(adj, 1, 0);
  spinner.set_value(val);
  spinner.set_wrap(TRUE);
  spinner.set_shadow_type(GTK_SHADOW_IN);
  table.attach_defaults(spinner, column, (column + 1), 2, 3);

  button = new(GtkToggleButton);
  button.label = "Any";
  button.signal("clicked", `toggle_any(@spinner, @button));
  spinner.signal("changed", `untoggle_any(@spinner, @button));
  table.attach_defaults(button, column, (column + 1), 3, 4);
  list(spinner, button);
}    


function toggle_any(spinner, button)
{
  local time;
  if (button.get_active() == TRUE)
    {
      time = -1;
      spinner.set_visibility(FALSE);
    }
  else
    {
      spinner.set_visibility(TRUE);
      time = spinner.get_value_as_int();
    }
  time;
}


function untoggle_any(spinner, button)
{
  spinner.set_visibility(TRUE);
  button.set_active(FALSE);
}


function time_string(time_period)
{
  local print_string;
  if (time_period)
    print_string = format("%02d", time_period);
  else
    print_string = "**";
  print_string;
}


function set_at(day, month, year, hour, minute, second, label)
{
  local tm;
  cancel(timer_at);

  time_values = list(day, month, year, hour, minute, second);

  with v in time_values time_values = collect
    {
      tm = toggle_any
	(car(v),cadr(v));
      if (tm == -1)
	tm = nil;
      tm;
    }

  day = car(time_values);
  month = cadr(time_values);
  year = caddr(time_values);
  hour = car(cdddr(time_values));
  minute = cadr(cdddr(time_values));
  second = caddr(cdddr(time_values));

  label.set_text(string("This message will disappear on ",
		       time_string(day), "\/",
		       time_string(month), "\/",
		       time_string(year), "\/", " at ",
		       time_string(hour), ":",
		       time_string(minute), ":",
		       time_string(second), "."));
  label.show();
  
  timer_at = at(day, month, year, hour, minute, second, `(@label).hide());
  if (timer_at == nil)
    {
      label.set_text("That time is past or invalid, try again.");
      label.show();
      timer_at = at(31,12,2026,23,59,59,`(@label).hide());
    }
  timer_at;
}

function month_number(month)
{
  switch (month)
    {
    case "Jan": 1;
    case "Feb": 2;
    case "Mar": 3;
    case "Apr": 4;
    case "May": 5;
    case "Jun": 6;
    case "Jul": 7;
    case "Aug": 8;
    case "Sep": 9;
    case "Oct": 10;
    case "Nov": 11;
    case "Dec": 12;
    }
}

function make_adj (low, up, step, pg_inc, pg_size)
{
  adj = new(GtkAdjustment);
  adj.lower = low;
  adj.upper = up;
  adj.step_increment = step;
  adj.page_increment = pg_inc;
  adj.page_size = pg_size;
  adj;
}

function cancel_timers(timerlist...)
{
  with tmr in timerlist do
    if (tmr != nil)
      cancel(tmr);  
}


function create_timertest ()
{
  local	box1, box2, box3, frame, at_label, every_label, label, t1, t2,
  table, now, adj, spinner, frequency, separator;
  
  win_timertest = new (GtkWindow);
  win_timertest.signal ("destroy",  #cancel_timers(timer_clock,
						   timer_at,
						   (car(timers_every)),
						   (cadr(timers_every)),
						   timer_after));
  win_timertest.signal ("destroy", #win_timertest = nil);
  win_timertest.title = "Timer Test";
  win_timertest.border_width = 0;
  win_timertest.set_color(1, GTK_STATE_NORMAL, 0xbbdbcc);
  
  box1 = new (GtkVBox);
  win_timertest.add (box1);
  
  box2 = new (GtkHBox);
  box1.pack_start (box2, TRUE, TRUE, 0);
  
  /* every() test */

  box3 = new(GtkVBox);
  box3.spacing = 5;
  box3.border_width = 20;
  frame = new(GtkFrame);
  frame.border_width = 0;
  frame.set_usize(140, 100);
  frame.set_label("Test of every ( ) : ");
  frame.set_shadow_type(GTK_SHADOW_IN); 
  box3.pack_start(frame, FALSE, FALSE, 0);
  
  every_label = new(GtkLabel);
  every_label.set_text(string("This message\nblinks on and off",
			      "\nevery 2 seconds."));
  frame.add(every_label);
  
  t1 = every(2, `(@every_label).show());      
  t2 = every(4, `(@every_label).hide());
  timers_every = list(t1, t2);
  
  table = new(GtkTable);
  table.n_columns = 3;
  table.n_rows = 3;
  table.set_row_spacings(5);
  table.set_col_spacings(5);
  table.set_homogeneous(TRUE);
  box3.pack_start(table, FALSE, FALSE, 0);
  
  label = new(GtkLabel);
  label.set_text("Set frequency:");
  table.attach_defaults(label, 0, 3, 0, 1);
  
  adj = make_adj(0.2, 10.0, 0.1, 1.0, 0.0);
  spinner = new(GtkSpinButton);
  spinner.configure(adj, 0.1, 1);
  spinner.set_value(2.0);
  spinner.set_wrap(TRUE);
  spinner.set_shadow_type(GTK_SHADOW_IN);
  table.attach_defaults(spinner, 1, 2, 1, 2);
  
  frequency = 10;
  button = new(GtkButton);
  button.label = "Restart";
  button.signal("clicked", `(timers_every =
			     set_every((@spinner).get_value_as_float(),
						      @every_label)));
  table.attach_defaults(button, 1, 2, 2, 3);
  
  box2.pack_start(box3, FALSE, FALSE, 0);

  /* after() test */
  
  separator = new(GtkVSeparator);
  separator.width = 0;
  box2.pack_start(separator, TRUE, TRUE, 0);
  
  box3 = new(GtkVBox);
  box3.spacing = 5;
  box3.border_width = 20;
  frame = new(GtkFrame);
  frame.border_width = 0;
  frame.set_usize(160, 100);
  frame.set_label("Test of after ( ) : ");
  frame.set_shadow_type(GTK_SHADOW_IN);
  after_label = new(GtkLabel);
  after_label.set_text("This message\nwill disappear\nafter 5 seconds.");
  frame.add(after_label);
  box3.pack_start(frame, FALSE, FALSE, 0);
  
  timer_after = after(5, `(@after_label).hide());
  
  table = new(GtkTable);
  table.n_columns = 3;
  table.n_rows = 3;
  table.set_row_spacings(5);
  table.set_col_spacings(5);
  table.set_homogeneous(TRUE);
  box3.pack_start(table, FALSE, FALSE, 0);
  
  label = new(GtkLabel);
  label.set_text("Set time:");
  table.attach_defaults(label, 0, 3, 0, 1);
  
  adj = make_adj(0.1, 60.0, 1.0, 1.0, 0.0);
  spinner = new(GtkSpinButton);
  spinner.configure(adj, 0.1, 1);
  spinner.set_value(5.0);
  spinner.set_wrap(TRUE);
  spinner.set_shadow_type(GTK_SHADOW_IN);
  table.attach_defaults(spinner, 1, 2, 1, 2);
  
  button = new(GtkButton);
  button.label = "Restart";
  button.signal("clicked", `(timer_after = set_after((@spinner).get_value_as_float(), @after_label)));
  table.attach_defaults(button, 1, 2, 2, 3);
  
  box2.pack_start(box3, FALSE, FALSE, 0);
  
  /* at() test */

  separator = new(GtkHSeparator);
  box1.pack_start(separator, TRUE, TRUE, 0);
  
  box2 = new (GtkHBox);
  box2.border_width = 20;
  box1.pack_start (box2, TRUE, TRUE, 0);
  
  box3 = new(GtkVBox);
  box3.spacing = 5;
  frame = new(GtkFrame);
  frame.border_width = 0;
  frame.set_usize(345, 60);
  frame.set_label("Test of at ( ) : ");
  frame.set_shadow_type(GTK_SHADOW_IN);
  at_label = new(GtkLabel);
  at_label.set_text("Set a date and time to make a message disappear.");
  frame.add(at_label);
  box3.pack_start(frame, FALSE, FALSE, 0);
  
  timer_at = at(nil, nil, nil, nil, nil, nil, `(@at_label).show());
  
  table = new(GtkTable);
  table.n_columns = 6;
  table.n_rows = 5;
  table.set_row_spacings(5);
  table.set_row_spacing(0, 0);
  table.set_row_spacing(1, 0);
  table.set_col_spacings(5);
  table.set_homogeneous(TRUE);
  table.set_usize(140, 130);
  box3.pack_start(table, FALSE, FALSE, 0);

  label = new(GtkLabel);
  label.set_text("Set a new date and time for a message to disappear:");
  table.attach_defaults(label, 0, 6, 0, 1);

  now = string(date());
  now = cdr(string_split(now, " :", 0));
  princ(now, "\n");
  
  spin_day_value = make_at_spinner("Day: ", 1, 31, 0,
				   number(cadr(now)));
  spin_month_value = make_at_spinner("Month: ", 1, 12, 1,
				     month_number(car(now)));
  spin_year_value = make_at_spinner("Year: ", 1994, 2026, 2,
				    number(car(nth_cdr(now, 5))));
  spin_hour_value = make_at_spinner("Hour: ", 0, 24, 3,
				    number(caddr(now)));
  spin_minute_value = make_at_spinner("Minute: ", 0, 59, 4,
				      number(car(nth_cdr(now, 3))));
  spin_second_value = make_at_spinner("Second: ", 0, 59, 5,
				      number(car(nth_cdr(now, 4))) + 10);
  
  button = new(GtkButton);
  button.label = "Restart";
  button.signal("clicked", `(timer_at = set_at((spin_day_value),
					       (spin_month_value),
					       (spin_year_value),
					       (spin_hour_value),
					       (spin_minute_value),
					       (spin_second_value),
					       @at_label)));
  table.attach_defaults(button, 2, 4, 4, 5);
  button.clicked();
  box2.pack_start(box3, FALSE, FALSE, 0);
  
  separator = new(GtkHSeparator);
  box1.pack_start(separator, TRUE, TRUE, 0);
  
  box3 = new(GtkHBox);
  box3.border_width = 10;
  label = new(GtkLabel);
  label.set_text(string("System Time: ", date()));
  box3.add(label);
  timer_clock = every(1, `(@label).set_text(string("System Time: ", date())));
  box1.pack_start(box3, TRUE, TRUE, 0);
  
  separator = new(GtkHSeparator);
  box1.pack_start(separator, TRUE, TRUE, 0);
  
  box3 = new(GtkHBox);
  button = new (GtkButton);
  button.label = "Cancel timers";

  button.signal ("clicked", #cancel_timers(timer_at,
					   (car(timers_every)),
					   (cadr(timers_every)),
					   timer_after));
  button.signal ("clicked", `(@every_label).set_text("Cancelled."));
  button.signal ("clicked", `(@after_label).set_text("Cancelled."));
  button.signal ("clicked", `(@at_label).set_text("Cancelled."));

  box3.pack_start(button, TRUE, TRUE, 10);
  
  button = new (GtkButton);
  button.label = "Close";
  button.signal ("clicked", #cancel_timers(timer_clock,
					   timer_at,
					   (car(timers_every)),
					   (cadr(timers_every)),
					   timer_after));
  button.signal ("clicked", `(@win_timertest).destroy());
  box3.pack_start(button, TRUE, TRUE, 10);
  
  box2 = new (GtkVBox);
  box2.border_width = 10;
  box2.spacing = 10;
  box2.pack_start(box3, FALSE, FALSE, 0);
  box1.pack_start (box2, TRUE, TRUE, 0);
  
  win_timertest.show_all();
  win_timertest;
}


function main ()
{
  local window, win_timertest;
  TRUE=1;
  FALSE=0;
  window = create_timertest();
  window.signal ("destroy", #exit_program(0));
  init_ipc("timertest", "timertestq");
  gtk_main ();
}