/*
 * xman - X window system manual page display program.
 *
 * $XConsortium: handler.c,v 1.20 91/06/05 14:50:29 dave Exp $
 *
 * Copyright 1987, 1988 Massachusetts Institute of Technology
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of M.I.T. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  M.I.T. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * Author:    Chris D. Peterson, MIT Project Athena
 * Created:   October 29, 1987
 */

#include "globals.h"
#include "vendor.h"

static void PutUpManpage();
static void ToggleBothShownState();

/*	Function Name: OptionCallback
 *	Description: This is the callback function for the callback menu.
 *	Arguments: w - the widget we are calling back from. 
 *                 globals_pointer - a pointer to the psuedo globals structure
 *                                  for this manpage.
 *                 junk - (call data) not used.
 *	Returns: none.
 */

/*ARGSUSED*/
void
OptionCallback(w, pointer, junk)
Widget w;
XtPointer pointer;
XtPointer junk;		/* unused */
{
  ManpageGlobals * man_globals = (ManpageGlobals *) pointer;
  String params;
  Cardinal num_params = 1;

  if ( w == man_globals->search_entry )
    PopupSearch(XtParent(w), NULL, NULL, NULL);
  else if (w == man_globals->dir_entry) {       /* Put Up Directory */
    params = "Directory";
    GotoPage(XtParent(w), NULL, &params, &num_params);
  }
  else if (w == man_globals->manpage_entry ) {  /* Put Up Man Page */
    params = "ManualPage";
    GotoPage(XtParent(w), NULL, &params, &num_params);
  }
  else if ( w == man_globals->help_entry )      /* Help */
    PopupHelp(XtParent(w), NULL, NULL, NULL);
  else if ( w == man_globals->both_screens_entry ) /*Toggle Both_Shown State.*/
    ToggleBothShownState(man_globals);
  else if ( w == man_globals->remove_entry)     /* Kill the manpage */
    RemoveThisManpage(XtParent(w), NULL, NULL, NULL);
  else if ( w == man_globals->open_entry)       /* Open new manpage */
    CreateNewManpage(XtParent(w), NULL, NULL, NULL);
  else if ( w == man_globals->version_entry)    /* Get version */
    ShowVersion(XtParent(w), NULL, NULL, NULL);
  else if ( w == man_globals->quit_entry)      /* Quit. */
    Quit(XtParent(w), NULL, NULL, NULL);
}

/*      Function Name: ToggleBothShownState;
 *      Description: toggles the state of the both shown feature.
 *      Arguments: man_globals - the man globals structure.
 *      Returns: none.
 */

/*
 * I did not have a two state widget, which is the way this
 * should really be done.  1/22/88 - CDP.
 */

static void
ToggleBothShownState(man_globals)
ManpageGlobals * man_globals; 
{
#ifdef MOTIF
  XmString xms;
#endif
  char * label_str;
  Arg arglist[1];

  if (man_globals->both_shown == TRUE) {
    label_str = SHOW_BOTH;
    if (man_globals->dir_shown)
#ifdef MOTIF
      XtUnmanageChild(
	XtParent( XtParent( man_globals->manpagewidgets.manpage ) ) );
#else
      XtUnmanageChild(man_globals->manpagewidgets.manpage);
#endif
    else
      XtUnmanageChild(man_globals->manpagewidgets.directory);
  }
  else {
    Widget manpage = man_globals->manpagewidgets.manpage;
    Widget dir = man_globals->manpagewidgets.directory;
    
    label_str = SHOW_ONE;

#ifdef MOTIF
    XtSetArg(arglist[0], XmNheight, resources.directory_height);  
#else
    XtSetArg(arglist[0], XtNpreferredPaneSize, resources.directory_height);
#endif
    XtSetValues(dir, arglist, (Cardinal) 1);

    if (!man_globals->dir_shown) {
#ifdef MOTIF
      XtUnmanageChild( XtParent( XtParent( manpage) ) );
#else
      XtUnmanageChild(manpage);
#endif
      XtManageChild(dir);
    }
#ifdef MOTIF
      XtManageChild( XtParent( XtParent( manpage) ) );
#else
    XtManageChild(manpage);
#endif
  }
  man_globals->both_shown = !man_globals->both_shown;
  
  if (man_globals->dir_shown)
    ChangeLabel(man_globals->label,
		man_globals->section_name[man_globals->current_directory]);
  else
    ChangeLabel(man_globals->label, man_globals->manpage_title);
  
#ifdef MOTIF
  xms = XmStringCreateSimple( label_str );
  XtSetArg(arglist[0], XmNlabelString, xms);
  XtSetValues(man_globals->both_screens_entry, arglist, ONE);
  XmStringFree( xms );
#else
  XtSetArg(arglist[0], XtNlabel, label_str);
  XtSetValues(man_globals->both_screens_entry, arglist, ONE);
#endif
  
  /* if both are shown there is no need to switch between the two. */

  XtSetArg(arglist[0], XtNsensitive, !man_globals->both_shown);
  XtSetValues(man_globals->manpage_entry, arglist, ONE);
  XtSetValues(man_globals->dir_entry, arglist, ONE);
}

