/*
 * $Source: /afs/sipb.mit.edu/project/sipbsrc/src/xscreensaver/RCS/hft.c,v $
 * $Author: jik $
 *
 * This file is part of xscreensaver.  It contains the code for dealing with
 * enabling/disabling the switching of screens via HFT "hotkeys" on the
 * IBM RS/6000.
 *
 * Author: Lucien Van Elsen, MIT Project Athena
 *
 * Coyright (c) 1989 by Jonathan Kamens.  This code may be distributed
 * freely as long as this notice is kept intact in its entirety and
 * every effort is made to send all corrections and improvements to
 * the code back to the author.  Also, don't try to make any money off
 * of it or pretend that you wrote it.
 */

#ifndef lint
     static char rcsid_hft_c[] = "$Header: ";
#endif

#include <sys/types.h>
#include <sys/hft.h>
#include <fcntl.h>

static struct hftqstat orig_hft_state;
static struct hfbuf hft_buffer;
static int hft_locked = 0;

/* What we're doing here:
     Get a new hft by opening /dev/hft; this new hft will be inserted at the
     head of the hft list, making the previously active hft the last one
     in the list.  We need this new hft to get a handle on the hft device,
     so that we can use the nec. ioctls.  We let it create a new one for us,
     because there is no reliable way (without grunging through kernel
     memory) to determine which hft the X server is running on.
     
     Once we've got the hft, "hide" all the screens except the last one,
     which is the one which was active when the routine was called,
     which should be the one that the X server is running on.
     Then, close the hft we got, so it drops out of the ring, and the
     only unhidden hft becomes the active (visible) one.

     To "unhide" the screens, we again get a new hft to get a handle on the
     device, and proceed to unhide all the screens that weren't hidden when
     we started; since we unhide the last terminal in the ring last, it will
     become the active (visible) one.
*/

void
enable_hft_hotkey()
{
  int i,fd;
  struct hftsmgrcmd hft_cmd;

  if (!hft_locked)
    return;

  if ((fd = open("/dev/hft",O_RDONLY,0)) < 0) {
    perror("opening hft");
    return;
  }

  for (i=0; i<orig_hft_state.hf_numvts; i++) {
    if (orig_hft_state.hf_vtinfo[i].hf_vtstate & HFVTHIDDEN)
      continue;
    hft_cmd.hf_vtid = orig_hft_state.hf_vtinfo[i].hf_vtid;
    hft_cmd.hf_cmd = SMUNHIDE;

    if (ioctl(fd, HFTCSMGR, &hft_cmd) != 0)
      perror("ioctl: HFTCSMGR failed");
      
  }
  close(fd);
  hft_locked = 0;
}

int
disable_hft_hotkey()
{
  int fd, i;
  struct hftsmgrcmd hft_cmd;

  hft_buffer.hf_bufp = (char *) &orig_hft_state;
  hft_buffer.hf_buflen = sizeof(struct hftqstat);

  if ((fd = open("/dev/hft",O_RDONLY,0)) < 0) {
    perror("opening hft");
    return -1;
  }

  if (ioctl(fd, HFTQSMGR, &hft_buffer) != 0) {
    perror("ioctl: HFTQSMGR failed");
    close(fd);
    return -1;
  }

  for (i=0; i<(orig_hft_state.hf_numvts -1); i++) {
    hft_cmd.hf_vtid = orig_hft_state.hf_vtinfo[i].hf_vtid;
    hft_cmd.hf_cmd = SMHIDE;
    if (ioctl(fd, HFTCSMGR, &hft_cmd) != 0) { 
      perror("ioctl: HFTCSMGR failed");
      close(fd);
      enable_hft_hotkey();
      return -1;
    }
  }
  close(fd);
  hft_locked = 1;
  return 0;
}
