/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                                 I N I T . C                                  *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: init.c,v 1.7 2004/08/29 14:52:00 jrh Exp $
* $Log: init.c,v $
* Revision 1.7  2004/08/29 14:52:00  jrh
* Release 2.4.1
*
* Revision 1.6  2003/11/07 11:04:56  jrh
* Release 2.4
*
* Revision 1.5  2000/12/10 15:09:19  jrh
* Release 2.3
*
* Revision 1.4  1999/05/24 01:25:52  jrh
* Release 2.2.1
*
* Revision 1.3  1999/02/07 21:50:24  jrh
* Release 2.2
*
* Revision 1.2  1998/01/26 00:48:00  jrh
* Release 2.1
*
* Revision 1.1  1996/12/10  18:41:22  jrh
* Initial revision
*
*/
#include<sys/types.h>
#include<dirent.h>
#include<fnmatch.h>
#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/Intrinsic.h>
#include<X11/Shell.h>
#include<X11/cursorfont.h>
#include<Xm/Xm.h>
#include<Xm/DialogS.h>
#include<Xm/DrawingA.h>
#include<Xm/Form.h>
#include<Xm/MwmUtil.h> 
#include<Xm/PushBG.h>
#include<Xm/RowColumn.h>
#include<Xm/SeparatoG.h>
#include<Xm/ToggleBG.h>
#include<GL/gl.h>
#include<GL/glu.h>
#include "viewmol.h"

#define TEXTURE_WIDTH  64
#define TEXTURE_HEIGHT 64

void makeWindow(int, char *, void *func());
Widget makeViewerMenu(Widget);
void initSpectrum(Widget, caddr_t, caddr_t);
void makeSpectrumMenu(void);
void initMODiagram(Widget, caddr_t, caddr_t);
void makeMODiagramMenu(void);
void initHistory(Widget, caddr_t, caddr_t);
void makeHistoryMenu(void);
void setCursor(Widget, unsigned int);
void setMenuItem(int, int);
void blendToPicture(void);
struct MenuItem *makeMoleculesMenu(struct MenuItem *, int);
struct MenuItem *makeScriptsMenu(struct MenuItem *);
#if defined LINUX || defined DARWIN
int matchScripts(const struct dirent *);
#else
int matchScripts(struct dirent *);
#endif
void setMenu(struct MOLECULE *);
void initPython(int, char **);