/*	Function Name: Popup
 *	Description: This function pops up the given widget under the cursor.
 *	Arguments: w - the widget to popup.
 *                 grab_kind - the kind of grab to register.
 *	Returns: none
 */

/* How far off the top of the widget to have the initial cursor postion. */

#define OFF_OF_TOP 25

void
Popup(w, grab_kind)
Widget w;
XtGrabKind grab_kind;
{
  int x_root,y_root,y_pos,garbage;
  unsigned int mask;
  Window junk_window;

  XQueryPointer(XtDisplay(w), XtWindow(w), &junk_window, &junk_window,
		&x_root, &y_root, &garbage, &garbage, &mask);

  y_pos = OFF_OF_TOP - Height(w)/2 - BorderWidth(w);
  PositionCenter(w, x_root, y_root, y_pos, 0, 2, 2);
#ifdef MOTIF
  if ( grab_kind == XtGrabNone )
    XtMapWidget( w );
  else
#endif
    XtPopup(w, grab_kind);
}

/*	Function Name: PutUpManpage
 *	Description: Puts the manpage on the display.
 *	Arguments: man_globals - a pointer to the psuedo globals structure
 *                                  for this manpage.
 *                 file - the file to display.
 *	Returns: none.
 */

static void
PutUpManpage(man_globals, file)
ManpageGlobals * man_globals;
FILE * file;
{
  String params = "ManualPage";
  Cardinal num_params = 1;
  
  if (file == NULL)
    return;

  OpenFile(man_globals, file);
  fclose(file);

  if (!man_globals->both_shown) {
    Arg arglist[1];
    XtSetArg(arglist[0], XtNsensitive, TRUE);
    XtSetValues(man_globals->manpage_entry, arglist, ONE);
    XtSetValues(man_globals->both_screens_entry, arglist, ONE);
  }
  GotoPage(man_globals->manpagewidgets.manpage, NULL, &params, &num_params);
}

/*	Function Name: DirectoryHandler
 *	Description: This is the callback function for the directory listings.
 *	Arguments: w - the widget we are calling back from. 
 *                 global_pointer - the pointer to the psuedo global structure
 *                                  associated with this manpage.
 *                 ret_val - return value from the list widget.
 *	Returns: none.
 */

void
DirectoryHandler(w, global_pointer, ret_val)
Widget w;
XtPointer global_pointer, ret_val;
{
  FILE * file;			/* The manpage file. */
  ManpageGlobals * man_globals = (ManpageGlobals *) global_pointer;
#ifdef MOTIF
  int *pos_list;
  int  pos_count;
  if ( !XmListGetSelectedPos( w, &pos_list, &pos_count ) || !pos_count ) 
    /* nothing selected, nothing to do */
    return;

  file = FindManualFile( man_globals, man_globals->current_directory, 
	   pos_list[ 0 ] - 1 );   /* in XmList, first item is position 1 */

#ifdef DEBUG
printf( "DirectoryHandler, index = %d\n", pos_list[ 0 ] - 1 );
#endif

  /* release memory, see XmList man page */
  XtFree( (XtPointer) pos_list );

#else
  XawListReturnStruct * ret_struct = (XawListReturnStruct *) ret_val;

  file = FindManualFile(man_globals, man_globals->current_directory,
			ret_struct->list_index);
#ifdef DEBUG
printf( "DirectoryHandler, index = %d\n", ret_struct->list_index );
#endif

#endif

  PutUpManpage(man_globals, file);

}

/*	Function Name: DirPopupCallback
 *	Description: This is the callback function for the callback menu.
 *	Arguments: w - the widget we are calling back from. 
 *                 pointer - a pointer to the psuedo globals structure
 *                                  for this manpage.
 *                 junk - (call data) not used.
 *	Returns: none.
 */

/*ARGSUSED*/
void
DirPopupCallback(w,pointer,junk)
Widget w;
XtPointer pointer;
XtPointer junk;		/* unused */
{
  ManpageGlobals * man_globals; 
  MenuStruct * menu_struct;
  Widget parent;
  int number;
  int current_box;

  menu_struct = (MenuStruct *) pointer;
  man_globals = (ManpageGlobals *) menu_struct->data;

  number = menu_struct->number;
  current_box = man_globals->current_directory;

  /* We have used this guy, pop down the menu. */
  
  if (number != current_box) {
    /* This is the only one that we know has a parent. */
    parent = XtParent(man_globals->manpagewidgets.box[INITIAL_DIR]);
#ifdef MOTIF
    /* gross*&!!!... Form->ScrWin->List */
    MakeDirectoryBox(man_globals, XtParent( parent ),
		     man_globals->manpagewidgets.box + number, number);
    XtUnmanageChild( XtParent(man_globals->manpagewidgets.box[current_box]) );
    XtManageChild(man_globals->manpagewidgets.box[number]);
    XtManageChild( XtParent(man_globals->manpagewidgets.box[number]) );

#else
    MakeDirectoryBox(man_globals, parent,
		     man_globals->manpagewidgets.box + number, number);
    XtUnmanageChild(man_globals->manpagewidgets.box[current_box]);
    XtManageChild(man_globals->manpagewidgets.box[number]);

    XawListUnhighlight(man_globals->manpagewidgets.box[current_box]);
#endif
    ChangeLabel(man_globals->label, man_globals->section_name[number]);
    man_globals->current_directory = number;
  }

  /* put up directory. */
  if (!man_globals->both_shown) {
#ifdef MOTIF
    XtUnmanageChild(
      XtParent( XtParent( man_globals->manpagewidgets.manpage ) ) );
#else
    XtUnmanageChild(man_globals->manpagewidgets.manpage);
#endif
#ifdef MOTIF
    XtManageChild(man_globals->manpagewidgets.directory);
#else
    XtManageChild(man_globals->manpagewidgets.directory);
#endif
  }
}
    
/************************************************************
 *
 * Action Routines.
 *
 ************************************************************/

/*	Function Name: SaveFormattedPage
 *	Description: This is the action routine may save the manpage.
 *      Arguments: w - any widget in the widget tree.
 *                 event - NOT USED.
 *                 params, num_params - the parameters paseed to the action
 *                                      routine, can be either Manpage or
 *                                      Directory.
 *      Returns: none.
 */