extern char *getStringResource(Widget, char *);
extern void createFileselect(void);
extern int  input(int, char **);
extern void setWindowTitle(Widget, char *);
extern void setAtom(struct MOLECULE *);
extern void inert(struct MOLECULE *);
extern int  makeConnectivity(struct MOLECULE *, int, int);
extern void *getmem(size_t, size_t);
extern void *expmem(void *, size_t, size_t);
extern void fremem(void **);
extern void storeColor(Pixel, struct WINDOW *, int);
extern void redraw(int);
extern void drawBackground(int, Pixel, double);
extern int StringWidth(XFontStruct *, char *);
extern void deleteFontList(GLuint, XFontStruct *);
extern XFontStruct *makeRasterFont(Display *, char *, GLuint *);
extern void drawSpectrum(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void drawHistory(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void drawMODiagram(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void reshape(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void hardcopyCallback(Widget, caddr_t, XmAnyCallbackStruct *);
extern Widget makeMenu(Widget, int, char *, struct MenuItem *);
extern void processInput(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void (*drawString)(char *, double, double, double, double, GLuint, char);
extern void setWindowColor(int, Pixel, const float *);
extern void getImaginaryMode(Widget, caddr_t, caddr_t);
extern void selectMolecule(Widget, caddr_t, XmToggleButtonCallbackStruct *);
extern void setGeometry(int);
extern void setBondType(Widget, caddr_t, caddr_t);
extern XVisualInfo *getVisualInfo(Display *, Visual *);
extern Colormap getRGBcolormap(Display *, int, XVisualInfo *);
extern int checkZoom(int);
extern void setCellSliders(struct MOLECULE *);
extern void setWindowSize(double);
extern void initViewmolModule(void);
extern void initMoleculeModule(void);
extern void initAtomModule(void);
extern void initElementModule(void);
extern void initSpectrumModule(void);
extern void initHistoryModule(void);
extern void initEnergyLevelModule(void);
extern void initLightModule(void);
extern void initLabelModule(void);
extern void runScript(Widget, caddr_t, XmAnyCallbackStruct *);
extern void startModule(Widget, caddr_t, XmAnyCallbackStruct *);
extern void addBoundaryAtoms(struct MOLECULE *);
extern void getScreenCoordinates(double, double, double, double *, double *,
                                             double *);

extern struct MOLECULE *molecules;
extern struct WINDOW windows[];
extern Pixel stdcol[9];
extern int rgbMode, projectionMode;
extern Widget topShell;
extern float *transObject, *rotObject;
extern int nmolecule;
extern int label, showForces, noutput, nUndo;
extern int showUnitCell, showInertia, swapBuffers;
extern char language[], *moduleName;

extern XVisualInfo *vi;

#include "menudef.h"

int initViewer(int argc, char **argv, Widget widget)
{
  struct MOLECULE *mol;
  double box;
  GLubyte texture[TEXTURE_WIDTH][TEXTURE_HEIGHT][3];
  char def[]="variable", *string;
  register int i, j;

  setCursor(widget, XC_watch);
  if ((string=getStringResource(widget, "font")) == NULL) string=def;
  windows[VIEWER].font=makeRasterFont(XtDisplay(widget), string,
                                      &windows[VIEWER].GLfontId);
  createFileselect();

  transObject=(float *)getmem(MOLECULES, 3*sizeof(float));
  rotObject=(float *)getmem(MOLECULES, 4*sizeof(float));
  rotObject[4*VIEWPOINT+3]=1.0;
  rotObject[4*LIGHTNO0+3]=1.0;
  rotObject[4*LIGHTNO1+3]=1.0;
  rotObject[4*WORLD+3]=1.0;

  for (i=0; i<TEXTURE_WIDTH; i++)
  {
    for (j=0; j<TEXTURE_HEIGHT; j++)
    {
      if (i % 4)
      {
        texture[i][j][0]=(GLubyte)255;
        texture[i][j][1]=(GLubyte)255;
        texture[i][j][2]=(GLubyte)255;
      }
      else
      {
        texture[i][j][0]=(GLubyte)0;
        texture[i][j][1]=(GLubyte)0;
        texture[i][j][2]=(GLubyte)0;
      }
    }
  }
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TEXTURE_WIDTH, TEXTURE_HEIGHT,
               0, GL_RGB, GL_UNSIGNED_BYTE, texture);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

  windows[VIEWER].menu=makeViewerMenu(windows[VIEWER].widget);
  if (!input(argc, argv))
  {
    setMenuItem(VIEWER_SELECT, False);
/*  setMenuItem(VIEWER_BONDTYPE, False);
    setMenuItem(VIEWER_INERTIA, False);
    setMenuItem(VIEWER_LABEL, False);
    setMenuItem(VIEWER_THERMODYNAMICS, False);*/
    setMenuItem(VIEWER_HARDCOPY, False);
    setMenuItem(VIEWER1_SAVE, False);
    setMenuItem(VIEWER1_DELETE, False);
    setMenuItem(VIEWER1_BUILD, False);
    setCursor(widget, XC_top_left_arrow);
    return(FALSE);
  }
  box=0.0;
  for (i=0; i<nmolecule; i++)
  {
    mol=&molecules[i];
    setAtom(mol);
    inert(mol);
    if (mol->unitcell) addBoundaryAtoms(mol);
    if (!makeConnectivity(mol, TRUE, TRUE)) return(FALSE);
    box=windows[VIEWER].far > box ? windows[VIEWER].far : box;
    if (!mol->unitcell) showUnitCell=FALSE;
  }
  setWindowSize(box);
  setWindowTitle(windows[VIEWER].widget, molecules[windows[VIEWER].set].title);
  windows[VIEWER].menu=makeViewerMenu(windows[VIEWER].widget);
  blendToPicture();
  setCursor(widget, XC_top_left_arrow);
  return(TRUE);
}

Widget makeViewerMenu(Widget widget)
{
  static struct MenuItem *moleculesMenu=NULL;
  static struct MenuItem *scriptsMenu=NULL;
  Widget menu;
  struct MOLECULE *mol;
  register int i;

  if (nmolecule > 1)
  {
    moleculesMenu=makeMoleculesMenu(moleculesMenu, VIEWER);
    i=VIEWER_SELECT;
    viewerMenu[i & 0xff].subitems=moleculesMenu;
  }
  scriptsMenu=makeScriptsMenu(scriptsMenu);
  i=VIEWER_RUNSCRIPT;
  viewerMenu[i & 0xff].subitems=scriptsMenu;
  menu=makeMenu(widget, XmMENU_POPUP, "viewmol", viewerMenu);
  if (molecules == NULL)
    mol=NULL;
  else
  {
    if (windows[VIEWER].set >= 0)
      mol=&molecules[windows[VIEWER].set];
    else
      mol=&molecules[0];
  }
  if (windows[VIEWER].mode == WIREMODEL)
  {
    setMenuItem(VIEWER_WIRE, False);
    setMenuItem(VIEWER_RAYTRACING, False);
  }
  if (windows[VIEWER].mode == STICKMODEL) setMenuItem(VIEWER_STICK, False);
  if (windows[VIEWER].mode == BALLMODEL)  setMenuItem(VIEWER_BALL, False);
  if (windows[VIEWER].mode == CUPMODEL)   setMenuItem(VIEWER_CPK, False);
  if (nmolecule == 1)                     setMenuItem(VIEWER_SELECT, False);
  if (projectionMode == ORTHO)            setMenuItem(VIEWER_FOREGROUND, False);
  if (noutput == 0)                       setMenuItem(VIEWER1_SAVE, False);
  if (nUndo == 0)                         setMenuItem(VIEWER2_UNDO, False);
  setMenu(mol);
  return(menu);
}

void initSpectrum(Widget w, caddr_t client_data, caddr_t call_data)
{
  Pixel pixel;
  char t[7], *string, line[MAXLENLINE];

  makeWindow(SPECTRUM, "spectrum", (void *(*)())drawSpectrum);
  string=getStringResource(windows[SPECTRUM].widget, "font");
  windows[SPECTRUM].font=makeRasterFont(XtDisplay(windows[SPECTRUM].widget),
                                        string, &windows[SPECTRUM].GLfontId);
  if (windows[VIEWER].set >= 0)
    windows[SPECTRUM].set=windows[VIEWER].set;
  else
    windows[SPECTRUM].set=0;
  makeSpectrumMenu();
  XtVaGetValues(windows[SPECTRUM].widget, XmNbackground, &pixel, NULL);
  storeColor(pixel, &windows[SPECTRUM], BACKGROUND);
  XtVaGetValues(windows[SPECTRUM].widget, XmNforeground, &pixel, NULL);
  storeColor(pixel, &windows[SPECTRUM], FOREGROUND);
  sprintf(t, "title%.1d", windows[SPECTRUM].mode);
  string=getStringResource(XtParent(windows[SPECTRUM].widget), t);
  sprintf(line, string, molecules[windows[SPECTRUM].set].title);
  setWindowTitle(windows[SPECTRUM].widget, line);
}

void makeSpectrumMenu(void)
{
  static struct MenuItem *submenu1=NULL, *submenu2=NULL;
  struct MOLECULE *mol;
  char *label;
  int imol;
  register int i;

  imol=windows[SPECTRUM].set;
  mol=&molecules[imol];
  if (mol->imag != 0)
  {
    if (submenu1 != NULL) fremem((void **)&submenu1);
    submenu1=(struct MenuItem *)getmem(mol->imag+1, sizeof(struct MenuItem));
    label=(char *)getmem(mol->imag, 10);
    for (i=0; i<mol->imag; i++)
    {
      sprintf(&label[10*i], "%7.2f i", -mol->normal_modes[i].wavenumber);
      submenu1[i].label=&label[10*i];
      submenu1[i].class=&xmPushButtonGadgetClass;
      submenu1[i].callback=getImaginaryMode;
      submenu1[i].callback_data=(XtPointer)i;
      submenu1[i].widget=(Widget)NULL;
      submenu1[i].subitems=NULL;
    }
    submenu1[i].label=NULL; 
    i=SPECTRUM_IMAGINARY;
    spectrumMenu[i & 0xff].subitems=submenu1;
  }
  if (nmolecule > 1)
  {
    submenu2=makeMoleculesMenu(submenu2, SPECTRUM);
    i=SPECTRUM_SELECT;
    spectrumMenu[i & 0xff].subitems=submenu2;
  }
  windows[SPECTRUM].menu=makeMenu(windows[SPECTRUM].widget,
                                  XmMENU_POPUP, "spectrum_menu", spectrumMenu);
  setMenuItem(VIEWER_SPECTRUM, False);
  if (nmolecule <= 1)
    setMenuItem(SPECTRUM_SELECT, False);
  else
  {
    for (i=0; i<nmolecule; i++)
    {
      if (molecules[i].normal_modes == NULL)
          XtVaSetValues(submenu2[i].widget, XmNsensitive, False, NULL);
      if (imol == i)
          XtVaSetValues(submenu2[i].widget, XmNset, True, NULL);
    }
  }
  if (mol->imag == 0) setMenuItem(SPECTRUM_IMAGINARY, False);
  setMenuItem(SPECTRUM_DELETE, False);
  if (!checkZoom(SPECTRUM)) setMenuItem(SPECTRUM_ZOOMOUT, False);
}

void initHistory(Widget w, caddr_t client_data, caddr_t call_data)
{
  Pixel pixel;
  double xs, ys, zs;
  char *string, line[MAXLENLINE];

  makeWindow(HISTORY, "history", (void *(*)())drawHistory);
  string=getStringResource(windows[HISTORY].widget, "font");
  windows[HISTORY].font=makeRasterFont(XtDisplay(windows[HISTORY].widget),
                                       string, &windows[HISTORY].GLfontId);
  if (windows[VIEWER].set >= 0)
    windows[HISTORY].set=windows[VIEWER].set;
  else
    windows[HISTORY].set=0;
  makeHistoryMenu();
  XtVaGetValues(windows[HISTORY].widget, XmNbackground, &pixel, NULL);
  storeColor(pixel, &windows[HISTORY], BACKGROUND);
  XtVaGetValues(windows[HISTORY].widget, XmNforeground, &pixel, NULL);
  storeColor(pixel, &windows[HISTORY], FOREGROUND);
  storeColor(stdcol[GREEN], &windows[HISTORY], GNORM);
  setGeometry(TRUE);
  string=getStringResource(XtParent(windows[HISTORY].widget), "title");
  sprintf(line, string, molecules[windows[HISTORY].set].title);
  setWindowTitle(windows[HISTORY].widget, line);
  redraw(HISTORY);
  getScreenCoordinates((double)(molecules[windows[HISTORY].set].nhist), 0.0, 0.0, &xs, &ys, &zs);
  windows[HISTORY].mouseX=(int)xs;
  redraw(VIEWER);
}

void makeHistoryMenu(void)
{
  static struct MenuItem *submenu=NULL;
  int i;

  if (nmolecule > 1)
  {
    submenu=makeMoleculesMenu(submenu, HISTORY);
    i=HISTORY_SELECT;
    historyMenu[i & 0xff].subitems=submenu;
  }
  windows[HISTORY].menu=makeMenu(windows[HISTORY].widget,
                                 XmMENU_POPUP, "history_menu", historyMenu);
  setMenuItem(VIEWER_OPTIMIZATION, False);
  if (nmolecule <= 1)
  {
    setMenuItem(HISTORY_SELECT, False);
    windows[HISTORY].set=0;
  }
  else
  {
    for (i=nmolecule; i>=0; i--)
    {
      if (molecules[i].history == NULL)
          XtVaSetValues(submenu[i].widget, XmNsensitive, False, NULL);
      else
        windows[HISTORY].set=i;
    }
    for (i=0; i<nmolecule; i++)
    {
      if (windows[HISTORY].set == i)
          XtVaSetValues(submenu[i].widget, XmNset, True, NULL);
    }
  }
}

void initMODiagram(Widget w, caddr_t client_data, caddr_t call_data)
{
  Pixel pixel;
  char *string, line[MAXLENLINE];

  makeWindow(MO, "MODiagram", (void *(*)())drawMODiagram);
  string=getStringResource(windows[MO].widget, "font");
  windows[MO].font=makeRasterFont(XtDisplay(windows[MO].widget), string,
                                  &windows[MO].GLfontId);
  /* It seems that under Linux the greekFont resource, although set
     in the fallbacks, cannot always be retrieved by the call to
     getStringResource. Therefore set it here if the call fails. */
  if ((string=getStringResource(windows[MO].widget, "greekFont")) == NULL)
    string="-adobe-symbol-medium-r-normal--14-*";
  windows[MO].greekFont=makeRasterFont(XtDisplay(windows[MO].widget), string,
                                       &windows[MO].GLgreekFontId);
  if (windows[VIEWER].set >= 0)
    windows[MO].set=windows[VIEWER].set;
  else
    windows[MO].set=0;
  makeMODiagramMenu();
  XtVaGetValues(windows[MO].widget, XmNbackground, &pixel, NULL);
  storeColor(pixel, &windows[MO], BACKGROUND);
  XtVaGetValues(windows[MO].widget, XmNforeground, &pixel, NULL);
  storeColor(pixel, &windows[MO], FOREGROUND);
  if ((string=getStringResource(topShell, "MO-energy")) == NULL)
  {
    windows[MO].bottom=1.05*molecules[windows[MO].set].orbitals[0].energy;
    windows[MO].top=1.05*molecules[windows[MO].set].orbitals[molecules[windows[MO].set].nbasfu-1].energy;
  }
  else
  {
    windows[MO].bottom=atof(strtok(string, ":"));
    windows[MO].top=atof(strtok(NULL, ":"));
  }
  windows[MO].horizontalMargin=0;
  windows[MO].verticalMargin=0;
  string=getStringResource(XtParent(windows[MO].widget), "title");
  sprintf(line, string, molecules[windows[MO].set].title);
  setWindowTitle(windows[MO].widget, line);
}

void makeMODiagramMenu(void)
{
  static struct MenuItem *submenu=NULL;
  int i;

  if (nmolecule > 1)
  {
    submenu=makeMoleculesMenu(submenu, MO);
    i=MO_SELECT;
    MODiagramMenu[i & 0xff].subitems=submenu;
  }
  windows[MO].menu=makeMenu(windows[MO].widget, XmMENU_POPUP,
                            "MODiagram_menu", MODiagramMenu);
  setMenuItem(MO_TRANSITION, False);
  setMenuItem(MO_ZOOMOUT, False);
  setMenuItem(VIEWER_ENERGYLEVEL, False);
  if (nmolecule <= 1)
    setMenuItem(MO_SELECT, False);
  else
  {
    for (i=0; i<nmolecule; i++)
    {
      if (molecules[i].orbitals == NULL)
          XtVaSetValues(submenu[i].widget, XmNsensitive, False, NULL);
      if (windows[MO].set == i)
          XtVaSetValues(submenu[i].widget, XmNset, True, NULL);
    }
  }
}

void makeWindow(int which, char *name, void *drawFunc())
{
  String translations="<KeyDown>:    DrawingAreaInput()\n\
                       <Btn1Motion>: DrawingAreaInput()\n\
                       <Btn2Motion>: DrawingAreaInput()\n\
                       <BtnDown>:    DrawingAreaInput()\n\
                       <BtnUp>:      DrawingAreaInput()";
  Display *display;
  Visual *vi;
  Colormap colormap;
  Widget shell;
  int depth;

  display=XtDisplay(topShell);
  XtVaGetValues(topShell, XtNvisual, &vi, XtNdepth, &depth, XtNcolormap, &colormap, NULL);
  shell=XtVaCreatePopupShell(name, applicationShellWidgetClass, topShell,
                             XtNvisual, vi,
                             XtNdepth, depth,
                             XtNcolormap, colormap,
                             NULL, 0);
  windows[which].widget=XtVaCreateManagedWidget(name, xmDrawingAreaWidgetClass, shell,
                                                XtNvisual, vi,
                                                XmNtranslations, XtParseTranslationTable(translations),
                                                XmNmarginHeight, 0,
                                                XmNmarginWidth, 0,
                                                NULL);
  XtManageChild(shell);
  XtRealizeWidget(shell);

  windows[which].context=glXCreateContext(display, getVisualInfo(display, vi), None, GL_TRUE);
  glXMakeCurrent(XtDisplay(windows[which].widget), XtWindow(windows[which].widget), windows[which].context);
  XtAddCallback(windows[which].widget, XmNinputCallback, (XtCallbackProc)processInput,
                NULL);
  XtAddCallback(windows[which].widget, XmNresizeCallback, (XtCallbackProc)reshape,
                (XtPointer)which);
  XtAddCallback(windows[which].widget, XmNexposeCallback, (XtCallbackProc)drawFunc,
                NULL);
  windows[which].smooth=0;
}

void setCursor(Widget widget, unsigned int shape)
{
  static Cursor cursor=0;
  static unsigned int oldShape=0;
  Display *display;
  Window  window;

  display=XtDisplay(widget);
  window=XtWindow(widget);
  if (shape != oldShape)
  {
    if (cursor != 0) XFreeCursor(display, cursor);
    cursor=XCreateFontCursor(display, shape);
    oldShape=shape;
  }
  XDefineCursor(display, window, cursor);
  XFlush(display);
}

void showTitle(Widget widget,  caddr_t client_data, XmDrawingAreaCallbackStruct *data)
{
  Dimension width, height;
  Display *display;
  XFontStruct *font;
  GLuint GLfont;
  char viewmol[8] = PROGRAM;
  char *version, *by;
  char author[21] = "Jörg-Rüdiger Hill";
  char versionLine[30];
  const float yellow[4]  = {1.0, 1.0, 0.0, 0.0};
  const float black[4]   = {0.0, 0.0, 0.0, 0.0};
  float save[3];
  int w, cyrillic=FALSE;

  XtVaGetValues(windows[VIEWER].widget, XtNwidth, &width, XtNheight, &height, NULL);
  display=XtDisplay(windows[VIEWER].widget);
  by=getStringResource(topShell, "fontList");
  if (by && strstr(by, "koi8"))
  {
    cyrillic=TRUE;
    strcpy(viewmol, "÷ÀÍÏÌ");
    strcpy(author, "éÏÒÇÁ-òÙÄÉÇÅÒÁ èÉÌÌÁ");
  }
  strcpy(language, getStringResource(topShell, "language"));
  version=getStringResource(topShell, "version");
  strcpy(versionLine, version);
  strcat(versionLine, " ");
  strcat(versionLine, VERSION);
  glXMakeCurrent(XtDisplay(windows[VIEWER].widget), XtWindow(windows[VIEWER].widget), windows[VIEWER].context);
  glDrawBuffer(GL_BACK);
  save[0]=windows[VIEWER].background_rgb[0];
  save[1]=windows[VIEWER].background_rgb[1];
  save[2]=windows[VIEWER].background_rgb[2];
  windows[VIEWER].background_rgb[0]=0.0;
  windows[VIEWER].background_rgb[1]=0.0;
  windows[VIEWER].background_rgb[2]=1.0;
  windows[VIEWER].smooth=2;
  drawBackground(VIEWER, stdcol[SKYBLUE], (double)0.0);
  windows[VIEWER].background_rgb[0]=save[0];
  windows[VIEWER].background_rgb[1]=save[1];
  windows[VIEWER].background_rgb[2]=save[2];
  windows[VIEWER].smooth=0;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D((double)0.0, (double)width, (double)0.0, (double)height);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  setWindowColor(FOREGROUND, stdcol[YELLOW], yellow);
  if (cyrillic)
  {
    font=makeRasterFont(display, "-cronyx-times-bold-r-normal--34-240-100-100-p-124-koi8-r",
                        &GLfont);
    if (font == NULL)
    {
      font=makeRasterFont(display, "fixed", &GLfont);
      strcpy(viewmol, PROGRAM);
    }
  }
  else
  {
    font=makeRasterFont(display, "-adobe-times-bold-r-normal--34-240-100-100-p-177-iso8859-1",
                        &GLfont);
    if (font == NULL)
      font=makeRasterFont(display, "fixed", &GLfont);
  }
  w=StringWidth(font, viewmol);
  (*drawString)(viewmol, (GLdouble)(width-w)/2.e0, 2.e0/3.e0*height, 0.0, 0.0, GLfont, 'l');
  deleteFontList(GLfont, font);
  setWindowColor(FOREGROUND, stdcol[BLACK], black);
  if (cyrillic)
  {
    font=makeRasterFont(display, "-cronyx-helvetica-medium-r-normal--14-100-100-100-p-56-koi8-r",
                        &GLfont);
    if (font == NULL)
    {
      font=makeRasterFont(display, "fixed", &GLfont);
      strcpy(author, "Jörg-Rüdiger Hill");
    }
  }
  else
  {
    font=makeRasterFont(display, "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-1",
                        &GLfont);
    if (font == NULL)
      font=makeRasterFont(display, "fixed", &GLfont);
  }
  w=StringWidth(font, versionLine);
  (*drawString)(versionLine, (GLdouble)(width-w)/2.e0, height/2.e0, 0.0, 0.0, GLfont, 'l');
  by=getStringResource(topShell, "by");
  w=StringWidth(font, by);
  (*drawString)(by, (GLdouble)(width-w)/2.e0, height/2.5e0, 0.0, 0.0, GLfont, 'l');
  w=StringWidth(font, author);
  (*drawString)(author, (GLdouble)(width-w)/2.e0, height/3.e0, 0.0, 0.0, GLfont, 'l');
  deleteFontList(GLfont, font);
  glXSwapBuffers(XtDisplay(windows[VIEWER].widget), XtWindow(windows[VIEWER].widget));
}

void setMenuItem(int item, int disable)
{
  struct MenuItem *m=NULL;

  switch (item >> 8)
  {
    case VIEWER:    m=viewerMenu;
                    break;
    case SPECTRUM:  m=spectrumMenu;
                    break;
    case MO:        m=MODiagramMenu;
                    break;
    case HISTORY:   m=historyMenu;
                    break;
    case VIEWER1:   m=moleculeMenu;
                    break;
    case VIEWER2:   m=geometryMenu;
                    break;
  }
  XtVaSetValues(m[item & 0xff].widget, XmNsensitive, disable, NULL);
}

void blendToPicture(void)
{

/* Switch smoothly from title to picture */

  Dimension width, height;
  GLsizei incx, incy, ngrid=5;
  register int i, j, k;

  XtVaGetValues(windows[VIEWER].widget, XmNwidth, &width, XmNheight, &height,
                NULL);
  incx=(GLsizei)width/ngrid;
  incy=(GLsizei)height/ngrid;
  if (width % ngrid != 0) incx++;
  if (height % ngrid !=0) incy++;
  swapBuffers=FALSE;
  redraw(VIEWER);
  swapBuffers=TRUE;
  glReadBuffer(GL_BACK);
  glDrawBuffer(GL_FRONT);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D((double)0.0, (double)width, (double)0.0, (double)height);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  i=0;
  j=0;
  for (k=ngrid-1; k>0; k--)
  {
    while (i<k)
    {
      glRasterPos2i((GLint)(i*incx), (GLint)(j*incy));
      glCopyPixels((GLint)(i*incx), (GLint)(j*incy), incx, incy, GL_COLOR);
      i++;
    }
    while (j<k)
    {
      glRasterPos2i((GLint)(i*incx), (GLint)(j*incy));
      glCopyPixels((GLint)(i*incx), (GLint)(j*incy), incx, incy, GL_COLOR);
      j++;
    }
    while (i>ngrid-k-1)
    {
      glRasterPos2i((GLint)(i*incx), (GLint)(j*incy));
      glCopyPixels((GLint)(i*incx), (GLint)(j*incy), incx, incy, GL_COLOR);
      i--;
    }
    while (j>ngrid-k)
    {
      glRasterPos2i((GLint)(i*incx), (GLint)(j*incy));
      glCopyPixels((GLint)(i*incx), (GLint)(j*incy), incx, incy, GL_COLOR);
      j--;
    }
    glXWaitGL();
  }
  glRasterPos2i((GLint)(i*incx), (GLint)(j*incy));
  glCopyPixels((GLint)(i*incx), (GLint)(j*incy), incx, incy, GL_COLOR);
  glXWaitGL();
  glDrawBuffer(GL_BACK);
}

struct MenuItem *makeMoleculesMenu(struct MenuItem *submenu, int window)
{
  static char all[]="all", sep[]="sep";
  int offset;
  register int i;

  if (submenu != NULL) fremem((void **)&submenu);
  if (windows[window].selectMenu != NULL) fremem((void **)&windows[window].selectMenu);
  offset=nmolecule;
  if (window == VIEWER) offset+=2;
  submenu=(struct MenuItem *)getmem(offset+1, sizeof(struct MenuItem));
  windows[window].selectMenu=(struct MENUDATA *)getmem(offset, sizeof(struct MENUDATA));
  offset=0;
  if (window == VIEWER)
  {
    submenu[0].label=all;
    submenu[0].class=&xmToggleButtonGadgetClass;
    submenu[0].callback=selectMolecule;
    windows[window].selectMenu[0].submenu=submenu;
    windows[window].selectMenu[0].window=window;
    windows[window].selectMenu[0].which=(-1);
    submenu[0].callback_data=(XtPointer)(&windows[window].selectMenu[0]);
    submenu[0].widget=(Widget)NULL;
    submenu[0].subitems=NULL;
    submenu[1].label=sep;
    submenu[1].class=&xmSeparatorGadgetClass;
    submenu[1].callback=NULL;
    submenu[1].callback_data=(XtPointer)NULL;
    submenu[1].widget=(Widget)NULL;
    submenu[1].subitems=NULL;
    offset=2; 
  }
  for (i=0; i<nmolecule; i++)
  {
    submenu[i+offset].label=molecules[i].title;
    submenu[i+offset].class=&xmToggleButtonGadgetClass;
    submenu[i+offset].callback=selectMolecule;
    windows[window].selectMenu[i+offset].submenu=submenu;
    windows[window].selectMenu[i+offset].window=window;
    windows[window].selectMenu[i+offset].which=i;
    submenu[i+offset].callback_data=(XtPointer)(&windows[window].selectMenu[i+offset]);
    submenu[i+offset].widget=(Widget)NULL;
    submenu[i+offset].subitems=NULL;
  }
  submenu[i+offset].label=NULL;
  return(submenu);
}

struct MenuItem *makeScriptsMenu(struct MenuItem *submenu)
{
  DIR *d;
  struct dirent **namelist=NULL;
  static char sel[]="select", sep[]="sep";
  char path[PATH_MAX], cmd[PATH_MAX], module[PATH_MAX], *word;
  int n;
  register int i, j;

  if (submenu != NULL) return(submenu); /* fremem((void **)&submenu); */
  strncpy(path, getenv("VIEWMOLPATH"), PATH_MAX-1);
  strncat(path, "/scripts", PATH_MAX-strlen(path));
  if ((d=opendir(path)) != NULL)
  {
    closedir(d);
    strncpy(cmd, "import sys\nsys.path.insert(0, \"", PATH_MAX-1);
    strncat(cmd, path, PATH_MAX-strlen(cmd)-1);
    strncat(cmd, "\")", PATH_MAX-strlen(cmd)-1);
    PyRun_SimpleString(cmd);
    n=scandir(path, &namelist, matchScripts, alphasort);
    if (n > 0)
    {
      submenu=(struct MenuItem *)getmem(n+3, sizeof(struct MenuItem));
      j=0;
      for (i=0; i<n; i++)
      {
        strncpy(module, namelist[i]->d_name, PATH_MAX-1);
        word=strstr(module, ".py");
        if (word) *word='\0';
        sprintf(cmd, "try:\n  import %s\nexcept:\n  print \"Error loading module %s.\"\nelse:\n  module%2.2d=%s.%s()\n  module%2.2d.register(\"%s\")\n",
                module, module, i, module, module, i, language);
	moduleName='\0';
        PyRun_SimpleString(cmd);
        if (moduleName)
        {
          submenu[j].label=moduleName;
          submenu[j].class=&xmPushButtonGadgetClass;
          submenu[j].callback=startModule;
          submenu[j].callback_data=(XtPointer)j;
          submenu[j].widget=(Widget)NULL;
          submenu[j++].subitems=NULL;
        }
      }
      submenu[j].label=sep;
      submenu[j].class=&xmSeparatorGadgetClass;
      submenu[j].callback=(XtPointer)0;
      submenu[j].callback_data=(XtPointer)0;
      submenu[j].widget=(Widget)NULL;
      submenu[j++].subitems=NULL;
    }
    else
    {
      submenu=(struct MenuItem *)getmem(1, sizeof(struct MenuItem));
      j=0;
    }
  }
  else
  {
    submenu=(struct MenuItem *)getmem(1, sizeof(struct MenuItem));
    j=0;
  }
  submenu[j].label=sel;
  submenu[j].class=&xmPushButtonGadgetClass;
  submenu[j].callback=runScript;
  submenu[j].callback_data=(XtPointer)0;
  submenu[j].widget=(Widget)NULL;
  submenu[j++].subitems=NULL;
  submenu[j].label=NULL;
  fremem((void **)&namelist);
  return(submenu);
}

#if defined LINUX || defined DARWIN
int matchScripts(const struct dirent *d)
#else
int matchScripts(struct dirent *d)
#endif
{
  return(!fnmatch("*.py", d->d_name, 0));
}

void setMenu(struct MOLECULE *mol)
{
  if (!mol)
  {
    setMenuItem(VIEWER_BONDTYPE, False);
    setMenuItem(VIEWER_THERMODYNAMICS, False);
    setMenuItem(VIEWER_INERTIA, False);
    setMenuItem(VIEWER_LABEL, False);
    setMenuItem(VIEWER_ANNOTATE, False);
  }
  else 
  {
    setMenuItem(VIEWER_BONDTYPE, True);
    setMenuItem(VIEWER_THERMODYNAMICS, True);
    setMenuItem(VIEWER_INERTIA, True);
    setMenuItem(VIEWER_LABEL, True);
    setMenuItem(VIEWER_ANNOTATE, True);
  }
  if (!mol || (mol->basisset == NULL && mol->gridObjects == NULL)) setMenuItem(VIEWER_WAVEFUNCTION, False);
  else                                                      setMenuItem(VIEWER_WAVEFUNCTION, True);
  if (!mol || mol->orbitals == NULL || windows[MO].widget)  setMenuItem(VIEWER_ENERGYLEVEL, False);
  else                                                      setMenuItem(VIEWER_ENERGYLEVEL, True);
  if (!mol || mol->nhist < 2 || windows[HISTORY].widget)    setMenuItem(VIEWER_OPTIMIZATION, False);
  else                                                      setMenuItem(VIEWER_OPTIMIZATION, True);
  if (!mol || mol->history == NULL)                         setMenuItem(VIEWER_FORCES, False);
  else                                                      setMenuItem(VIEWER_FORCES, True);
  if (!mol || mol->nmodes == 0 || windows[SPECTRUM].widget) setMenuItem(VIEWER_SPECTRUM, False);
  else                                                      setMenuItem(VIEWER_SPECTRUM, True);
  if (!mol || !mol->unitcell)
    setMenuItem(VIEWER_UNITCELL, False);
  else
  {
    setMenuItem(VIEWER_UNITCELL, True);
    setCellSliders(mol);
  }
  if (!mol || mol->ninternal == 0)
  {
    setMenuItem(VIEWER2_ALL, False);
    setMenuItem(VIEWER2_LAST, False);
  }
  else
  {
    setMenuItem(VIEWER2_ALL, True);
    setMenuItem(VIEWER2_LAST, True);
  }
}

Widget initShell(Widget parent, char *name, Widget *board, Widget *form)
{
  Arg args[5];
  Visual *vi;
  Colormap colormap;
  Pixel bg;
  Widget dialog;
  char line[MAXLENLINE];

  XtVaGetValues(topShell, XmNvisual, &vi, XmNcolormap, &colormap,
                XmNbackground, &bg, NULL);
  XtSetArg(args[0], XmNautoUnmanage, False);
  XtSetArg(args[1], XmNdefaultPosition, False);
  XtSetArg(args[2], XmNvisual, vi);
  XtSetArg(args[3], XmNcolormap, colormap);
  if (XmIsMotifWMRunning(topShell))
    XtSetArg(args[4], XmNmwmDecorations, MWM_DECOR_RESIZEH | MWM_DECOR_TITLE);
  else
    XtSetArg(args[4], (char *)NULL, 0);

  strcpy(line, name);
  strcat(line, "_popup");
  dialog=XmCreateDialogShell(parent, line, args, XtNumber(args));
  *board=XtVaCreateWidget(name, xmFormWidgetClass, dialog,
                          XmNautoUnmanage, False,
                          XmNdefaultPosition, False,
                          NULL);
  *form=XtVaCreateWidget("rowcolumn", xmRowColumnWidgetClass, *board,
                         XmNorientation, XmVERTICAL,
                         XmNtopAttachment, XmATTACH_FORM,
                         XmNbottomAttachment, XmATTACH_FORM,
                         XmNleftAttachment, XmATTACH_FORM,
                         XmNrightAttachment, XmATTACH_FORM,
                         NULL);  
  return(dialog);
}

void initPython(int argc, char **argv)
{
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  PySys_SetArgv(argc, argv);
  initViewmolModule();
  initMoleculeModule();
  initAtomModule();
  initElementModule();
  initSpectrumModule();
  initHistoryModule();
  initEnergyLevelModule();
  initLightModule();
  initLabelModule();
}