/*ARGSUSED*/
void
SaveFormattedPage(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  ManpageGlobals * man_globals;
  char cmdbuf[BUFSIZ], error_buf[BUFSIZ];

  if (*num_params != 1) {
    XtAppWarning(XtWidgetToApplicationContext(w), 
       "Xman - SaveFormattedPage: This action routine requires one argument.");
    return;
  }

  man_globals = GetGlobals(w);

/*
 * If we are not active then take no action.
 */

  if (man_globals->tmpfile == '\0') return;

  switch (params[0][0]) {
  case 'S':
  case 's':

#ifndef NO_COMPRESS
    if (!man_globals->compress)
#endif

      sprintf(cmdbuf, "%s %s %s", COPY, man_globals->tmpfile, 
	      man_globals->save_file);

#ifndef NO_COMPRESS
    else
      sprintf(cmdbuf, "%s < %s > %s", COMPRESS, man_globals->tmpfile, 
	      man_globals->save_file);
#endif

    if(! system(cmdbuf)) {
	/* make sure the formatted man page is fully accessible by the world */
	if (chmod(man_globals->save_file, CHMOD_MODE) != 0) {
	    sprintf(error_buf,
		    "Couldn't set permissions on formatted man page '%s'.\n",
		    man_globals->save_file);
	    PopupWarning( man_globals, error_buf);
	}
    } else {
	sprintf(error_buf, "Error while executing the command '%s'.\n",
		cmdbuf);
	PopupWarning( man_globals, error_buf);
    }
    break;
  case 'C':
  case 'c':
    break;
  default:
    sprintf(error_buf,"%s %s", "Xman - SaveFormattedPagee:",
	    "Unknown argument must be either 'Save' or 'Cancel'.");
    PopupWarning(man_globals, error_buf);
    return;
  }
    
/*
 * We do not need the filename anymore, and have the fd open.
 * We will unlink it.     
 */

  unlink(man_globals->tmpfile);
  XtPopdown( XtParent(XtParent(w)) );
}

/*      Function Name: GotoPage
 *      Description: The Action routine that switches over to the manpage
 *                   or directory.
 *      Arguments: w - any widget in the widget tree.
 *                 event - NOT USED.
 *                 params, num_params - the parameters paseed to the action
 *                                      routine, can be either Manpage or
 *                                      Directory.
 *      Returns: none.
 */

/*ARGSUSED*/
void
GotoPage(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  ManpageGlobals * man_globals;
  char error_buf[BUFSIZ];
  Arg arglist[1];
  Boolean sensitive;

  if (*num_params != 1) {
    XtAppWarning(XtWidgetToApplicationContext(w), 
		"Xman - GotoPage: This action routine requires one argument.");
    return;
  }

  man_globals = GetGlobals(w);

  if (man_globals->both_shown) {
    ChangeLabel(man_globals->label, 
		man_globals->section_name[man_globals->current_directory]);
    return;
  }

  switch (params[0][0]) {
  case 'M':
  case 'm':
    XtSetArg(arglist[0], XtNsensitive, &sensitive);
    XtGetValues(man_globals->manpage_entry, arglist, ONE);
    if (sensitive) {
      ChangeLabel(man_globals->label,man_globals->manpage_title);
      XtUnmanageChild(man_globals->manpagewidgets.directory);
#ifdef MOTIF
      XtManageChild(
        XtParent( XtParent( man_globals->manpagewidgets.manpage ) ) );
#else
      XtManageChild(man_globals->manpagewidgets.manpage);
#endif
      man_globals->dir_shown = FALSE;
    }
    break;
  case 'D':
  case 'd':
    ChangeLabel(man_globals->label,
		man_globals->section_name[man_globals->current_directory]);
#ifdef MOTIF
    XtUnmanageChild(
      XtParent( XtParent( man_globals->manpagewidgets.manpage ) ) );
#else
    XtUnmanageChild(man_globals->manpagewidgets.manpage);
#endif
    XtManageChild(man_globals->manpagewidgets.directory);  
    man_globals->dir_shown = TRUE;
    break;
  default:
    sprintf(error_buf,"%s %s", "Xman - GotoPage: Unknown argument must be",
	    "either Manpage or Directory.");
    XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
    return;
  }
}

/*      Function Name: Quit.
 *      Description: Quits Xman.
 *      Arguments: w - any widget.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
Quit(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  XCloseDisplay(XtDisplay(w));
  exit(0);
}

/*      Function Name: PopupHelp
 *      Description: Pops up xman's help.
 *      Arguments: w - NOT USED.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
PopupHelp(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  if (MakeHelpWidget())
#ifdef MOTIF
    /* This is the only way I can make the help window modeless. */
    XtMapWidget( help_widget );
#else
    XtPopup(help_widget,XtGrabNone);
#endif
}

/*      Function Name: PopupSearch
 *      Description: Pops up this manual pages search widget.
 *      Arguments: w - any widget in this manpage.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
PopupSearch(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  ManpageGlobals * man_globals = GetGlobals(w);
  if (!XtIsRealized(man_globals->search_widget)) {
    XtRealizeWidget(man_globals->search_widget);
    AddCursor(man_globals->search_widget, resources.cursors.search_entry);
  }
#ifdef MOTIF
  XtManageChild( man_globals->search_widget );
#else
  Popup(man_globals->search_widget, XtGrabNone);
#endif
}

/*      Function Name: CreateNewManpage
 *      Description: Creates A New Manual Page.
 *      Arguments: w - NOT USED.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
CreateNewManpage(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  (void) CreateManpage(NULL);
  man_pages_shown++;
}

/*      Function Name: RemoveThisManpage
 *      Description: Removes a manual page.
 *      Arguments: w - any widget in the manpage.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
RemoveThisManpage(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  ManpageGlobals * man_globals = GetGlobals(w);
  
  if (man_globals->This_Manpage != help_widget) {
    RemoveGlobals(man_globals->This_Manpage);
    XtDestroyWidget(man_globals->This_Manpage);

    XtFree( (char *) man_globals->section_name);
    XtFree( (char *) man_globals->manpagewidgets.box);
    XtFree( (char *) man_globals);

    if ( (--man_pages_shown) == 0)
      Quit(w, NULL, NULL, NULL);  
  }
  else
#ifdef MOTIF
    XtUnmapWidget( help_widget );
#else
    XtPopdown(help_widget);
#endif
}

/*      Function Name: Search
 *      Description: Actually performs a search.
 *      Arguments: w - any widget in the manpage.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
Search(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  ManpageGlobals * man_globals = GetGlobals(w);
  FILE * file;

#ifdef MOTIF
  XtUnmanageChild( w );
#else
  XtPopdown(  XtParent(XtParent(w)) );       /* popdown the search widget */
#endif

  if ( (*num_params < 1) || (*num_params > 2) ) {
    XtAppWarning(XtWidgetToApplicationContext(w), 
      "Xman - Search: This action routine requires one or two arguments.");
    return;
  }

  switch(params[0][0]) {
  case 'a':
  case 'A':
    file = DoSearch(man_globals,APROPOS);
    break;
  case 'm':
  case 'M':
    file = DoSearch(man_globals,MANUAL);
    break;
  case 'c':
  case 'C':
    file = NULL;
    break;
  default:
    XtAppWarning(XtWidgetToApplicationContext(w), 
		 "Xman - Search: First parameter unknown.");
    file = NULL;
    break;
  }

  if ( *num_params == 2 ) 
    switch (params[1][0]) {
    case 'O':
    case 'o':
      if (file != NULL) {
	Widget w;
	char * label;

	w = CreateManpage(file);
	man_pages_shown++;

	/* Put title into new manual page. */

	label = man_globals->manpage_title;
	man_globals = GetGlobals(w);
	strcpy(man_globals->manpage_title, label);
	ChangeLabel(man_globals->label, label);
      }
      break;
    default:
      XtAppWarning(XtWidgetToApplicationContext(w), 
		   "Xman - Search: Second parameter unknown.");
      break;
    }
  else {
    PutUpManpage(man_globals, file);
  }
}

/*      Function Name: ShowVersion
 *      Description: Show current version.
 *      Arguments: w - any widget in the manpage.
 *                 event - NOT USED.
 *                 params, num_params - NOT USED.
 *      Returns: none.
 */

/*ARGSUSED*/
void 
ShowVersion(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
  ManpageGlobals * man_globals = GetGlobals(w);
  ChangeLabel(man_globals->label, XMAN_VERSION);
}
