/* 
   A* -------------------------------------------------------------------
   B* This file contains source code for the PyMOL computer program
   C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. 
   D* -------------------------------------------------------------------
   E* It is unlawful to modify or remove this copyright notice.
   F* -------------------------------------------------------------------
   G* Please see the accompanying LICENSE file for further information. 
   H* -------------------------------------------------------------------
   I* Additional authors of this source file include:
   -* 
   -* 
   -*
   Z* -------------------------------------------------------------------
*/
#include"os_python.h"
#include"os_predef.h"
#include"os_std.h"
#include"os_gl.h"

#include <set>
#include <algorithm>
#include <map>
#include <clocale>

#include"Version.h"
#include"main.h"
#include"Base.h"
#include"OOMac.h"
#include"Executive.h"
#include"SpecRec.h"
#include"ObjectMesh.h"
#include"ObjectDist.h"
#include"ObjectSurface.h"
#include"ObjectSlice.h"
#include"ObjectAlignment.h"
#include"ObjectGroup.h"
#include"ObjectVolume.h"
#include"ObjectCallback.h"
#include"ObjectMap.h"
#include"ListMacros.h"
#include"MyPNG.h"
#include"Ortho.h"
#include"Scene.h"
#include"ScenePicking.h"
#include"SceneRay.h"
#include"Selector.h"
#include"Vector.h"
#include"Color.h"
#include"Setting.h"
#include"Matrix.h"
#include"P.h"
#include"PConv.h"
#include"Match.h"
#include"ObjectCGO.h"
#include"Util.h"
#include"Util2.h"
#include"Wizard.h"
#include"ScrollBar.h"
#include"Movie.h"
#include"ObjectGadgetRamp.h"
#include"SculptCache.h"
#include"Control.h"
#include"Menu.h"
#include"Map.h"
#include"Editor.h"
#include"RepDot.h"
#include"Seq.h"
#include"Text.h"
#include"PyMOL.h"
#include"PyMOLOptions.h"
#include"Tracker.h"
#include"Word.h"
#include"main.h"
#include"Parse.h"
#include"PlugIOManager.h"
#include "Lex.h"

#include"OVContext.h"
#include"OVLexicon.h"
#include"OVOneToOne.h"
#include"OVOneToAny.h"

#include"ShaderMgr.h"
#include"File.h"
#include"MacPyMOL.h"

#include "MovieScene.h"
#include "Texture.h"

#ifndef _PYMOL_NOPY
#include "ce_types.h"
#endif

#ifdef WIN32
#define mkstemp _mktemp_s
#endif

#define cExecObject 0
#define cExecSelection 1
#define cExecAll 2

#define cTempRectSele "_rect"
#define cLeftButSele "lb"
#define cIndicateSele "indicate"

typedef struct PanelRec {
  SpecRec *spec;
  int nest_level;
  int is_group;
  int is_open;
  struct PanelRec *next;
} PanelRec;

typedef struct {
  int list_id;
  int next;
} ListMember;

struct _CExecutive {
  ::Block *Block;
  SpecRec *Spec;
  CTracker *Tracker;
  int Width, Height, HowFarDown;
  int ScrollBarActive;
  int NSkip;
  struct CScrollBar *ScrollBar;
  CObject *LastEdited;
  int DragMode;
  int Pressed, Over, LastOver, OldVisibility, ToggleMode, PressedWhat, OverWhat;
  SpecRec *LastChanged, *LastZoomed, *RecoverPressed;
  int ReorderFlag;
  OrthoLineType ReorderLog;
#ifndef GLUT_FULL_SCREEN
  // freeglut has glutLeaveFullScreen, no need to remember window dimensions
  int oldPX, oldPY, oldWidth, oldHeight;
#endif
  int all_names_list_id, all_obj_list_id, all_sel_list_id;
  OVLexicon *Lex;
  OVOneToOne *Key;
  int ValidGroups;
  int ValidSceneMembers;
  int ValidGridSlots;
  PanelRec *Panel;
  int ValidPanel;
  int CaptureFlag;
  int LastMotionCount;
  CGO *selIndicatorsCGO;
  int selectorTexturePosX, selectorTexturePosY, selectorTextureAllocatedSize, selectorTextureSize;
  short selectorIsRound;

  // AtomInfoType::unique_id -> (object, atom-index)
  ExecutiveObjectOffset *m_eoo; // VLA of (object, atom-index)
  OVOneToOne *m_id2eoo; // unique_id -> m_eoo-index
};

#ifndef NO_MMLIBS
#include "mmpymolx.h"
#endif

/* routines that still need to be updated for Tracker list iteration

Low priority:

ExecutiveSculptIterate
ExecutiveSculptActivate
ExecutiveSculptDeactivate
ExecutiveRenameObjectAtoms
ExecutiveSpheroid

*/

static int ExecutiveGetNamesListFromPattern(PyMOLGlobals * G, const char *name,
                                            int allow_partial, int expand_groups);

static void ExecutiveSpecEnable(PyMOLGlobals * G, SpecRec * rec, int parents, int log);
static void ExecutiveSetAllRepVisMask(PyMOLGlobals * G, int repmask, int state);
static SpecRec *ExecutiveFindSpec(PyMOLGlobals * G, const char *name);
static int ExecutiveDrag(Block * block, int x, int y, int mod);
static void ExecutiveSpecSetVisibility(PyMOLGlobals * G, SpecRec * rec,
                                       int new_vis, int mod, int parents);
static int ExecutiveSetObjectMatrix2(PyMOLGlobals * G, CObject * obj, int state,
                                     double *matrix);
static int ExecutiveGetObjectMatrix2(PyMOLGlobals * G, CObject * obj, int state,
                                     double **matrix, int incl_ttt);
int ExecutiveTransformObjectSelection2(PyMOLGlobals * G, CObject * obj, int state,
                                       const char *s1, int log, float *matrix, int homogenous,
                                       int global);

/*
 * ObjectIterator methods
 */
void ObjectIterator::reset() {
  rec = G->Executive->Spec;

  // DEBUG assume first element is always "all"
  if (rec->type != cExecAll)
    printf("Error: first SpecRec is not cExecAll\n");
}

bool ObjectIterator::next() {
  if (!rec || !(rec = rec->next))
    return false;

  if (rec->type != cExecObject)
    return next();

  return true;
}

CObject * ObjectIterator::getObject() {
  return rec->obj;
}

/*
 * True if `rec` and all its parent groups are enabled
 */
static bool SpecRecIsEnabled(const SpecRec * rec) {
  while (rec->visible && (rec = rec->group)) {}
  return !rec;
}

/* ======================================================= */

static void ReportEnabledChange(PyMOLGlobals * G, SpecRec *rec){
#ifdef _PYMOL_LIB
  if (G->CallbackObject && G->enabledCallback){
    G->enabledCallback(G->CallbackObject, rec->name, rec->visible);
  }
#endif
  OrthoInvalidateDoDraw(G);
  ExecutiveInvalidateSelectionIndicatorsCGO(G);
}

int ExecutiveGroupMotionModify(PyMOLGlobals *G, CObject *group, int action, 
                                int index, int count, int target, int freeze)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetExpandedGroupList(G,group->Name);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;
  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type != cObjectGroup) {
          ObjectMotionModify(rec->obj, action, index, count, target, freeze, true);
        }
        break;
      }
    }
  }
  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}

int ExecutiveGroupMotion(PyMOLGlobals *G, CObject *group,int action, int first,
                         int last, float power, float bias,
                         int simple, float linear, int wrap,
                         int hand, int window, int cycles, int state, int quiet)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetExpandedGroupList(G,group->Name);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;
  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type != cObjectGroup) {
          ObjectMotion(rec->obj,action,first,last,power,bias,simple,linear,wrap,hand,window,cycles,state,quiet);
        }
        break;
      }
    }
  }
  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}

int ExecutiveGroupCombineTTT(PyMOLGlobals *G, CObject *group, float *ttt, int reverse_order, int store)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetExpandedGroupList(G,group->Name);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;
  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type != cObjectGroup) {
          ObjectCombineTTT(rec->obj, ttt, reverse_order, store);
        }
        break;
      }
    }
  }
  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}

int ExecutiveGroupTranslateTTT(PyMOLGlobals *G, CObject *group, float *v, int store)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetExpandedGroupList(G,group->Name);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;
  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type != cObjectGroup) {
          ObjectTranslateTTT(rec->obj,v, store);
        }
        break;
      }
    }
  }
  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}


int ExecutiveMotionView(PyMOLGlobals *G, int action, int first,
              int last, float power, float bias,
              int simple, float linear, const char *name, int wrap,
              int hand, int window, int cycles,
              const char *scene_name, float scene_cut, int state, int quiet, int autogen)
{
  int ok = true;

  CExecutive *I = G->Executive;

  if(wrap < 0) {
    wrap = SettingGetGlobal_b(G, cSetting_movie_loop);
  }

  if((!name)||(!name[0])||(!strcmp(name,cKeywordNone))||
     (!strcmp(name,cKeywordAll))||(!strcmp(name,cKeywordSame))) { 
    if(autogen) { 
      /* if autogenerated, then use current settings */
      power  = SettingGetGlobal_f(G, cSetting_motion_power);
      bias   = SettingGetGlobal_f(G, cSetting_motion_bias);
      linear = SettingGetGlobal_f(G, cSetting_motion_linear);
      hand   = SettingGetGlobal_i(G, cSetting_motion_hand);
    }
    /* camera */

    ok = MovieView(G, action, first, last, power,
                   bias, true, linear, wrap, hand, window, cycles,
                   scene_name, scene_cut, state, quiet);

    if(name && name[0] && strcmp(name, cKeywordNone)) {
      /* also do all other objects */
      SpecRec *rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        switch(rec->type) {
        case cExecObject:
          if(autogen) {
            power  = SettingGet_f(G, NULL, rec->obj->Setting, cSetting_motion_power);
            bias   = SettingGet_f(G, NULL, rec->obj->Setting, cSetting_motion_bias);
            simple = SettingGet_i(G, NULL, rec->obj->Setting, cSetting_motion_simple);
            linear = SettingGet_f(G, NULL, rec->obj->Setting, cSetting_motion_linear);
            hand   = SettingGet_i(G, NULL, rec->obj->Setting, cSetting_motion_hand);
          }
          if((ObjectGetSpecLevel(rec->obj,0)>=0)||(!strcmp(name,cKeywordAll))) {
            ok = ObjectMotion(rec->obj, action, first, last, power, bias,
                              simple < 0 ? 0 : 1, 
                              linear, wrap, hand, window, cycles, state, quiet);
          }
          break;
        }
      }
    }
  } else { /* pattern */
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {

        switch (rec->type) {
        case cExecObject: 
          if(autogen) {
            power  = SettingGet_f(G, NULL, rec->obj->Setting, cSetting_motion_power);
            bias   = SettingGet_f(G, NULL, rec->obj->Setting, cSetting_motion_bias);
            simple = SettingGet_i(G, NULL, rec->obj->Setting, cSetting_motion_simple);
            linear = SettingGet_f(G, NULL, rec->obj->Setting, cSetting_motion_linear);
            hand   = SettingGet_i(G, NULL, rec->obj->Setting, cSetting_motion_hand);
          }
          
          ok = ObjectMotion(rec->obj, action, first, last, power, bias,
                            simple < 0 ? 0 : simple, 
                              linear, wrap, hand, window, cycles, state, quiet);
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);

    // fix for PYMOL-1465
    OrthoReshape(G, -1, -1, false);
  }
  ExecutiveCountMotions(G);
  return ok;
}



void ExecutiveMotionViewModify(PyMOLGlobals *G, int action, 
                               int index, int count, int target, const char *name,
                               int freeze,int quiet)
{
  CExecutive *I = G->Executive;
  if((!name)||(!name[0])||
     (!strcmp(name,cKeywordNone))||
     (!strcmp(name,cKeywordSame))||
     (!strcmp(name,cKeywordAll))) {
    /* camera */
    if(MovieGetSpecLevel(G,0)>=0) {
      MovieViewModify(G, action, index, count, target, true, true);
    }
    if((!name) || strcmp(name, cKeywordNone)) {
      /* also do all other objects */
      SpecRec *rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        switch(rec->type) {
        case cExecObject:
          if(ObjectGetSpecLevel(rec->obj,0)>=0) {
            ObjectMotionModify(rec->obj, action, index, count, target, true, true);
          }        
          break;
        }
      }
      ExecutiveMotionTrim(G);
    } else {
      ExecutiveMotionExtend(G,true);
    }
    
    if((!freeze) && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }
  } else { /* pattern */
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecObject: 
          if(ObjectGetSpecLevel(rec->obj,0)>=0) {
            /* only modify objects with motion matrices */
            ObjectMotionModify(rec->obj, action, index, count, target, freeze, false);
          }
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  ExecutiveCountMotions(G);
}

void ExecutiveMotionReinterpolate(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  while(ListIterate(I->Spec, rec, next)) {
    switch(rec->type) {
    case cExecAll:
      if(MovieGetSpecLevel(G,0)>=0) {
        MovieViewReinterpolate(G);
      }
      break;
    case cExecObject:
      if(ObjectGetSpecLevel(rec->obj,0)>=0) {
        ObjectMotionReinterpolate(rec->obj);
      }        
      break;
    }
  }
}

void ExecutiveMotionTrim(PyMOLGlobals * G)
{
  int n_frame = MovieGetLength(G);
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  while(ListIterate(I->Spec, rec, next)) {
    switch(rec->type) {
    case cExecObject:
      if(ObjectGetSpecLevel(rec->obj,0)>=0) {
        ObjectMotionTrim(rec->obj,n_frame);
      }        
      break;
    }
  }
}

void ExecutiveMotionExtend(PyMOLGlobals * G, int freeze)
{
  int n_frame = 0;
  int max_length = 0;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  if(MovieGetSpecLevel(G,-1)>0)
    n_frame = MovieGetLength(G);
  while(ListIterate(I->Spec, rec, next)) {
    switch(rec->type) {
    case cExecObject:
      if(ObjectGetSpecLevel(rec->obj,-1)>0) {
        int length = ObjectMotionGetLength(rec->obj);
        if(max_length < length)
          max_length = length;
      }
      break;
    }
  }
  if(max_length) {
    if(n_frame < max_length)
      MovieViewTrim(G,max_length);
    while(ListIterate(I->Spec, rec, next)) {
      switch(rec->type) {
      case cExecObject:
        if(ObjectGetSpecLevel(rec->obj,-1)>0) {
          ObjectMotionTrim(rec->obj,max_length);
        }        
        break;
      }
    }
  }
  if((!freeze) && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
    ExecutiveMotionReinterpolate(G);
  }

}

int ExecutiveCountMotions(PyMOLGlobals * G)
{
  int count = 0;
  CExecutive *I = G->Executive;
  if(MovieGetLength(G)) {
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      switch(rec->type) {
      case cExecAll:
        if(MovieGetSpecLevel(G,0)>=0)
          count++;
        break;
      case cExecObject:
        if(ObjectGetSpecLevel(rec->obj,0)>=0)
          count++;
        break;
      }
    }
  }
  
  if(count != I->LastMotionCount) {
    if(SettingGetGlobal_i(G,cSetting_movie_panel)) {
      OrthoDoViewportWhenReleased(G);
    }
    I->LastMotionCount = count;
  }
  
  return (count);
}

void ExecutiveMotionDraw(PyMOLGlobals * G, BlockRect *rect, int expected ORTHOCGOARG)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  int frames = MovieGetLength(G);
  BlockRect draw_rect = *rect;
  int count = 0;
  int height = rect->top - rect->bottom;
  while(ListIterate(I->Spec, rec, next)) {
    switch(rec->type) {
    case cExecAll:
      if(MovieGetSpecLevel(G,0)>=0) {
        int presentation = SettingGetGlobal_b(G, cSetting_presentation);
        if(presentation) { 
          expected = 1;
        }
        draw_rect.top = rect->top - (height * count) / expected;
        draw_rect.bottom = rect->top - (height * (count + 1)) / expected;
        MovieDrawViewElem(G,&draw_rect,frames ORTHOCGOARGVAR);
        count++;
        if(presentation) { 
          goto done;
        }
          
      }
      break;
    case cExecObject:
      if(ObjectGetSpecLevel(rec->obj,0)>=0) {
        draw_rect.top = rect->top - (height * count) / expected;
        draw_rect.bottom = rect->top - (height * (count + 1)) / expected;
        ObjectDrawViewElem(rec->obj,&draw_rect,frames ORTHOCGOARGVAR);
        count++;
      }
      break;
    }
  }
 done:
  return;
}

void ExecutiveMotionMenuActivate(PyMOLGlobals * G, BlockRect *rect, int expected, int passive, 
                                 int x, int y, int same)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  BlockRect draw_rect = *rect;
  int count = 0;
  int height = rect->top - rect->bottom;
  if(same) {
    if(MovieGetSpecLevel(G,0)>=0) {
      int n_frame = MovieGetLength(G);
      int frame = MovieXtoFrame(G, &draw_rect, n_frame, x, false);
      WordType frame_str = "0";
      if((frame>=0) && (frame<n_frame)) {
        sprintf(frame_str,"%d",frame+1);
      }
      MenuActivate2Arg(G, x, y, x, y, passive, "obj_motion","same",frame_str);
    }
  } else {
  while(ListIterate(I->Spec, rec, next)) {
    switch(rec->type) {
    case cExecAll:
      if(MovieGetSpecLevel(G,0)>=0) {
        draw_rect.top = rect->top - (height * count) / expected;
        draw_rect.bottom = rect->top - (height * (count + 1)) / expected;
        if((y>draw_rect.bottom) && (y<draw_rect.top)) {
          int n_frame = MovieGetLength(G);
          int frame = MovieXtoFrame(G, &draw_rect, n_frame, x, false);
          WordType frame_str = "0";
          if((frame>=0) && (frame<n_frame)) {
            sprintf(frame_str,"%d",frame+1);
          }
          MenuActivate1Arg(G, x, y, x, y, passive, "camera_motion",frame_str);
          goto done;
        }
        count++;
      }
      break;
    case cExecObject:
      if(ObjectGetSpecLevel(rec->obj,0)>=0) {
        draw_rect.top = rect->top - (height * count) / expected;
        draw_rect.bottom = rect->top - (height * (count + 1)) / expected;
        if((y>draw_rect.bottom) && (y<draw_rect.top)) {
          int n_frame = MovieGetLength(G);
          int frame = MovieXtoFrame(G, &draw_rect, n_frame, x, false);
          WordType frame_str = "0";
          if((frame>=0) && (frame<n_frame)) {
            sprintf(frame_str,"%d",frame+1);
          }
          MenuActivate2Arg(G, x, y, x, y, passive, "obj_motion", rec->obj->Name, frame_str);
          goto done;
        }
        count++;
      }
      break;
    }
  }
  }
 done:
  return;
}

void ExecutiveMotionClick(PyMOLGlobals * G, BlockRect *rect,int mode, int expected, int x, int y, int nearest)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  BlockRect draw_rect = *rect;
  int count = 0;
  int height = rect->top - rect->bottom;
  while(ListIterate(I->Spec, rec, next)) {
    switch(rec->type) {
    case cExecAll:
      if(MovieGetSpecLevel(G,0)>=0) {
        draw_rect.top = rect->top - (height * count) / expected;
        draw_rect.bottom = rect->top - (height * (count + 1)) / expected;
        if((y>=draw_rect.bottom) && (y<=draw_rect.top)) {
          MoviePrepareDrag(G,&draw_rect,NULL,mode,x,y,nearest);
          goto done;
        }
        count++;
      }
      break;
    case cExecObject:
      if(ObjectGetSpecLevel(rec->obj,0)>=0) {
        MoviePrepareDrag(G,rect,NULL,mode,x,y,nearest);
        draw_rect.top = rect->top - (height * count) / expected;
        draw_rect.bottom = rect->top - (height * (count + 1)) / expected;
        if((y>=draw_rect.bottom) && (y<=draw_rect.top)) {
          MoviePrepareDrag(G,&draw_rect,rec->obj,mode,x,y,nearest);
          goto done;
        }
        count++;
      }
      break;
    }
  }
 done:
  return;
}

int ExecutiveReference(PyMOLGlobals * G, int action, const char *sele, int state, int quiet)
{
  int result = -1;
  int s1 = SelectorIndexByName(G, sele);
  if(s1 >= 0) {
    ObjectMoleculeOpRec op;
    ObjectMoleculeOpRecInit(&op);

    switch (action) {
    case 1:
      op.code = OMOP_ReferenceStore;
      break;
    case 2:
      op.code = OMOP_ReferenceRecall;
      break;
    case 3:
      op.code = OMOP_ReferenceValidate;
      break;
    case 4:
      op.code = OMOP_ReferenceSwap;
      break;
    }
    op.i1 = state;
    op.i2 = 0;
    ExecutiveObjMolSeleOp(G, s1, &op);
    result = op.i2;
  }
  return result;
}

int ExecutiveIsosurfaceEtc(PyMOLGlobals * G,
                           const char *surf_name, const char *map_name, float lvl,
                           const char *sele, float fbuf, int state,
                           float carve, int map_state, int side,
                           int quiet, int surf_mode, int box_mode)
{
  int c;
  OrthoLineType s1;
  CObject *obj = NULL, *mObj, *origObj;
  ObjectMap *mapObj;
  float mn[3] = { 0, 0, 0 };
  float mx[3] = { 15, 15, 15 };
  float *vert_vla = NULL;
  int ok = true;
  ObjectMapState *ms;
  int multi = false;
  /* box_mode 0 = all, 1 = sele + buffer, 2 = vector, 3 = testing */

  /* (pattern) if old_name(origObj) exists, overwrite it */
  origObj = ExecutiveFindObjectByName(G, surf_name);
  if(origObj) {
    if(origObj->type != cObjectSurface) {
      ExecutiveDelete(G, surf_name);
      origObj = NULL;
    }
  }

  /* (pattern) if old_name(mObj) exists, overwrite it */
  mObj = ExecutiveFindObjectByName(G, map_name);
  if(mObj) {
    if(mObj->type != cObjectMap)
      mObj = NULL;
  }
  /* state finding for the map */
  if(mObj) {
    mapObj = (ObjectMap *) mObj;
    /* state handling */
    if(state == -1) {
      multi = true;
      state = 0;
      map_state = 0;
    } else if(state == -2) {    /* current state */
      state = SceneGetState(G);
      if(map_state < 0)
        map_state = state;
    } else if(state == -3) {    /* append mode */
      state = 0;
      if(origObj)
        if(origObj->fGetNFrame)
          state = origObj->fGetNFrame(origObj);
    } else {
      if(map_state == -1) {
        map_state = 0;
        multi = true;
      } else {
        multi = false;
      }
    }
    while(1) {
      if(map_state == -2)
        map_state = SceneGetState(G);
      if(map_state == -3)
        map_state = ObjectMapGetNStates(mapObj) - 1;
      ms = ObjectMapStateGetActive(mapObj, map_state);
      if(ms) {
        switch (box_mode) {
        case 0:                /* using map to get extents */
          for(c = 0; c < 3; c++) {
            mn[c] = ms->Corner[c];
            mx[c] = ms->Corner[3 * 7 + c];
          }
          if(ms->State.Matrix) {
            transform44d3f(ms->State.Matrix, mn, mn);
            transform44d3f(ms->State.Matrix, mx, mx);
            {
              float tmp;
              int a;
              for(a = 0; a < 3; a++)
                if(mn[a] > mx[a]) {
                  tmp = mn[a];
                  mn[a] = mx[a];
                  mx[a] = tmp;
                }
            }
          }
          carve = 0.0F;
          break;
        case 1:                /* using selection to get extents */
          ok = (SelectorGetTmp2(G, sele, s1) >= 0);
          ExecutiveGetExtent(G, s1, mn, mx, false, -1, false);  /* TODO state */
          if(carve != 0.0F) {
            vert_vla = ExecutiveGetVertexVLA(G, s1, state);
            if(fbuf <= R_SMALL4)
              fbuf = fabs(carve);
          }
          SelectorFreeTmp(G, s1);
          for(c = 0; c < 3; c++) {
            mn[c] -= fbuf;
            mx[c] += fbuf;
          }
          break;
        }
        PRINTFB(G, FB_CCmd, FB_Blather)
          " Isosurface: buffer %8.3f carve %8.3f\n", fbuf, carve ENDFB(G);
        obj =
          (CObject *) ObjectSurfaceFromBox(G, (ObjectSurface *) origObj, mapObj,
                                           map_state, state, mn, mx, lvl, surf_mode,
                                           carve, vert_vla, side, quiet);
        /* copy the map's TTT */
        ExecutiveMatrixCopy2(G, mObj, obj, 1, 1, -1, -1, false, 0, quiet);

        if(!origObj) {
          ObjectSetName(obj, surf_name);
          ExecutiveManageObject(G, (CObject *) obj, -1, quiet);
        }
        if(SettingGetGlobal_b(G, cSetting_isomesh_auto_state))
          if(obj)
            ObjectGotoState((ObjectMolecule *) obj, state);
        if(!quiet) {
          PRINTFB(G, FB_ObjectSurface, FB_Actions)
            " Isosurface: created \"%s\", setting level to %5.3f\n", surf_name, lvl
            ENDFB(G);
        }
      } else if(!multi) {
        PRINTFB(G, FB_ObjectMesh, FB_Warnings)
          " Isosurface-Warning: state %d not present in map \"%s\".\n", map_state + 1,
          map_name ENDFB(G);
        ok = false;
      }
      if(multi) {
        origObj = obj;
        map_state++;
        state++;
        if(map_state >= mapObj->NState)
          break;
      } else {
        break;
      }
    }
  } else {
    PRINTFB(G, FB_ObjectSurface, FB_Errors)
      " Isosurface: Map or brick object \"%s\" not found.\n", map_name ENDFB(G);
    ok = false;
  }
  return ok;
}

int ExecutiveIsomeshEtc(PyMOLGlobals * G,
                        const char *mesh_name, const char *map_name, float lvl,
                        const char *sele, float fbuf, int state,
                        float carve, int map_state, int quiet,
                        int mesh_mode, int box_mode, float alt_lvl)
{
  int ok = true;
  CObject *obj = NULL, *mObj, *origObj;
  ObjectMap *mapObj;
  float mn[3] = { 0, 0, 0 };
  float mx[3] = { 15, 15, 15 };
  float *vert_vla = NULL;
  int multi = false;
  ObjectMapState *ms;
  OrthoLineType s1;
  ObjectMolecule *sele_obj = NULL;
  CSymmetry *symm;

  /* (pattern) if old_name(origObj) exists, overwrite it */
  origObj = ExecutiveFindObjectByName(G, mesh_name);
  if(origObj) {
    if(origObj->type != cObjectMesh) {
      ExecutiveDelete(G, mesh_name);
      origObj = NULL;
    }
  }

  /* (pattern) if old_name(mObj) exists, overwrite it */
  mObj = ExecutiveFindObjectByName(G, map_name);
  if(mObj) {
    if(mObj->type != cObjectMap)
      mObj = NULL;
  }
  if(mObj) {
    mapObj = (ObjectMap *) mObj;
    /* state handling */
    if(state == -1) {
      multi = true;
      state = 0;
      map_state = 0;
    } else if(state == -2) {
      state = SceneGetState(G);
      if(map_state < 0)
        map_state = state;
    } else if(state == -3) {    /* append mode */
      state = 0;
      if(origObj)
        if(origObj->fGetNFrame)
          state = origObj->fGetNFrame(origObj);
    } else {
      if(map_state == -1) {
        map_state = 0;
        multi = true;
      } else {
        multi = false;
      }
    }
    while(1) {
      if(map_state == -2)
        map_state = SceneGetState(G);
      if(map_state == -3)
        map_state = ObjectMapGetNStates(mapObj) - 1;
      ms = ObjectMapStateGetActive(mapObj, map_state);
      if(ms) {
        switch (box_mode) {
        case 0:                /* do the whole map */
          {
            int c;
            for(c = 0; c < 3; c++) {
              mn[c] = ms->Corner[c];
              mx[c] = ms->Corner[3 * 7 + c];
            }
          }
          if(ms->State.Matrix) {
            transform44d3f(ms->State.Matrix, mn, mn);
            transform44d3f(ms->State.Matrix, mx, mx);
            {
              float tmp;
              int a;
              for(a = 0; a < 3; a++)
                if(mn[a] > mx[a]) {
                  tmp = mn[a];
                  mn[a] = mx[a];
                  mx[a] = tmp;
                }
            }
          }
          carve = -0.0;         /* impossible */
          break;
        case 1:                /* just do area around selection */
	  /* determine the selected object */
          ok = (SelectorGetTmp2(G, sele, s1) >= 0);
          if(ok) {
            int sele1 = SelectorIndexByName(G, s1);
            if(sele1 >= 0)
              sele_obj = SelectorGetSingleObjectMolecule(G, sele1);
          }

          ExecutiveGetExtent(G, s1, mn, mx, false, -1, false);  /* TODO state */
          if(carve != 0.0) {
            vert_vla = ExecutiveGetVertexVLA(G, s1, state);
            if(fbuf <= R_SMALL4)
              fbuf = fabs(carve);
          }
          SelectorFreeTmp(G, s1);
          {
            int c;
            for(c = 0; c < 3; c++) {
              mn[c] -= fbuf;
              mx[c] += fbuf;
            }
          }
          break;
        }
        PRINTFB(G, FB_CCmd, FB_Blather)
          " Isomesh: buffer %8.3f carve %8.3f \n", fbuf, carve ENDFB(G);

        symm = NULL;
        if(sele_obj &&  ObjectMapValidXtal(mapObj, state)) {
          if(SettingGet_b(G, NULL, sele_obj->Obj.Setting, cSetting_map_auto_expand_sym)
              && (sele_obj->Symmetry)) {
            // legacy default: take symmetry from molecular object
            symm = sele_obj->Symmetry;
          } else if(SettingGet_b(G, NULL, mapObj->Obj.Setting, cSetting_map_auto_expand_sym)) {
            // fallback: take symmetry from map state
            symm = ms->Symmetry;
          }
        }

        if(symm) {
          obj = (CObject *) ObjectMeshFromXtalSym(G, (ObjectMesh *) origObj, mapObj,
                                                  symm,
                                                  map_state, state, mn, mx, lvl,
                                                  mesh_mode, carve, vert_vla, alt_lvl,
                                                  quiet);
        } else {
          obj = NULL;
        }
        if(!obj) {
          obj = (CObject *) ObjectMeshFromBox(G, (ObjectMesh *) origObj, mapObj,
                                              map_state, state, mn, mx, lvl, mesh_mode,
                                              carve, vert_vla, alt_lvl, quiet);
        }
        /* copy the map's TTT */
        ExecutiveMatrixCopy2(G, mObj, obj, 1, 1, -1, -1, false, 0, quiet);

        if(!origObj) {
          ObjectSetName(obj, mesh_name);
          ExecutiveManageObject(G, (CObject *) obj, false, quiet);
        }

        if(SettingGetGlobal_b(G, cSetting_isomesh_auto_state))
          if(obj)
            ObjectGotoState((ObjectMolecule *) obj, state);
        if(!quiet) {
          if(mesh_mode != 3) {
            PRINTFB(G, FB_ObjectMesh, FB_Actions)
              " Isomesh: created \"%s\", setting level to %5.3f\n", mesh_name, lvl
              ENDFB(G);
          } else {
            PRINTFB(G, FB_ObjectMesh, FB_Actions)
              " Gradient: created \"%s\"\n", mesh_name ENDFB(G);
          }
        }
      } else if(!multi) {
        PRINTFB(G, FB_ObjectMesh, FB_Warnings)
          " Isomesh-Warning: state %d not present in map \"%s\".\n", map_state + 1,
          map_name ENDFB(G);
        ok = false;
      }
      if(multi) {
        origObj = obj;
        map_state++;
        state++;
        if(map_state >= mapObj->NState)
          break;
      } else {
        break;
      }
    }
  } else {
    PRINTFB(G, FB_ObjectMesh, FB_Errors)
      " Isomesh: Map or brick object \"%s\" not found.\n", map_name ENDFB(G);
    ok = false;
  }
  return ok;
}


int ExecutiveVolumeColor(PyMOLGlobals * G, const char * volume_name, float * colors, int ncolors) {
 
  int ok = true;
#if 0 
  CObject * origObj = NULL;
  
  origObj = ExecutiveFindObjectByName(G, volume_name);
  if(origObj) {
    if(origObj->type != cObjectVolume) {
      ExecutiveDelete(G, volume_name);
      origObj = NULL;
    }
  }

  if(origObj) {
    ok = ObjectVolumeColor((ObjectVolume*) origObj, colors, ncolors);
  } else {
    PRINTFB(G, FB_ObjectVolume, FB_Errors)
      " Volume: volume object \"%s\" not found.\n", volume_name ENDFB(G);
    ok = false;
  }

#endif
  return ok;
}


int ExecutiveVolume(PyMOLGlobals * G, const char *volume_name, const char *map_name,
                        float lvl,
                        const char *sele, float fbuf, int state,
                        float carve, int map_state, int quiet,
                        int mesh_mode, int box_mode, float alt_lvl)
{
  int ok = true;
  CObject *obj = NULL, *mObj, *origObj;
  ObjectMap *mapObj;
  float mn[3] = { 0, 0, 0 };
  float mx[3] = { 15, 15, 15 };
  float *vert_vla = NULL;
  int multi = false;
  ObjectMapState *ms;
  OrthoLineType s1;
  ObjectMolecule *sele_obj = NULL;
  CSymmetry *symm;

  /* Goal: make a new volume map from the object or selection
   *
   * If the user specifies an VOLUME OBJECT NAME that already exists, then
   * check to make sure it's a volume.  If it is, keep it, else delete it
   * 
   * If the user specifies a MAP OBJECT NAME that already exists, then
   * make sure it's really a map.  Keep it if it is (to append the state)
   * otherwise, delete it.
   *
   * Given that the MAP is valid, find the current states for the MAP object
   * and the scene/protein.
   *
   * If the user is loading a map with N-states, into an N-state object, we need
   * to loop over each state.  So,
   *
   * FOR EACH state in the MAP:
   *   - determine the extents of the MAP for THIS STATE
   *
   *   - create the VOLUME object from the MAP/XTAL SYMM
   *   - if VOLUME CREATION didn't work, then try creating from a BOX
   *
   *   - transform (translate/rotate) the VOLUME vis so that it
   *     matches the map's ObjectMatrix.
   *
   *   - if this is a new VOLUME, (eg., origObj==NULL) then set the internal
   *     PyMOL state to manage the object and add the name to the object list
   *
   *   - update the map state for the next loop and re-iterate
   */

  /* check for synonymous volume */
  origObj = ExecutiveFindObjectByName(G, volume_name);
  if(origObj) {
    if(origObj->type != cObjectVolume) {
      ExecutiveDelete(G, volume_name);
      origObj = NULL;
    }
  }
  /* find the map for this volume */
  mObj = ExecutiveFindObjectByName(G, map_name);
  if(mObj) {
    if(mObj->type != cObjectMap)
      mObj = NULL;
  }

  if(mObj) {
    mapObj = (ObjectMap *) mObj;
    /* BEGIN state finding */
    if(state == -1) {
      multi = true;
      state = 0;
      map_state = 0;
    } else if(state == -2) {
      state = SceneGetState(G);
      if(map_state < 0)
        map_state = state;
    } else if(state == -3) {    /* append mode */
      state = 0;
      if(origObj)
        if(origObj->fGetNFrame)
          state = origObj->fGetNFrame(origObj);
    } else {
      if(map_state == -1) {
        map_state = 0;
        multi = true;
      } else {
        multi = false;
      }
      /* END state finding */
    }
    /* do for each state */
    while(1) {
      if(map_state == -2)
        map_state = SceneGetState(G);
      if(map_state == -3)
        map_state = ObjectMapGetNStates(mapObj) - 1;
      ms = ObjectMapStateGetActive(mapObj, map_state);
      if(ms) {
	/* determine extents */
        switch (box_mode) {
        case 0:                /* do the whole map */
          {
            int c;
            for(c = 0; c < 3; c++) {
              mn[c] = ms->Corner[c];
              mx[c] = ms->Corner[3 * 7 + c];
            }
          }
          if(ms->State.Matrix) {
            transform44d3f(ms->State.Matrix, mn, mn);
            transform44d3f(ms->State.Matrix, mx, mx);
            {
              float tmp;
              int a;
              for(a = 0; a < 3; a++)
                if(mn[a] > mx[a]) {
                  tmp = mn[a];
                  mn[a] = mx[a];
                  mx[a] = tmp;
                }
            }
          }
          carve = -0.0;         /* impossible */
          break;
        case 1:                /* just do area around selection */
          ok = (SelectorGetTmp2(G, sele, s1) >= 0);
          if(ok) {
            int sele1 = SelectorIndexByName(G, s1);
            if(sele1 >= 0)
              sele_obj = SelectorGetSingleObjectMolecule(G, sele1);
          }

          ExecutiveGetExtent(G, s1, mn, mx, false, -1, false);  /* TODO state */
          if(carve != 0.0) {
            vert_vla = ExecutiveGetVertexVLA(G, s1, state);
            if(fbuf <= R_SMALL4)
              fbuf = fabs(carve);
          }
          SelectorFreeTmp(G, s1);
          {
            int c;
            for(c = 0; c < 3; c++) {
              mn[c] -= fbuf;
              mx[c] += fbuf;
            }
          }
          break;
        }
        PRINTFB(G, FB_CCmd, FB_Blather)
          " Volume: buffer %8.3f carve %8.3f \n", fbuf, carve ENDFB(G);

        symm = NULL;
        if(sele_obj && ObjectMapValidXtal(mapObj, state)) {
          if(SettingGet_b(G, NULL, sele_obj->Obj.Setting, cSetting_map_auto_expand_sym)
              && (sele_obj->Symmetry)) {
            // legacy default: take symmetry from molecular object
            symm = sele_obj->Symmetry;
          } else if(SettingGet_b(G, NULL, mapObj->Obj.Setting, cSetting_map_auto_expand_sym)) {
            // fallback: take symmetry from map state
            symm = ms->Symmetry;
          }
        }

        if(symm) {
          obj = (CObject *) ObjectVolumeFromXtalSym(G, (ObjectVolume *) origObj, mapObj,
                                                  symm,
                                                  map_state, state, mn, mx, lvl,
                                                  box_mode, carve, vert_vla, alt_lvl,
                                                  quiet);
        } else {
          obj = NULL;
        }

        if(!obj) {
          obj = (CObject *) ObjectVolumeFromBox(G, (ObjectVolume *) origObj, mapObj,
                                              map_state, state, mn, mx, lvl, box_mode,
                                              carve, vert_vla, alt_lvl, quiet);
        }
        /* copy the map's TTT */
        ExecutiveMatrixCopy2(G, mObj, obj, 1, 1, -1, -1, false, 0, quiet);
	/* set the object name
	 * manage the object in the UI */
        if(!origObj) {
          ObjectSetName(obj, volume_name);
          ExecutiveManageObject(G, (CObject *) obj, false, quiet);
        }

        if(SettingGetGlobal_b(G, cSetting_isomesh_auto_state))
          if(obj)
            ObjectGotoState((ObjectMolecule *) obj, state);
        if(!quiet) {
	  PRINTFB(G, FB_ObjectVolume, FB_Actions)
	    " Volume: created \"%s\"\n", volume_name
	    ENDFB(G);
        }
      } else if(!multi) {
        PRINTFB(G, FB_ObjectVolume, FB_Warnings)
          " Volume-Warning: state %d not present in map \"%s\".\n", map_state + 1,
          map_name ENDFB(G);
        ok = false;
      }
      if(multi) {
        origObj = obj;
        map_state++;
        state++;
        if(map_state >= mapObj->NState)
          break;
      } else {
        break;
      }
    }
  } else {
    PRINTFB(G, FB_ObjectVolume, FB_Errors)
      " Volume: Map or brick object \"%s\" not found.\n", map_name ENDFB(G);
    ok = false;
  }
  return ok;
}

int ExecutivePseudoatom(PyMOLGlobals * G, const char *object_name, const char *sele,
                        const char *name, const char *resn, const char *resi, const char *chain,
                        const char *segi, const char *elem, float vdw, int hetatm,
                        float b, float q, const char *label, float *pos, int color,
                        int state, int mode, int quiet)
{
  int ok = true;

  ObjectMolecule *obj = NULL;
  ObjectNameType object_name_buf;

  if (!object_name[0]) {
    strcpy(object_name_buf, "pseudo");
    ExecutiveMakeUnusedName(G, object_name_buf, sizeof(ObjectNameType));
    object_name = object_name_buf;
  } else {
    obj = ExecutiveFindObjectMoleculeByName(G, object_name);
  }

  int is_new = false;
  int sele_index = -1;
  float local_pos[3];

  if(sele && sele[0]) {
    if(WordMatchExact(G, cKeywordCenter, sele, true)) {
      sele = NULL;
      SceneGetCenter(G, local_pos);
      pos = local_pos;
    } else if(WordMatchExact(G, cKeywordOrigin, sele, true)) {
      sele = NULL;
      SceneOriginGet(G, local_pos);
      pos = local_pos;
    }
  }

  if(sele && sele[0]) {
    sele_index = SelectorIndexByName(G, sele);
    if(sele_index < 0) {
      ok = false;
      PRINTFB(G, FB_Executive, FB_Errors)
        " Pseudoatom-Error: invalid selection\n" ENDFB(G);
    }
  }
  if(ok) {
    if(!obj) {
      /* new object */
      is_new = true;
      obj = ObjectMoleculeNew(G, false);
      ObjectSetName(&obj->Obj, object_name);
      if(!obj)
        ok = false;
    }
  }

  if(ok) {
    if(ObjectMoleculeAddPseudoatom(obj, sele_index, name, resn, resi, chain,
                                   segi, elem, vdw, hetatm, b, q, label, pos, color,
                                   state, mode, quiet)) {
      if(is_new) {
        ExecutiveDelete(G, object_name);        /* just in case */
        ExecutiveManageObject(G, &obj->Obj, false, true);
      } else {
        ExecutiveUpdateObjectSelection(G, &obj->Obj);
      }
    }
  }
  return ok;
}

static void ExecutiveInvalidateGridSlots(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  I->ValidGridSlots = false;
}

static void ExecutiveSetGridSlot(SpecRec *rec, int new_grid_slot){
  if (rec->grid_slot != new_grid_slot){
    CGOFree(rec->gridSlotSelIndicatorsCGO);
    rec->gridSlotSelIndicatorsCGO = NULL;
    rec->grid_slot = new_grid_slot;
  }
}
static void ExecutiveUpdateGridSlots(PyMOLGlobals * G, int force)
{
  CExecutive *I = G->Executive;
  int grid_slot_count = 0;
  int grid_by_group = 1;        /* grid slots are inherited this many levels */

  ExecutiveUpdateGroups(G, false);
  if(force || (!I->ValidGridSlots)) {
    CTracker *I_Tracker = I->Tracker;
    I->ValidGridSlots = true;
    {
      SpecRec *rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
	ExecutiveSetGridSlot(rec, 0);
        if(rec->type == cExecObject) {
          /* make sure every object (potentially) needing a grid slot gets one */
          switch (rec->obj->type) {
          case cObjectMolecule:
          case cObjectMap:
          case cObjectMesh:
          case cObjectMeasurement:
          case cObjectCallback:
          case cObjectCGO:
          case cObjectSurface:
          case cObjectSlice:
          case cObjectGadget:
          case cObjectGroup:
          case cObjectVolume:
	    ExecutiveSetGridSlot(rec, ++grid_slot_count);
            break;
          }
        }
      }
    }

    if(grid_by_group) {
      SpecRec *rec = NULL, *group_rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        OVreturn_word result;
        if(OVreturn_IS_OK
           ((result = OVLexicon_BorrowFromCString(I->Lex, rec->group_name)))) {
          if(OVreturn_IS_OK((result = OVOneToOne_GetForward(I->Key, result.word)))) {
            if(TrackerGetCandRef(I_Tracker, result.word,
                                 (TrackerRef **) (void *) &group_rec)) {
              int grid_slot_group_depth = grid_by_group;
              {
                SpecRec *check_rec = group_rec;
                while(check_rec && grid_slot_group_depth) {
                  if(grid_slot_group_depth == 1)
		    ExecutiveSetGridSlot(rec, check_rec->grid_slot);
                  if(check_rec == rec) {        /* cycle */
                    break;
                  } else {
                    check_rec = check_rec->group;
                    grid_slot_group_depth--;
                  }
                }
              }
            }
          }
        }
      }
    }

    {
      SpecRec *rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        if(rec->type == cExecObject) {
          int obj_slot = SettingGet_i(G, rec->obj->Setting, NULL, cSetting_grid_slot);
          if(obj_slot == -1) {
            rec->obj->grid_slot = rec->grid_slot;
          } else
            rec->obj->grid_slot = obj_slot;
        }
      }
    }
  }
}

static void ExecutiveInvalidatePanelList(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  if(I->ValidPanel) {
    if(I->Panel)
      ListFree(I->Panel, next, PanelRec);
    I->ValidPanel = false;
  }
  ExecutiveInvalidateGridSlots(G);
}

static PanelRec *PanelListGroup(PyMOLGlobals * G, PanelRec * panel, SpecRec * group,
                                int level, int hide_underscore)
{
  CExecutive *I = G->Executive;
  PanelRec *result = NULL;
  SpecRec *rec = NULL;
  /* set up recursion prevention */
  if(level == 0)
  while(ListIterate(I->Spec, rec, next)) {
    rec->in_panel = false;
  }
  while(ListIterate(I->Spec, rec, next)) {      /* add all members which belong to this group */

    if((rec->name[0] != '_') || (!hide_underscore)) {   /* not hidden */
      if((rec->group == group) && (!rec->in_panel)) {
        int group_name_len = strlen(rec->group_name);
        if((!hide_underscore)
           || !((strncmp(rec->name, rec->group_name, group_name_len) == 0) &&
                /* named with proper group prefix */
                (rec->name[group_name_len] == '.')
                && (rec->name[group_name_len + 1] == '_'))) {
          /* and not hidden inside group */

          PanelRec *new_panel = NULL;
          ListElemCalloc(G, new_panel, PanelRec);
          if(panel)
            panel->next = new_panel;
          else
            result = new_panel;
          panel = new_panel;
          panel->spec = rec;
          panel->nest_level = level;
          if(!level)
            rec->group_name[0] = 0;     /* force open any cycles which have been created... */
          rec->in_panel = true;
          if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
            ObjectGroup *obj_group = (ObjectGroup *) rec->obj;
            panel->is_group = true;
            if(obj_group->OpenOrClosed) {
              panel->is_open = true;
              panel = PanelListGroup(G, panel, rec, level + 1, hide_underscore);
            }
          }
        }
      }
    }
  }
  if(!result)
    result = panel;
  return result;
}

static void ExecutiveUpdatePanelList(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
  if(!I->ValidPanel) {
    /* brute-force & inefficient -- need to optimize algorithm */
    I->Panel = PanelListGroup(G, NULL, NULL, 0, hide_underscore);
    I->ValidPanel = true;
  }
}

static void ExecutiveInvalidateSceneMembers(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  I->ValidSceneMembers = false;
}

static void ExecutiveUpdateSceneMembers(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  ExecutiveUpdateGroups(G, false);
  ExecutiveUpdateGridSlots(G, false);
  if(!I->ValidSceneMembers) {
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        int visible = rec->visible;
        SpecRec *group_rec = rec->group;
        while(visible && group_rec) {   /* visibility is a group issue... */
          if(!group_rec->visible)
            visible = false;
          else
            group_rec = group_rec->group;
        }
        if(rec->in_scene && !visible) {
          rec->in_scene = SceneObjectDel(G, rec->obj, true);
        } else if(visible && !rec->in_scene) {
          rec->in_scene = SceneObjectAdd(G, rec->obj);
        }
      }
    }
    I->ValidSceneMembers = true;
  }
}

void ExecutiveInvalidateGroups(PyMOLGlobals * G, int force)
{
  CExecutive *I = G->Executive;
  if(force || I->ValidGroups) {
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      rec->group = NULL;
      if(rec->type == cExecObject)
        if(rec->obj->type == cObjectGroup) {
          int list_id = rec->group_member_list_id;
          if(list_id)
            TrackerDelList(I_Tracker, rec->group_member_list_id);
          rec->group_member_list_id = 0;        /* not a list */
        }
    }
    I->ValidGroups = false;
    ExecutiveInvalidateSceneMembers(G);
    ExecutiveInvalidatePanelList(G);
  }
  /* any changes to group structure means that we need to check scene
     members */
}

void ExecutiveUpdateGroups(PyMOLGlobals * G, int force)
{
  CExecutive *I = G->Executive;

  if(force || (!I->ValidGroups)) {
    CTracker *I_Tracker = I->Tracker;

    /* first, get rid of existing group lists */

    if(force || I->ValidGroups)
      ExecutiveInvalidateGroups(G, true);

    /* create empty lists for each group (also init grid_slot) */

    {
      SpecRec *rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        rec->group = NULL;
        if(rec->type == cExecObject) {
          if(rec->obj->type == cObjectGroup) {
            rec->group_member_list_id = TrackerNewList(I_Tracker, NULL);
          }
        }
      }
    }

    /* iterate through and populate groups lists with their members */

    {
      SpecRec *rec = NULL, *group_rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        OVreturn_word result;
        if(OVreturn_IS_OK
           ((result = OVLexicon_BorrowFromCString(I->Lex, rec->group_name)))) {
          if(OVreturn_IS_OK((result = OVOneToOne_GetForward(I->Key, result.word)))) {
            if(TrackerGetCandRef(I_Tracker, result.word,
                                 (TrackerRef **) (void *) &group_rec)) {
              int cycle = false;
              {                 /* don't close infinite loops */
                SpecRec *check_rec = group_rec;
                while(check_rec) {
                  if(check_rec == rec) {
                    cycle = true;
                    break;
                  } else {
                    check_rec = check_rec->group;
                  }
                }
              }
              if(!cycle) {
                rec->group = group_rec;
                TrackerLink(I_Tracker, rec->cand_id, group_rec->group_member_list_id, 1);
              }
            }
          }
        }
      }
    }

    {
      int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
      if(hide_underscore) {
        SpecRec *rec = NULL;
        while(ListIterate(I->Spec, rec, next)) {
          rec->is_hidden = false;
          if(rec->name[0] == '_')
            rec->is_hidden = true;
          else if(rec->group) {
            int group_name_len = strlen(rec->group_name);
            if(rec->group->is_hidden)
              rec->is_hidden = true;
            else if((strncmp(rec->name, rec->group_name, group_name_len) == 0) &&
                    (rec->name[group_name_len] == '.') &&
                    (rec->name[group_name_len + 1] == '_'))
              rec->is_hidden = true;
          }
        }
        {                       /* sub-optimal propagation of hidden status to group members */
          int repeat_flag = true;
          while(repeat_flag) {
            repeat_flag = false;
            while(ListIterate(I->Spec, rec, next)) {
              if(rec->group && (!rec->is_hidden)) {
                if(rec->group->is_hidden) {
                  rec->is_hidden = true;
                  repeat_flag = true;
                }
              }
            }
          }
        }
      }
    }

    /* note that it is possible to have infinite loops -- these must be
       allowed for later in the group expansion routine(s) */
    I->ValidGroups = true;
    ExecutiveInvalidatePanelList(G);
  }
}

static int ExecutiveGetObjectParentList(PyMOLGlobals * G, SpecRec * child)
{
  int list_id = 0;
  ExecutiveUpdateGroups(G, false);
  {
    CExecutive *I = G->Executive;
    CTracker *I_Tracker = I->Tracker;
    int priority = 1;           /* generations removed from child */
    int repeat_flag = true;
    SpecRec *group_rec = NULL;

    list_id = TrackerNewList(I_Tracker, NULL);
    while(child && child->group && repeat_flag) {
      OVreturn_word result;
      repeat_flag = false;
      if(OVreturn_IS_OK
         ((result = OVLexicon_BorrowFromCString(I->Lex, child->group_name)))) {
        if(OVreturn_IS_OK((result = OVOneToOne_GetForward(I->Key, result.word)))) {
          if(TrackerGetCandRef(I_Tracker, result.word,
                               (TrackerRef **) (void *) &group_rec)) {
            if(TrackerLink(I_Tracker, result.word, list_id, priority++)) {
              /* checking this prevents infinite loops */
              if(group_rec->group) {
                repeat_flag = true;
                child = group_rec;
              }
            }
          }
        }
      }
    }
  }
  return list_id;
}

int ExecutiveVdwFit(PyMOLGlobals * G, const char *s1, int state1, const char *s2, int state2,
                    float buffer, int quiet)
{
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  int sele1 = tmpsele1.getIndex();
  int sele2 = tmpsele2.getIndex();

  int ok = true;

  if((sele1 >= 0) && (sele2 >= 0)) {
    ok = SelectorVdwFit(G, sele1, state1, sele2, state2, buffer, quiet);
  } else {
    ok = false;
  }
  return ok;
}

static int get_op_cnt(PyMOLGlobals * G)
{
  int result = 5;
  if(!strcmp(SettingGetGlobal_s(G, cSetting_button_mode_name), "3-Button Motions"))
    result = 6;
  return result;
}

static int ExecutiveAddKey(CExecutive * I, SpecRec * rec)
{
  int ok = false;
  OVreturn_word result;
  if(OVreturn_IS_OK((result = OVLexicon_GetFromCString(I->Lex, rec->name)))) {
    if(OVreturn_IS_OK(OVOneToOne_Set(I->Key, result.word, rec->cand_id))) {
      ok = true;
    }
  }
  return ok;
}

static int ExecutiveDelKey(CExecutive * I, SpecRec * rec)
{
  int ok = false;
  OVreturn_word result;
  if(OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, rec->name)))) {
    if(OVreturn_IS_OK(OVLexicon_DecRef(I->Lex, result.word)) &&
       OVreturn_IS_OK(OVOneToOne_DelForward(I->Key, result.word))) {
      ok = true;
    }
  }
  return ok;
}

static SpecRec *ExecutiveUnambiguousNameMatch(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  SpecRec *result = NULL;
  SpecRec *rec = NULL;
  int best = 0;
  int wm;
  int ignore_case = SettingGetGlobal_b(G, cSetting_ignore_case);

  while(ListIterate(I->Spec, rec, next)) {
    wm = WordMatch(G, name, rec->name, ignore_case);
    if(wm < 0) {                /* exact match, so this is valid */
      result = rec;
      best = wm;
      break;
    } else if((wm > 0) && (best < wm)) {
      result = rec;
      best = wm;
    } else if((wm > 0) && (best == wm)) {       /* ambiguous match... no good */
      result = NULL;
    }
  }
  return (result);
}

static SpecRec *ExecutiveAnyCaseNameMatch(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  SpecRec *result = NULL;
  SpecRec *rec = NULL;

  int ignore_case = SettingGetGlobal_b(G, cSetting_ignore_case);
  while(ListIterate(I->Spec, rec, next)) {
    if(WordMatchExact(G, name, rec->name, ignore_case)) {
      result = rec;
      break;
    }
  }
  return (result);
}

/*
 * Scroll the i'th match in the object menu panel to the top.
 * Scroll to last match if i < 0 and to first match if i > #-1.
 * Open groups if hit is inside.
 * Highlight the hit (same as mouse click highlight).
 *
 * Returns the number of hits
 */
int ExecutiveScrollTo(PyMOLGlobals * G, const char * name, int i) {
  CExecutive *I = G->Executive;
  PanelRec *panel = NULL;
  int pos = 0, numhits = 0;
  ObjectGroup *group;
  SpecRec *tmp, *spec = NULL, *first = NULL;
  int ignore_case = SettingGetGlobal_b(G, cSetting_ignore_case);
  int j, lendiff, plen = strlen(name);

  ok_assert(1, I->Spec);

  // i'th substring match, skip the "all" item
  for(tmp = I->Spec->next; tmp; tmp = tmp->next) {
    lendiff = strlen(tmp->name) - plen;
    for(j = 0; j <= lendiff; j++)
      if(WordMatchNoWild(G, name, tmp->name + j, ignore_case)) {
        if(numhits++ == i || i < 0)
          spec = tmp;
        if(!first)
          first = tmp;
        break;
      }
    tmp->hilight = 0;
  }

  // if i was out of range
  if(!spec)
    spec = first;

  ok_assert(1, spec);

  // flash button until panel is clicked for the next time
  spec->hilight = 1;

  // open parent groups
  for(tmp = spec->group; tmp; tmp = tmp->group) {
    if(!(tmp->type == cExecObject &&
         tmp->obj->type == cObjectGroup))
      break;
    group = (ObjectGroup *) tmp->obj;
    if(!group->OpenOrClosed) {
      group->OpenOrClosed = 1;
      ExecutiveInvalidatePanelList(G);
    }
  }

  // in case any parent got opened
  ExecutiveUpdatePanelList(G);

  // scroll that record to the top
  while(ListIterate(I->Panel, panel, next)) {
    if(panel->spec == spec) {
      ScrollBarSetValueNoCheck(I->ScrollBar, pos);
      return numhits;
    }
    pos++;
  }

ok_except1:
  return numhits;
}

void ExecutiveUpdateColorDepends(PyMOLGlobals * G, ObjectMolecule * mol)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;

  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      if(rec->obj->type == cObjectGadget) {
        ObjectGadget *gadget = (ObjectGadget *) rec->obj;
        if(gadget->GadgetType == cGadgetRamp) {
          ObjectGadgetRamp *ramp = (ObjectGadgetRamp *) gadget;
          if(ramp->RampType == cRampMol) {
            if(ramp->Mol == mol) {
              ExecutiveInvalidateRep(G, cKeywordAll, cRepAll, cRepInvColor);
              break;
            }
          }
        }
      }
    }
  }
}

void ExecutiveUpdateCoordDepends(PyMOLGlobals * G, ObjectMolecule * mol)
{                               /* nasty, ugly, inefficient hack */

  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectGadget *gadget;
  int done_inv_all = false;
  int dynamic_measures = SettingGet_b(G, mol ? mol->Obj.Setting : NULL, NULL,
      cSetting_dynamic_measures);

  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      switch(rec->obj->type) {
      case cObjectGadget:
        if(done_inv_all)
          break;
        gadget = (ObjectGadget *) rec->obj;
        if(gadget->GadgetType == cGadgetRamp) {
          ObjectGadgetRamp *ramp = (ObjectGadgetRamp *) gadget;
          if(ramp->RampType == cRampMol) {
            if(ramp->Mol == mol) {
              ExecutiveInvalidateRep(G, cKeywordAll, cRepAll, cRepInvColor);
              done_inv_all = true;
            }
          }
        }
        break;
      case cObjectMeasurement:
        if(dynamic_measures)
          ObjectDistMoveWithObject((ObjectDist*) rec->obj, mol);
        break;
      }
    }
  }
}

int ExecutiveValidNamePattern(PyMOLGlobals * G, const char *name)
{
  int result = false;
  CWordMatcher *matcher;
  CWordMatchOptions options;
  const char *wildcard = SettingGetGlobal_s(G, cSetting_wildcard);

  WordMatchOptionsConfigNameList(&options,
                                 *wildcard, SettingGetGlobal_b(G, cSetting_ignore_case));
  matcher = WordMatcherNew(G, name, &options, false);
  if(matcher) {                 /* this appears to be a pattern */
    result = true;
    WordMatcherFree(matcher);
  } else if(ExecutiveUnambiguousNameMatch(G, name)) {
    /* this does not appear to be a pattern, so it is an unambiguous partial name? */
    result = true;
  }
  return result;

}

#define cExecNoExpand false
#define cExecExpandGroups true
#define cExecExpandKeepGroups 2

static void ExecutiveExpandGroupsInList(PyMOLGlobals * G, int list_id, int expand_groups)
{
  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  int new_member_added = true;
  SpecRec *rec;
  ExecutiveUpdateGroups(G, false);
  while(new_member_added) {     /* keep adding til we can't add no more */
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    int cand_id;
    new_member_added = false;
    if(iter_id) {
      while((cand_id = TrackerIterNextCandInList(I_Tracker, iter_id,
                                                 (TrackerRef **) (void *) &rec))) {
        if(rec && (rec->type == cExecObject) &&
           rec->group_member_list_id && (rec->obj->type == cObjectGroup)) {
          int group_iter_id = TrackerNewIter(I_Tracker, 0, rec->group_member_list_id);
          int group_cand_id;
          SpecRec *group_rec;
          if(group_iter_id) {
            while((group_cand_id = TrackerIterNextCandInList(I_Tracker, group_iter_id,
                                                             (TrackerRef **) (void *)
                                                             &group_rec))) {
              if(group_rec && group_cand_id) {
                if(TrackerLink(I_Tracker, group_cand_id, list_id, 1))
                  new_member_added = true;
              }
            }
            TrackerDelIter(I_Tracker, group_iter_id);
          }
        }
      }
      TrackerDelIter(I_Tracker, iter_id);
    }
  }
  /* now purge all groups from the expanded list */
  if(expand_groups != cExecExpandKeepGroups) {
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    int cand_id;
    while((cand_id = TrackerIterNextCandInList(I_Tracker, iter_id,
                                               (TrackerRef **) (void *) &rec))) {
      if(rec && (rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
        TrackerUnlink(I_Tracker, cand_id, list_id);
      }
    }
  }
}


/* DON'T FORGET TO RELEASE LIST WHEN DONE!!! */
static int ExecutiveGetNamesListFromPattern(PyMOLGlobals * G, const char *name,
                                            int allow_partial, int expand_groups)
{
  CExecutive *I = G->Executive;
  int result = 0;
  CWordMatcher *matcher;
  CWordMatchOptions options;
  CTracker *I_Tracker = I->Tracker;
  const char *wildcard = SettingGetGlobal_s(G, cSetting_wildcard);
  int iter_id = TrackerNewIter(I_Tracker, 0, I->all_names_list_id);
  int cand_id;
  int group_found = false;
  SpecRec *rec;

  if (!name)
    return -1;

  // sanity check: name patterns are not object selections, bail if
  // parenthesis or operators in pattern
  if (strchr(name, '(') || strchr(name, ')') || strchr(name, '|')) {
    PRINTFB(G, FB_Executive, FB_Errors)
      " Names-Pattern-Error: Pattern looks like an atom selection"
      " (has parenthesis or operators), this is not supported for"
      " object name patterns.\n" ENDFB(G);
    return -1;
  }

  // special case: allow "not ..."
  bool match_not = false;
  if (WordMatchNoWild(G, "not ", name, false)) {
    match_not = true;
    name += 4;
  } else if (name[0] == '!') {
    match_not = true;
    name += 1;
  }

  // skip whitespace
  while (name[0] == ' ') {
    ++name;
  }

  bool match_enabled = WordMatchExact(G, "enabled", name, false);

  // ignore % and ? prefixes
  while(name[0] && (name[0] == '%' || name[0] == '?'))
    name++;

  WordMatchOptionsConfigNameList(&options,
                                 *wildcard, SettingGetGlobal_b(G, cSetting_ignore_case));
  matcher = WordMatcherNew(G, name, &options, /* force= */ match_not);
  if(matcher || match_enabled) {
    if(iter_id) {
      while((cand_id = TrackerIterNextCandInList(I_Tracker, iter_id,
                                                 (TrackerRef **) (void *) &rec))) {
        if(rec && !(rec->type == cExecAll)) {
          bool test = match_enabled ? SpecRecIsEnabled(rec) :
            WordMatcherMatchAlpha(matcher, rec->name);
          if(test ^ match_not) {
            if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup))
              group_found = true;
            if(!result)
              result = TrackerNewList(I_Tracker, NULL);
            if(result) {
              TrackerLink(I_Tracker, cand_id, result, 1);
            }
          }
        }
      }
    }
  } else if((rec = ExecutiveFindSpec(G, name))) {       /* only one name in list */
    if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup))
      group_found = true;
    result = TrackerNewList(I_Tracker, NULL);
    TrackerLink(I_Tracker, rec->cand_id, result, 1);
  } else if(allow_partial && (rec = ExecutiveUnambiguousNameMatch(G, name))) {
    if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup))
      group_found = true;
    result = TrackerNewList(I_Tracker, NULL);
    TrackerLink(I_Tracker, rec->cand_id, result, 1);
  }
  if(matcher)
    WordMatcherFree(matcher);
  if(iter_id)
    TrackerDelIter(I->Tracker, iter_id);
  if(group_found && expand_groups) {
    ExecutiveExpandGroupsInList(G, result, expand_groups);
  }
  return result;
}

int ExecutiveGroup(PyMOLGlobals * G, const char *name, const char *members, int action, int quiet)
{
  int ok = true;
  CExecutive *I = G->Executive;

  ObjectNameType valid_name;
  UtilNCopy(valid_name, name, sizeof(ObjectNameType));
  ObjectMakeValidName(G, valid_name);

  CObject *obj = ExecutiveFindObjectByName(G, valid_name);

  if(obj && (obj->type != cObjectGroup)) {
    if((action != 7) || (members[0])) {
      PRINTFB(G, FB_Executive, FB_Errors)
        " Group-Error: object '%s' is not a group object.", name ENDFB(G);
      ok = false;
    }
  } else {
    if((!obj) && (action == cExecutiveGroupAdd)) {
      obj = (CObject *) ObjectGroupNew(G);
      if(obj) {
        ObjectSetName(obj, valid_name);
        ExecutiveManageObject(G, obj, false, true);
      }
    }
  }
  if((!members[0]) && ((action == cExecutiveGroupOpen) ||
                       (action == cExecutiveGroupClose) ||
                       (action == cExecutiveGroupUngroup) ||
                       (action == cExecutiveGroupToggle) ||
                       (action == cExecutiveGroupEmpty) ||
                       (action == cExecutiveGroupPurge) ||
                       (action == cExecutiveGroupExcise))) {
    ExecutiveUpdateGroups(G, false);
    {
      CTracker *I_Tracker = I->Tracker;
      int list_id = ExecutiveGetNamesListFromPattern(G, name, true, false);
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
      SpecRec *rec;

      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          ObjectGroup *objGroup = NULL;
          if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
            objGroup = (ObjectGroup *) rec->obj;
          }

          switch (action) {
          case cExecutiveGroupUngroup:
            rec->group_name[0] = 0;
            break;
          case cExecutiveGroupOpen:
            if(objGroup)
              objGroup->OpenOrClosed = 1;
            break;
          case cExecutiveGroupClose:
            if(objGroup)
              objGroup->OpenOrClosed = 0;
            break;
          case cExecutiveGroupToggle:
            if(objGroup)
              objGroup->OpenOrClosed = !objGroup->OpenOrClosed;
            break;
          case cExecutiveGroupEmpty:
            if(objGroup) {
              SpecRec *rec2 = NULL;
              while(ListIterate(I->Spec, rec2, next)) {
                if((rec2->group == rec)
                   || WordMatchExact(G, rec2->group_name, rec->name, true)) {
                  rec2->group = NULL;
                  rec2->group_name[0] = 0;
                }
              }
            }
            break;
          case cExecutiveGroupPurge:
            if(objGroup) {
              SpecRec *rec2 = NULL;
              while(ListIterate(I->Spec, rec2, next)) {
                if((rec2->group == rec)
                   || WordMatchExact(G, rec2->group_name, rec->name, true)) {
                  ExecutiveDelete(G, rec2->name);
                  rec2 = NULL;  /* restart search (danger order N^2) */
                }
              }
            }
            break;
          case cExecutiveGroupExcise:
            if(objGroup) {

              if(rec->group_name[0]) {
                /* cascade group members up to the surrounding group */
                SpecRec *rec2 = NULL;
                while(ListIterate(I->Spec, rec2, next)) {
                  if((rec2->group == rec) ||
                     WordMatch(G, rec->name, rec2->group_name, true)) {
                    strcpy(rec2->group_name, rec->group_name);
                  }
                }
              } else if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
                /* and/or delete their group membership */
                SpecRec *rec2 = NULL;
                while(ListIterate(I->Spec, rec2, next)) {
                  if((rec2->group == rec) ||
                     WordMatch(G, rec->name, rec2->group_name, true)) {
                    rec2->group_name[0] = 0;
                  }
                }
              }
              ExecutiveDelete(G, rec->name);
            }
            break;
          }
        }
      }
      TrackerDelList(I_Tracker, list_id);
      TrackerDelIter(I_Tracker, iter_id);
      ExecutiveInvalidateGroups(G, true);
    }
  } else {
    if(obj && (obj->type == cObjectGroup)) {
      ObjectGroup *objGroup = (ObjectGroup *) obj;
      switch (action) {
      case cExecutiveGroupOpen:
        objGroup->OpenOrClosed = 1;
        break;
      case cExecutiveGroupClose:
        objGroup->OpenOrClosed = 0;
        break;
      case cExecutiveGroupToggle:
        objGroup->OpenOrClosed = !objGroup->OpenOrClosed;
        break;
      }
      if(members[0] && (action != cExecutiveGroupRemove))
        action = cExecutiveGroupAdd;

      switch (action) {
      case cExecutiveGroupAdd:
        {

          CTracker *I_Tracker = I->Tracker;
          int list_id = ExecutiveGetNamesListFromPattern(G, members, true, false);
          int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
          SpecRec *rec;

          while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                          (TrackerRef **) (void *) &rec)) {
            if(rec &&
               ((rec->type != cExecObject) ||
                ((rec->type == cExecObject) && (rec->obj != obj)))) {
              UtilNCopy(rec->group_name, valid_name, sizeof(WordType));
              if(!quiet) {
                PRINTFB(G, FB_Executive, FB_Actions)
                  " Executive: adding '%s' to group '%s'.\n", rec->name, rec->group_name
                  ENDFB(G);
              }
            }
          }
          TrackerDelList(I_Tracker, list_id);
          TrackerDelIter(I_Tracker, iter_id);
        }
        break;
      }

      ExecutiveInvalidateGroups(G, true);
    }
  }
  return ok;
}

static int ExecutiveGetUniqueIDAtomVLADict(PyMOLGlobals * G,
                                            ExecutiveObjectOffset ** return_vla,
                                            OVOneToOne ** return_dict)
{
  CExecutive *I = G->Executive;
  OVOneToOne *o2o = OVOneToOne_New(G->Context->heap);
  ExecutiveObjectOffset *vla = VLAlloc(ExecutiveObjectOffset, 1000);
  int n_oi = 0;
  {
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          ObjectMolecule *obj = (ObjectMolecule *) rec->obj;
          int a, id, n_atom = obj->NAtom;
          AtomInfoType *ai = obj->AtomInfo;
          for(a = 0; a < n_atom; a++) {
            if((id = ai->unique_id)) {
              if(OVOneToOne_GetForward(o2o, id).status == OVstatus_NOT_FOUND) {
                if(OVreturn_IS_OK(OVOneToOne_Set(o2o, id, n_oi))) {
                  VLACheck(vla, ExecutiveObjectOffset, n_oi);
                  vla[n_oi].obj = obj;
                  vla[n_oi].atm = a;
                  n_oi++;
                }
              }
            }
            ai++;
          }
        }
      }
    }
  }
  *return_dict = o2o;
  VLASize(vla, ExecutiveObjectOffset, n_oi);
  *return_vla = vla;
  return 1;
}

int ExecutiveDrawCmd(PyMOLGlobals * G, int width, int height, int antialias,
                     int entire_window, int quiet)
{
  CExecutive *I = G->Executive;
  if((width <= 0) && (height <= 0)) {
    SceneGetWidthHeight(G, &width, &height);
  }
  if(antialias < 0)
    antialias = SettingGetGlobal_i(G, cSetting_antialias);
  if(entire_window) {
    SceneInvalidateCopy(G, false);
    OrthoDirty(G);
    I->CaptureFlag = true;
  } else {
    if(SettingGetGlobal_i(G, cSetting_draw_mode) == -1) {
      ExecutiveSetSettingFromString(G, cSetting_draw_mode, "-2", "", -1, true, true);
      SceneUpdate(G, false);
    }
    SceneDeferImage(G, width, height, NULL, antialias, -1.0, cMyPNG_FormatPNG, quiet);
  }
  return 1;
}

int ExecutiveMatrixCopy2(PyMOLGlobals * G,
                         CObject * source_obj, CObject * target_obj,
                         int source_mode, int target_mode,
                         int source_state, int target_state,
                         int target_undo, int log, int quiet)
{
  /*  mode 0: raw coordinates, as per the txf history
     mode 1: object TTT matrix
     mode 2: state matrix */

  int ok = true;
  int copy_ttt_too = false;
  int matrix_mode = SettingGetGlobal_i(G, cSetting_matrix_mode);
  if(matrix_mode < 0)
    matrix_mode = 0; /* for now */

  if((source_mode < 0) && (target_mode < 0)) {
    copy_ttt_too = true;
  }
  if(source_mode < 0)
    source_mode = matrix_mode;
  if(target_mode < 0)
    target_mode = matrix_mode;

  switch (source_mode) {
  case 0:                      /* txf history is the source matrix */
    {
      double *history = NULL;
      int found = ExecutiveGetObjectMatrix2(G, source_obj, source_state, &history, false);
      if(found) {
        switch (target_mode) {
        case 0:                /* apply changes to coordinates in the target object */
          {
            double temp_inverse[16];
            if(target_undo) {
              double *target_history = NULL;
              int target_found = ExecutiveGetObjectMatrix2(G, source_obj,
                                                           target_state,
                                                           &target_history,
                                                           false);
              if(target_found && target_history) {
                invert_special44d44d(target_history, temp_inverse);
                if(history) {
                  right_multiply44d44d(temp_inverse, history);
                  history = temp_inverse;
                } else {
                  history = temp_inverse;
                }
              }
              {
                float historyf[16];
                if(history) {
                  convert44d44f(history, historyf);
                } else {
                  identity44f(historyf);
                }
                ExecutiveTransformObjectSelection2(G, target_obj, target_state,
                                                   "", log, historyf, true, false);
              }
            }
            if(copy_ttt_too) {
              const float *tttf;
              int found = ObjectGetTTT(source_obj, &tttf, -1);
              if(found) {
                ObjectSetTTT(target_obj, tttf, -1, -1);
                if(target_obj->fInvalidate)
                  target_obj->fInvalidate(target_obj, cRepNone, cRepInvExtents, -1);
              }
            }
          }
          break;
        case 1:                /* applying changes to the object's TTT matrix */
          if(history) {
            float tttf[16];
            convertR44dTTTf(history, tttf);
            ObjectSetTTT(target_obj, tttf, -1, -1);
          } else {
            ObjectSetTTT(target_obj, NULL, -1, -1);
          }
          if(target_obj->fInvalidate)
            target_obj->fInvalidate(target_obj, cRepNone, cRepInvExtents, -1);
          break;
        case 2:                /* applying changes to the state matrix */
          ok = ExecutiveSetObjectMatrix2(G, target_obj, target_state, history);
          break;
        }
        break;
      }
    }
    break;
  case 1:                      /* from the TTT matrix */
    {
      /* note that for now we're forcing states to be -1 */
      /* in the future, we may have per-state TTTs -- though right now the
         view matrices serve that purpose */

      const float *tttf;
      int found = ObjectGetTTT(source_obj, &tttf, -1);
      if(found) {
        switch (target_mode) {
        case 0:                /* coordinates & history unsupported.. */
          /* should complain */
          break;
        case 1:                /* TTT */
          ObjectSetTTT(target_obj, tttf, -1, -1);
          if(target_obj->fInvalidate)
            target_obj->fInvalidate(target_obj, cRepNone, cRepInvExtents, -1);
          break;
        case 2:                /* State */
          if(tttf) {
            double homo[16];
            convertTTTfR44d(tttf, homo);
            ok = ExecutiveSetObjectMatrix2(G, target_obj, -1, homo);
          } else {
            ok = ExecutiveSetObjectMatrix2(G, target_obj, -1, NULL);
          }
          break;
        }
      }
    }
    break;
  case 2:                      /* from the state matrix */
    {
      double *homo;
      int found = ExecutiveGetObjectMatrix2(G, source_obj, source_state, &homo, false);
      if(found) {
        switch (target_mode) {
        case 0:                /* coordinates & history */
          /* TODO */
          break;
        case 1:                /* TTT */
          if(homo) {
            float tttf[16];
            convertR44dTTTf(homo, tttf);
            ObjectSetTTT(target_obj, tttf, -1, -1);
            if(target_obj->fInvalidate)
              target_obj->fInvalidate(target_obj, cRepNone, cRepInvExtents, -1);
          } else {
            ObjectSetTTT(target_obj, NULL, -1, -1);
            if(target_obj->fInvalidate)
              target_obj->fInvalidate(target_obj, cRepNone, cRepInvExtents, -1);
          }
          break;
        case 2:                /* State */
          ok = ExecutiveSetObjectMatrix2(G, target_obj, target_state, homo);
          if(copy_ttt_too) {
            const float *tttf;
            int found = ObjectGetTTT(source_obj, &tttf, -1);
            if(found) {
              ObjectSetTTT(target_obj, tttf, -1, -1);
              if(target_obj->fInvalidate)
                target_obj->fInvalidate(target_obj, cRepNone, cRepInvExtents, -1);
            }
          }
          break;
        }
      }
    }
    break;
  }
  SceneInvalidate(G);
  return ok;
}

int ExecutiveMatrixCopy(PyMOLGlobals * G,
                        const char *source_name, const char *target_name,
                        int source_mode, int target_mode,
                        int source_state, int target_state,
                        int target_undo, int log, int quiet)
{
  /*  mode 0: raw coordinates, as per the txf history
     mode 1: object TTT matrix
     mode 2: state matrix
     mode 3 (source only): camera matrix transformation */

  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  SpecRec *src_rec = NULL;
  int ok = true;
  int copy_ttt_too = false;
  int matrix_mode = SettingGetGlobal_i(G, cSetting_matrix_mode);
  if(matrix_mode < 0)
    matrix_mode = 0; /* for now */

  if((source_mode < 0) && (target_mode < 0)) {
    copy_ttt_too = true;
  }

  if(source_mode < 0)
    source_mode = matrix_mode;
  if(target_mode < 0)
    target_mode = matrix_mode;
  if(source_name[0] == 0) {
    source_mode = 3;
    target_undo = 0;
  } else
    src_rec = ExecutiveFindSpec(G, source_name);

  if (source_mode != 3 && !src_rec) {
    PRINTFB(G, FB_Executive, FB_Warnings)
      " %s-Warning: Can't find source object '%s'.\n", __FUNCTION__, source_name
      ENDFB(G);
  }

  int list_id = ExecutiveGetNamesListFromPattern(G, target_name, true, cExecExpandKeepGroups);

  if (!list_id) {
    PRINTFB(G, FB_Executive, FB_Warnings)
      " %s-Warning: No match for target '%s'.\n", __FUNCTION__, target_name
      ENDFB(G);
  }

  switch (source_mode) {
  case 0:                      /* txf history is the source matrix */
    {
      double *history = NULL;
      int found = ExecutiveGetObjectMatrix(G, source_name, source_state, &history, false);
      if(found) {

        int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
        SpecRec *rec;

        while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                        (TrackerRef **) (void *) &rec)) {
          if(rec && (rec != src_rec)) {
            switch (rec->type) {
            case cExecObject:

              switch (target_mode) {
              case 0:          /* apply changes to coordinates in the target object */
                {
                  double temp_inverse[16];
                  if(target_undo) {
                    double *target_history = NULL;
                    int target_found = ExecutiveGetObjectMatrix(G, rec->name,
                                                                target_state,
                                                                &target_history,
                                                                false);
                    if(target_found && target_history) {
                      invert_special44d44d(target_history, temp_inverse);
                      if(history) {
                        right_multiply44d44d(temp_inverse, history);
                        history = temp_inverse;
                      } else {
                        history = temp_inverse;
                      }
                    }
                  }
                  {
                    float historyf[16];
                    if(history) {
                      convert44d44f(history, historyf);
                    } else {
                      identity44f(historyf);
                    }
                    ExecutiveTransformObjectSelection(G, rec->name, target_state,
                                                      "", log, historyf, true, false);
                  }
                  if(copy_ttt_too) {
                    const float *tttf;
                    int found = ExecutiveGetObjectTTT(G, source_name, &tttf, -1, quiet);
                    if(found) {
                      ExecutiveSetObjectTTT(G, rec->name, tttf, -1, quiet, -1);
                    }
                  }
                }
                break;
              case 1:          /* applying changes to the object's TTT matrix */
                if(history) {
                  float tttf[16];
                  convertR44dTTTf(history, tttf);
                  ExecutiveSetObjectTTT(G, rec->name, tttf, -1, quiet, -1);
                } else {
                  ExecutiveSetObjectTTT(G, rec->name, NULL, -1, quiet, -1);
                }
                /* to do: logging, return values, etc. */
                break;
              case 2:          /* applying changes to the state matrix */
                ok = ExecutiveSetObjectMatrix(G, rec->name, target_state, history);
                break;
              }
              break;
            }
          }
        }
        TrackerDelIter(I_Tracker, iter_id);
      }
    }
    break;
  case 1:                      /* from the TTT matrix */
    {
      /* note that for now we're forcing states to be -1 */
      /* in the future, we may have per-state TTTs -- though right now the
         view matrices serve that purpose */

      const float *tttf;
      int found = ExecutiveGetObjectTTT(G, source_name, &tttf, -1, quiet);
      if(found) {

        int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
        SpecRec *rec;

        while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                        (TrackerRef **) (void *) &rec)) {
          if(rec && (rec != src_rec)) {

            switch (rec->type) {
            case cExecObject:

              switch (target_mode) {
              case 0:          /* coordinates & history unsupported.. */
                /* should complain */
                break;
              case 1:          /* TTT */
                ExecutiveSetObjectTTT(G, rec->name, tttf, -1, quiet, -1);
                break;
              case 2:          /* State */
                if(tttf) {
                  double homo[16];
                  convertTTTfR44d(tttf, homo);
                  ok = ExecutiveSetObjectMatrix(G, rec->name, -1, homo);
                } else {
                  ok = ExecutiveSetObjectMatrix(G, rec->name, -1, NULL);
                }
                break;
              }
            }
          }
        }

        TrackerDelIter(I_Tracker, iter_id);
      }
    }
    break;
  case 2:                      /* from the state matrix */
    {
      double *homo;
      int found = ExecutiveGetObjectMatrix(G, source_name, source_state, &homo, false);
      if(found) {

        int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
        SpecRec *rec;

        while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                        (TrackerRef **) (void *) &rec)) {
          if(rec && (rec != src_rec)) {
            switch (rec->type) {
            case cExecObject:

              switch (target_mode) {
              case 0:          /* coordinates & history */
                /* TODO */
                break;
              case 1:          /* TTT */
                if(homo) {
                  float tttf[16];
                  convertR44dTTTf(homo, tttf);
                  ExecutiveSetObjectTTT(G, rec->name, tttf, -1, quiet, -1);
                } else {
                  ExecutiveSetObjectTTT(G, rec->name, NULL, -1, quiet, -1);
                }
                break;
              case 2:          /* State */
                ok = ExecutiveSetObjectMatrix(G, rec->name, target_state, homo);
                if(copy_ttt_too) {
                  const float *tttf;
                  int found = ExecutiveGetObjectTTT(G, source_name, &tttf, -1, quiet);
                  if(found) {
                    ExecutiveSetObjectTTT(G, rec->name, tttf, -1, quiet, -1);
                  }
                }
                break;
              }
            }
          }
        }
        TrackerDelIter(I_Tracker, iter_id);
      }
    }
    break;
  case 3:                      /* camera */
    {
      SceneViewType view;
      double homo[16], *history;
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
      SpecRec *rec;
      SceneGetView(G, view);
      homo[0] = view[0];
      homo[1] = view[4];
      homo[2] = view[8];
      homo[3] = -(view[0] * view[19] + view[4] * view[20] + view[8] * view[21]);
      homo[4] = view[1];
      homo[5] = view[5];
      homo[6] = view[9];
      homo[7] = -(view[1] * view[19] + view[5] * view[20] + view[9] * view[21]);
      homo[8] = view[2];
      homo[9] = view[6];
      homo[10] = view[10];
      homo[11] = -(view[2] * view[19] + view[6] * view[20] + view[10] * view[21]);
      homo[12] = 0.0;
      homo[13] = 0.0;
      homo[14] = 0.0;
      homo[15] = 1.0;
      history = homo;
      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec && (rec != src_rec)) {
          switch (rec->type) {
          case cExecObject:

            switch (target_mode) {
            case 0:            /* apply changes to coordinates in the target object */
              {
                double temp_inverse[16];
                if(target_undo) {
                  double *target_history = NULL;
                  int target_found = ExecutiveGetObjectMatrix(G, rec->name,
                                                              target_state,
                                                              &target_history,
                                                              false);
                  if(target_found && target_history) {
                    invert_special44d44d(target_history, temp_inverse);
                    if(history) {
                      right_multiply44d44d(temp_inverse, history);
                      history = temp_inverse;
                    } else {
                      history = temp_inverse;
                    }
                  }
                }
                {
                  float historyf[16];
                  if(history) {
                    convert44d44f(history, historyf);
                  } else {
                    identity44f(historyf);
                  }
                  ExecutiveTransformObjectSelection(G, rec->name, target_state,
                                                    "", log, historyf, true, false);
                }
              }
              break;
            case 1:            /* applying changes to the object's TTT matrix */
              if(history) {
                float tttf[16];
                convertR44dTTTf(history, tttf);
                ExecutiveSetObjectTTT(G, rec->name, tttf, -1, quiet, -1);
              } else {
                ExecutiveSetObjectTTT(G, rec->name, NULL, -1, quiet, -1);
              }
              /* to do: logging, return values, etc. */
              break;
            case 2:            /* applying changes to the state matrix */
              ok = ExecutiveSetObjectMatrix(G, rec->name, target_state, history);
              break;
            }
            break;
          }
        }
        TrackerDelIter(I_Tracker, iter_id);
      }
    }
    break;
  }

  TrackerDelList(I_Tracker, list_id);

  SceneInvalidate(G);
  return ok;
}

static void ExecutiveInvalidateMapDependents(PyMOLGlobals * G, const char *map_name, const char * new_name = NULL)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      switch (rec->obj->type) {
      case cObjectMesh:
        ObjectMeshInvalidateMapName((ObjectMesh *) rec->obj, map_name, new_name);
        break;
      case cObjectSurface:
        ObjectSurfaceInvalidateMapName((ObjectSurface *) rec->obj, map_name, new_name);
        break;
      case cObjectVolume:
        ObjectVolumeInvalidateMapName((ObjectVolume *) rec->obj, map_name, new_name);
        break;
      }
    }
  }
  SceneInvalidate(G);
}

void ExecutiveResetMatrix(PyMOLGlobals * G,
                          const char *name, int mode, int state, int log, int quiet)
{
  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;
  int matrix_mode = SettingGetGlobal_i(G, cSetting_matrix_mode);
  if(matrix_mode < 0)
    matrix_mode = 0; /* for now */

  if(mode < 0)
    mode = matrix_mode;

  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec && (rec->type == cExecObject)) {
      /*  CObject *obj = ExecutiveFindObjectByName(G,name); */
      CObject *obj = rec->obj;
      if(obj) {
        switch (obj->type) {
        case cObjectMolecule:
          switch (mode) {
          case 0:              /* transformations already applied to the coordinates */
            {
              double *history = NULL;
              int found = ExecutiveGetObjectMatrix(G, rec->name, state, &history, false);
              if(found && history) {
                double temp_inverse[16];
                float historyf[16];
                invert_special44d44d(history, temp_inverse);
                convert44d44f(temp_inverse, historyf);
                ExecutiveTransformObjectSelection(G, rec->name, state, "",
                                                  log, historyf, true, false);
              }
            }
            break;
          case 1:              /* operate on the TTT display matrix */
            ObjectResetTTT(obj,SettingGetGlobal_b(G,cSetting_movie_auto_store));
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);

            break;
          case 2:              /* applying changes to the state matrix */
            {
              double ident[16];
              identity44d(ident);
              ExecutiveSetObjectMatrix(G, rec->name, state, ident);
            }
            break;
          }
          break;
        case cObjectMap:
          ObjectMapResetMatrix((ObjectMap *) obj, state);
          break;
        case cObjectGroup:
          ObjectGroupResetMatrix((ObjectGroup *) obj, state);
          break;
        }
      }
    }
  }
}

static double ret_mat[16];      /* UGH ..not thread-safe */

static int ExecutiveGetObjectMatrix2(PyMOLGlobals * G, CObject * obj, int state,
                                     double **matrix, int incl_ttt)
{
  /* right now, this only makes sense for molecule objects -- but in
     time all objects should have per-state matrices */

  int ok = false;
  if(state < 0) {
    /* to do -- TTT only */
  } else {
    switch (obj->type) {
    case cObjectMolecule:
      ok = ObjectMoleculeGetMatrix((ObjectMolecule *) obj, state, matrix);
      break;
    case cObjectMap:
      ok = ObjectMapGetMatrix((ObjectMap *) obj, state, matrix);
      break;
    case cObjectGroup:
      ok = ObjectGroupGetMatrix((ObjectGroup *) obj, state, matrix);
      break;
    }

    if(ok && incl_ttt) {
      const float *ttt;
      double tttd[16];
      if(ObjectGetTTT(obj, &ttt, -1)) {
        convertTTTfR44d(ttt, tttd);
        if(*matrix) {
          copy44d(*matrix, ret_mat);
        } else {
          identity44d(ret_mat);
        }
        left_multiply44d44d(tttd, ret_mat);
        *matrix = ret_mat;
      }
    }
  }
  return ok;
}

int ExecutiveGetObjectMatrix(PyMOLGlobals * G, const char *name, int state, double **matrix,
                             int incl_ttt)
{
  int ok = false;
  CObject *obj = ExecutiveFindObjectByName(G, name);
  if(obj) {
    return ExecutiveGetObjectMatrix2(G, obj, state, matrix, incl_ttt);
  }
  return ok;
}

static int ExecutiveSetObjectMatrix2(PyMOLGlobals * G, CObject * obj, int state,
                                     double *matrix)
{
  /* -1 for the TTT matrix, 0 or greater for the state matrix */

  /* right now, this only makes sense for molecule objects -- but in
     time all objects should have per-state matrices */
  int ok = false;
  if(state < 0) {

  } else {
    switch (obj->type) {
    case cObjectMolecule:
      ok = ObjectMoleculeSetMatrix((ObjectMolecule *) obj, state, matrix);
      break;
    case cObjectMap:
      ok = ObjectMapSetMatrix((ObjectMap *) obj, state, matrix);
      break;
    case cObjectGroup:
      ok = ObjectGroupSetMatrix((ObjectGroup *) obj, state, matrix);
      break;
    }
  }
  return ok;
}

int ExecutiveSetObjectMatrix(PyMOLGlobals * G, const char *name, int state, double *matrix)
{
  int ok = false;
  CObject *obj = ExecutiveFindObjectByName(G, name);
  if(obj) {
    return ExecutiveSetObjectMatrix2(G, obj, state, matrix);
  }
  return ok;
}

static int ExecutiveCountNames(PyMOLGlobals * G)
{
  int count = 0;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  while(ListIterate(I->Spec, rec, next))
    count++;

  return (count);
}

static int ReorderOrderFn(PyMOLGlobals * G, SpecRec ** rec, int l, int r)
{
  return (WordCompare(G, rec[l]->name, rec[r]->name, true) <= 0);
}

static int SpecRecListPopulate(SpecRec ** list, SpecRec * first, const char * group_name)
{
  /* Add items to list such that group items are ordered behind their group records.
   * author: Thomas Holder, 2013-08
   * runtime: O(N * G) where N is the number of SpecRecs and G the number of groups
   * args: list: pointer to the end of the list
   *       first: pointer to G->Executive->Spec (root of linked list)
   *       group_name: if empty string, append ungrouped items, otherwise append group items
   * returns: number of appended items
   */
  SpecRec *rec;
  int a = 0;
  for(rec = first; rec; rec = rec->next) {
    if(!strcmp(group_name, rec->group_name)) {
      list[a++] = rec;
      if(rec->type == cExecObject && rec->obj->type == cObjectGroup)
        a += SpecRecListPopulate(list + a, first, rec->name);
    }
  }
  return a;
}

int ExecutiveOrder(PyMOLGlobals * G, const char *s1, int sort, int location)
{
  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  int ok = true;
  CWordList *word_list = WordListNew(G, s1);
  int n_names = ExecutiveCountNames(G);

  if(n_names) {
    SpecRec **list, **subset, **sorted;
    int *index = NULL;
    int n_sel;
    int source_row = -1;
    int min_row = -1;
    list = Alloc(SpecRec *, n_names);
    subset = Calloc(SpecRec *, n_names);
    sorted = Calloc(SpecRec *, n_names);
    index = Alloc(int, n_names);
    if(list && subset) {
      /* create an array of current names */
      {
        int a = 0;
        /* copy all names into array */
        /* update Thomas Holder 2013-08: order group members behind group.
         * fixes PYMOL-1382 (eventually).
         * I don't know if this is the best place for the fix, but it's my best guess.
         */
        SpecRecListPopulate(list, I->Spec, "");
        /* unlink them */
        for(a = 0; a < n_names; a++) {
          list[a]->next = NULL;
        }
      }
      /* transfer matching names to the subset array */
      {
        int a;
        int entry;
        int min_entry = word_list->n_word;
        const char *word = NULL;
        int word_iter = 0;
        while(WordListIterate(G, word_list, &word, &word_iter)) {
          int list_id = ExecutiveGetNamesListFromPattern(G, word, true, false);
          SpecRec *rec = NULL;
          entry = word_iter - 1;
          for(a = n_names - 1; a > 0; a--) {    /* skipping zeroth */
            int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
            while(TrackerIterNextCandInList
                  (I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
              if(rec == list[a]) {
                if((a < min_row) || (min_row < 0))
                  min_row = a;
                if(entry <= min_entry) {
                  source_row = a;       /* where will new list be inserted... */
                  min_entry = entry;
                }
                /* ensure that each record appears only once */
                rec->next = subset[entry];
                subset[entry] = rec;
                list[a] = NULL;
              }
            }
            TrackerDelIter(I_Tracker, iter_id);
          }
          TrackerDelList(I_Tracker, list_id);
        }
        if(word_list->n_word && WordMatchExact(G, word_list->start[0], cKeywordAll, true))
          location = -1;        /* set to top if "all" is first in list */
      }
      /* expand the selected entries */
      {
        SpecRec *rec, *last;
        int b;
        n_sel = 0;
        for(b = 0; b < word_list->n_word; b++) {
          rec = subset[b];
          while(rec) {
            sorted[n_sel++] = rec;
            last = rec;
            rec = rec->next;
            last->next = NULL;
          }
        }
      }
      /* sort the selected entries, if requested */
      if(sort) {
        UtilCopyMem(subset, sorted, sizeof(SpecRec *) * n_sel);
        {
          int a;
          UtilSortIndexGlobals(G, n_sel, subset, index,
                               (UtilOrderFnGlobals *) ReorderOrderFn);
          for(a = 0; a < n_sel; a++) {
            sorted[a] = subset[index[a]];
          }
        }
      }
      /* reassemble the list using the new order */
      {
        SpecRec *spec = NULL;
        SpecRec *last = NULL;
        int a, b;
        int flag;
        for(a = 0; a < n_names; a++) {
          flag = false;
          if(sorted) {          /* not yet added */
            switch (location) {
            case -1:           /* top */
              if(a == 1)
                flag = true;
              break;
            case -2:           /* upper */
              if(min_row >= 0) {
                if(a == min_row)
                  flag = true;
              } else if(!list[a])
                flag = true;
              break;
            case 0:            /* current */
              if(source_row >= 0) {
                if(a == source_row)
                  flag = true;
              } else if(!list[a])
                flag = true;
              break;
            }
          }
          if(flag) {
            for(b = 0; b < n_sel; b++) {
              if(sorted[b]) {
                if(last)
                  last->next = sorted[b];
                last = sorted[b];
                if(!spec)
                  spec = last;
              }
            }
            FreeP(sorted);
          }
          if(list[a]) {
            if(last)
              last->next = list[a];
            last = list[a];
            if(!spec)
              spec = last;
          }
        }
        if(sorted) {            /* still not yet readded? */
          for(b = 0; b < n_sel; b++) {
            if(sorted[b]) {
              if(last)
                last->next = sorted[b];
              last = sorted[b];
              if(!spec)
                spec = last;
            }
          }
        }
        I->Spec = spec;
        OrthoDirty(G);
        SeqChanged(G);
      }
      FreeP(index);
      FreeP(sorted);
      FreeP(list);
      FreeP(subset);
    }
    ExecutiveInvalidatePanelList(G);
  }
  WordListFreeP(word_list);
  return (ok);
}

ObjectMolecule **ExecutiveGetObjectMoleculeVLA(PyMOLGlobals * G, const char *sele)
{
  ObjectMolecule **result = NULL;
  int s1 = SelectorIndexByName(G, sele);
  if(s1 >= 0) {
    ObjectMoleculeOpRec op;
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_GetObjects;
    op.obj1VLA = (ObjectMolecule **) VLAlloc(ObjectMolecule *, 10);
    op.i1 = 0;
    ExecutiveObjMolSeleOp(G, s1, &op);
    result = (ObjectMolecule **) op.obj1VLA;
    VLASize(result, ObjectMolecule *, op.i1);
  }
  return result;
}


/* #define ExecLineHeight 18 */
#define ExecClickMargin DIP2PIXEL(2)
#define ExecTopMargin 0
#define ExecToggleMargin DIP2PIXEL(2)
#define ExecLeftMargin DIP2PIXEL(1)
#define ExecRightMargin 0
#define ExecToggleWidth DIP2PIXEL(17)
#define ExecToggleSize DIP2PIXEL(16)
#define ExecToggleTextShift DIP2PIXEL(4)

typedef struct {
  M4XAnnoType m4x;
  ObjectMolecule *obj;
} ProcPDBRec;

int ExecutiveSetDrag(PyMOLGlobals * G, const char *name, int quiet,int mode)
{
  char drag_name[] = cEditorDrag;
  int set_flag = false;
  int need_sele = true;
  int result = true;
  if(name[0]) {
    CObject *obj = ExecutiveFindObjectByName(G, name);
    if(obj) {
      EditorSetDrag(G, obj, -1, quiet, SceneGetState(G));
      set_flag = true;
    } else {
      SpecRec *rec = ExecutiveFindSpec(G, name);
      if(rec) {
        if(rec->type == cExecSelection) {
          SelectorCreate(G, drag_name, name, NULL, true, NULL);
          need_sele = false;
          {
            int sele = SelectorIndexByName(G, drag_name);
            ObjectMolecule *objMol = SelectorGetSingleObjectMolecule(G, sele);
            if(objMol) {
              if(mode>0) 
                sele = -1; /* force drag by matrix */
              EditorSetDrag(G, &objMol->Obj, sele, quiet, SceneGetState(G));
              set_flag = true;
            } else {
              PRINTFB(G, FB_Executive, FB_Errors)
                " Drag-Error: selection spans more than one object.\n" ENDFB(G);
            }
          }
        } else if(rec->type == cExecObject) {
          switch (rec->obj->type) {
          case cObjectGroup:
            PRINTFB(G, FB_Executive, FB_Errors)
              " Drag-Error: cannot drag group objects yet.\n" ENDFB(G);
            break;
            
          }
          result = false;
        }
      }
    }
    result = set_flag;
    if(!result) {
      EditorInactivate(G);
      PRINTFB(G, FB_Executive, FB_Errors)
        " Drag-Error: invalid or empty selection." ENDFB(G);
    } else if(EditorDraggingObjectMatrix(G)) {
      SelectorCreate(G, drag_name, "none", NULL, true, NULL);    
    } else if(need_sele && (obj->type == cObjectMolecule) && (!EditorDraggingObjectMatrix(G))) {
      SelectorCreate(G, drag_name, obj->Name, (ObjectMolecule*)(void*)obj, true, NULL);     /* for indication only */
    }
  } else {
    EditorInactivate(G);
  }
  return result;
}

int ExecutivePop(PyMOLGlobals * G, const char *target, const char *source, int quiet)
{
  int ok = true;
  int src;
  int result = 0;

  ExecutiveDelete(G, target);
  if(ExecutiveFindObjectMoleculeByName(G, source)) {
    ok = false;
    PRINTFB(G, FB_Executive, FB_Errors)
      " Pop-Error: source selection '%s' can't be an object.\n", source ENDFB(G);

  } else {
    src = SelectorIndexByName(G, source);
    if(src < 0)
      ok = false;
    if(!ok) {
      PRINTFB(G, FB_Executive, FB_Errors)
        " Pop-Error: invalid source selection name '%s'\n", source ENDFB(G);
    } else {
      ObjectMoleculeOpRec op;

      ObjectMoleculeOpRecInit(&op);
      op.code = OMOP_Pop;
      SelectorCreateEmpty(G, target, true);
      op.i1 = SelectorIndexByName(G, target);
      op.i2 = 1;
      op.i3 = 0;
      ExecutiveObjMolSeleOp(G, src, &op);
      result = op.i3;
    }
  }
  if(!result)
    ExecutiveDelete(G, target);
  if(!ok)
    return -1;
  else
    return result;
}

int ExecutiveGetActiveAlignmentSele(PyMOLGlobals * G)
{
  const char *alignment = SettingGetGlobal_s(G, cSetting_seq_view_alignment);
  int align_sele = -1;
  if(alignment && alignment[0]) {       /* explicit alignment setting name */
    align_sele = SelectorIndexByName(G, alignment);
  } else {                      /* otherwise, use the first active alignment */
    SpecRec *rec = NULL;
    CExecutive *I = G->Executive;
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->visible) {
        if(rec->type == cExecObject)
          if(rec->obj->type == cObjectAlignment) {
            if(rec->obj->fUpdate)       /* allow object to update selection, if necessary */
              rec->obj->fUpdate(rec->obj);
            align_sele = SelectorIndexByName(G, rec->obj->Name);
            if(align_sele >= 0)
              break;
          }
      }
    }
  }
  return align_sele;
}

int ExecutiveGetActiveSele(PyMOLGlobals * G)
{
  ObjectNameType name;
  if(ExecutiveGetActiveSeleName(G, name, false, false))
    return SelectorIndexByName(G, name);
  else
    return -1;

}

int ExecutiveGetActiveSeleName(PyMOLGlobals * G, char *name, int create_new, int log)
{
  /* TODO: cache/optimize to avoid table scan */

  int result = false;
  SpecRec *rec = NULL;
  CExecutive *I = G->Executive;
  while(ListIterate(I->Spec, rec, next)){
    if(rec->type == cExecSelection){
      if(rec->visible) {
        strcpy(name, rec->name);
        result = true;
      }
    }
  }
  if((!result) && create_new) {
    if(SettingGetGlobal_b(G, cSetting_auto_number_selections)) {
      int sel_num = SettingGetGlobal_i(G, cSetting_sel_counter) + 1;

      SettingSetGlobal_i(G, cSetting_sel_counter, sel_num);
      sprintf(name, "sel%02d", sel_num);
      SelectorCreateEmpty(G, name, -1);
      if(log) {
        if(SettingGetGlobal_i(G, cSetting_logging)) {
          OrthoLineType buf2;
          sprintf(buf2, "cmd.select('%s','none')\n", name);
          PLog(G, buf2, cPLog_no_flush);
        }
      }
    } else {
      sprintf(name, "sele");
      SelectorCreateEmpty(G, name, -1);
      if(log) {
        OrthoLineType buf2;
        sprintf(buf2, "cmd.select('%s','none')\n", name);
        PLog(G, buf2, cPLog_no_flush);
      }
    }
  }
  return result;
}

int ExecutiveFixChemistry(PyMOLGlobals * G, const char *s1, const char *s2, int invalidate, int quiet)
{
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  int sele1 = tmpsele1.getIndex();
  int sele2 = tmpsele2.getIndex();

  int ok = true;
  SpecRec *rec = NULL;
  CExecutive *I = G->Executive;

  if((sele1 >= 0) && (sele2 >= 0)) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject)
        if(rec->obj->type == cObjectMolecule) {
          ObjectMoleculeFixChemistry((ObjectMolecule *) rec->obj, sele1, sele2,
                                     invalidate);
        }
    }
  }
  return ok;
}

int ExecutiveSetObjectColor(PyMOLGlobals * G, const char *name, const char *color, int quiet)
{
  int result = false;
  int col_ind = ColorGetIndex(G, color);
  CObject *obj = NULL;
  obj = ExecutiveFindObjectByName(G, name);
  if(obj) {
    obj->Color = col_ind;
    result = true;
  }
  return (result);
}

int ExecutiveGetObjectColorIndex(PyMOLGlobals * G, const char *name)
{
  int result = -1;
  CObject *obj = NULL;
  obj = ExecutiveFindObjectByName(G, name);
  if(obj) {
    result = obj->Color;
  }
  return (result);
}

int ExecutiveGetAtomVertex(PyMOLGlobals * G, const char *s1, int state, int index, float *v)
{
  int ok = false;
  int sele1 = SelectorIndexByName(G, s1);

  if(sele1 >= 0) {
    ok = SelectorGetSingleAtomVertex(G, sele1, state, v);
  }
  return ok;
}

void ExecutiveMakeUnusedName(PyMOLGlobals * G, char * prefix, int length,
                             bool alwaysnumber, int start,
                             const char * pattern) {

  if (!prefix[0])
    strcpy(prefix, "obj");

  int prefixlen = strlen(prefix);
  int suffixlen = length - prefixlen;
  char * end = prefix + prefixlen;

  for (int cnt = start; alwaysnumber || ExecutiveValidName(G, prefix); ++cnt) {
    snprintf(end, suffixlen, pattern, cnt);
    alwaysnumber = false;
  }
}

std::string ExecutiveGetUnusedName(PyMOLGlobals * G, const char * prefix,
                                   bool alwaysnumber) {

  OrthoLineType unused_name;
  strcpy(unused_name, prefix);

  ObjectMakeValidName(G, unused_name);

  ExecutiveMakeUnusedName(G, unused_name, OrthoLineLength, alwaysnumber);

  return std::string(unused_name);
}

int ExecutiveProcessObjectName(PyMOLGlobals * G, const char *proposed, char *actual)
{
  int result = true;
  UtilNCopy(actual, proposed, sizeof(ObjectNameType));
  if(SettingGetGlobal_b(G, cSetting_validate_object_names))
    ObjectMakeValidName(G, actual);
  if(SettingGetGlobal_b(G, cSetting_auto_rename_duplicate_objects) || !proposed[0]) {
    ExecutiveMakeUnusedName(G, actual, sizeof(ObjectNameType), false, 2, "_%d");
  }
  return result;
}

int ExecutiveSetName(PyMOLGlobals * G, const char *old_name, const char *new_name)
{
  int ok = true;
  SpecRec *rec = NULL;
  CExecutive *I = G->Executive;
  int found = false;
  auto ignore_case = SettingGet<bool>(G, cSetting_ignore_case);

  ObjectNameType name;
  UtilNCopy(name, new_name, sizeof(ObjectNameType));
  ObjectMakeValidName(name);

  if(!name[0]) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "SetName-Error: blank names not allowed.\n" ENDFB(G);
    ok = false;
  } else if(WordMatchExact(G, name, cKeywordSame, ignore_case) || SelectorNameIsKeyword(G, name)) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "SetName-Error: name '%s' is a selection keyword.\n", name ENDFB(G);
    ok = false;
  }
  if(ok) {
    if(!name[0])
      ok = false;
    else if(!WordMatchExact(G, name, old_name, ignore_case)) {

      while(ListIterate(I->Spec, rec, next)) {
        if(found)
          break;
        switch (rec->type) {
        case cExecObject:
          if(WordMatchExact(G, rec->obj->Name, old_name, ignore_case)) {
            ExecutiveDelKey(I, rec);
            ExecutiveDelete(G, name);
            ObjectSetName(rec->obj, name);
            UtilNCopy(rec->name, rec->obj->Name, WordLength);
            ExecutiveAddKey(I, rec);
            if(rec->obj->type == cObjectMolecule) {
              /*
                 SelectorDelete(G,old_name);
                 ExecutiveUpdateObjectSelection(G,rec->obj);
               */
              SelectorSetName(G, name, old_name);
              SceneChanged(G);
              SeqChanged(G);
            }
            if (rec->obj->type == cObjectMap)
              ExecutiveInvalidateMapDependents(G, old_name, name);

            found = true;
          }
          break;
        case cExecSelection:
          if(WordMatchExact(G, rec->name, old_name, ignore_case)) {
            if(SelectorSetName(G, name, old_name)) {
              ExecutiveDelete(G, name); /* just in case */
              ExecutiveDelKey(I, rec);
              UtilNCopy(rec->name, name, WordLength);
              ExecutiveAddKey(I, rec);
              found = true;
              OrthoDirty(G);
            }
          }
          break;
        }
      }
      if(!found)
        ok = false;
      else {
        rec = NULL;
        int old_name_len = strlen(old_name);
        int new_name_len = strlen(name);
        ObjectNameType childname;
        UtilNCopy(childname, name, sizeof(ObjectNameType));
        while(ListIterate(I->Spec, rec, next)) {
          if(WordMatchExact(G, rec->group_name, old_name, ignore_case)) {
            UtilNCopy(rec->group_name, name, WordLength);
            // rename group members for group_auto_mode
            if (strncmp(rec->name, old_name, old_name_len) == 0 && rec->name[old_name_len] == '.') {
              UtilNCopy(childname + new_name_len, rec->name + old_name_len, sizeof(ObjectNameType) - new_name_len);
              ExecutiveSetName(G, rec->name, childname);
            }
          }
        }
        ExecutiveInvalidateGroups(G, false);
      }
    }
  }
  return ok;
}


/*
 * Load any file type which is implemented in C.
 *
 * content:     Either file name or file contents, depending on "content_format"
 * content_length:      Length of "content", if it's not a file name
 * content_format:      File type code
 * object_name:         New object name
 * state:       Object state to start loading new coordsets in
 * zoom:        Zoom on new loaded atoms
 * discrete:    Make discrete states
 * finish:      update object selection & zoom
 * multiplex:   Split new states into objects
 * quiet:       Suppress feedback
 * object_props:        names of object properties to load
 * atom_props:          names of atom properties to load
 */
int ExecutiveLoad(PyMOLGlobals * G,
                  const char *content, int content_length,
                  int content_format,
                  const char *object_name_proposed,
                  int state, int zoom,
                  int discrete, int finish, int multiplex, int quiet,
                  const char * plugin_arg,
                  const char * object_props,
                  const char * atom_props,
                  bool mimic)
{
  int ok = true;
  const char * fname = content;
  char * buffer = NULL;
  long size = (long) content_length;
  OrthoLineType buf = "";
  char plugin[16] = "";
  CObject *obj = NULL;
  CObject *origObj = NULL;
  int pdb_variant = PDB_VARIANT_DEFAULT;

  // validate proposed object name
  ObjectNameType object_name = "";
  ExecutiveProcessObjectName(G, object_name_proposed, object_name);

  // Ensure correct float parsing with scanf. It's possible to change this from
  // Python, so don't rely on a persistent global value.
  std::setlocale(LC_NUMERIC, "C");

  if (!object_props) object_props = SettingGetGlobal_s(G, cSetting_load_object_props_default);
  if (!atom_props)   atom_props   = SettingGetGlobal_s(G, cSetting_load_atom_props_default);

  // multiplex -2 -> "multiplex" setting
  // multiplex -1 -> file type dependant default
  // multiplex 1 -> split entries (don't try to load into existing object)
  if(multiplex == -2) {
    multiplex = SettingGetGlobal_i(G, cSetting_multiplex);
  }

  switch (content_format) {
  // string loading functions
  case cLoadTypePDBStr:
  case cLoadTypeVDBStr:
  case cLoadTypeCIFStr:
  case cLoadTypeMMTFStr:
  case cLoadTypeMAEStr:
  case cLoadTypeXPLORStr:
  case cLoadTypeCCP4Str:
  case cLoadTypePHIStr:
  case cLoadTypeMMDStr:
  case cLoadTypeMOLStr:
  case cLoadTypeMOL2Str:
  case cLoadTypeSDF2Str:
  case cLoadTypeXYZStr:
    fname = NULL;
    break;
  case cLoadTypePQR:
  case cLoadTypePDBQT:
  case cLoadTypePDB:
  case cLoadTypeCIF:
  case cLoadTypeMMTF:
  case cLoadTypeMAE:
  case cLoadTypeXPLORMap:
  case cLoadTypeCCP4Map:
  case cLoadTypePHIMap:
  case cLoadTypeMMD:
  case cLoadTypeMOL:
  case cLoadTypeMOL2:
  case cLoadTypeSDF2:
  case cLoadTypeXYZ:
    buffer = FileGetContents(fname, &size);
    content = buffer;

    if(!buffer) {
      PRINTFB(G, FB_Executive, FB_Errors)
        "ExecutiveLoad-Error: Unable to open file '%s'.\n", fname ENDFB(G);
      return false;
    } else {
      PRINTFB(G, FB_Executive, FB_Blather)
        " ExecutiveLoad: Loading from %s.\n", fname ENDFB(G);
    }

    break;

  // molfile_plugin based formats
  case cLoadTypeCUBEMap:
    strcpy(plugin, "cube");
    break;
  case cLoadTypeSpider:
    strcpy(plugin, "spider");
    break;
  case cLoadTypeXTC:
    strcpy(plugin, "xtc");
    break;
  case cLoadTypeTRR:
    strcpy(plugin, "trr");
    break;
  case cLoadTypeGRO:
    strcpy(plugin, "gro");
    break;
  case cLoadTypeG96:
    strcpy(plugin, "g96");
    break;
  case cLoadTypeTRJ2:
    strcpy(plugin, "trj");
    break;
  case cLoadTypeDCD:
    strcpy(plugin, "dcd");
    break;
  case cLoadTypeDTR:
    strcpy(plugin, "dtr");
    break;
  case cLoadTypeCMS:
    strcpy(plugin, "mae");
    break;
  default:
    if (plugin_arg)
      strcpy(plugin, plugin_arg);
    break;
  }

  if (plugin[0]) {
    content_format = cLoadTypePlugin;
  }

  if (multiplex != 1) {
    origObj = ExecutiveGetExistingCompatible(G, object_name, content_format);
  }

#ifndef _PYMOL_NO_UNDO
#endif

  // file type dependent multiplex and discrete default
  if(discrete < 0) {
    if(multiplex == 1) {
      discrete = 0;
    } else {
      switch (content_format) {
        case cLoadTypeMOL2:
        case cLoadTypeMOL2Str:
          discrete = -1;        /* content-dependent behavior... */
        case cLoadTypeSDF2:     /* SDF files currently default to discrete */
        case cLoadTypeSDF2Str:
          break;
        default:
          discrete = 0;
          break;
      }
    }
  }

  // downstream file type reading functions
  switch (content_format) {
  case cLoadTypePQR:
    pdb_variant = PDB_VARIANT_PQR;
  case cLoadTypePDBQT:
    if (content_format == cLoadTypePDBQT)
      pdb_variant = PDB_VARIANT_PDBQT;
  case cLoadTypeVDBStr:
    if (ok && content_format == cLoadTypeVDBStr)
      pdb_variant = PDB_VARIANT_VDB;
  case cLoadTypePDB:
  case cLoadTypePDBStr:
    ok = ExecutiveProcessPDBFile(G, origObj, fname, content, object_name,
        state, discrete, finish, buf, pdb_variant,
        quiet, multiplex, zoom);
    break;
  case cLoadTypeCIF:
  case cLoadTypeCIFStr:
    obj = (CObject *) ObjectMoleculeReadCifStr(G, (ObjectMolecule *) origObj,
        content, state, discrete, quiet, multiplex, zoom);
    break;
  case cLoadTypeMMTF:
  case cLoadTypeMMTFStr:
    obj = (CObject *) ObjectMoleculeReadMmtfStr(G, (ObjectMolecule *) origObj,
        content, size, state, discrete, quiet, multiplex, zoom);
    break;
  case cLoadTypeMAE:
  case cLoadTypeMAEStr:
    PRINTFB(G, FB_CCmd, FB_Errors)
      " Incentive-Only-Error: 'mae' format not supported by this PyMOL build\n"
      ENDFB(G);
    ok = false;
    break;
  case cLoadTypeTOP:
    if(origObj) {
      /* always reinitialize topology objects from scratch */
      ExecutiveDelete(G, origObj->Name);
      origObj = NULL;
    }
    obj = (CObject *) ObjectMoleculeLoadTOPFile(G, NULL, fname, state, discrete);
    break;
  case cLoadTypeTRJ:
    if(origObj) {
      ObjectMoleculeLoadTRJFile(G, (ObjectMolecule *) origObj, fname, state,
          1, 1, 1, -1, -1, NULL, 1, NULL, quiet);
    } else {
      PRINTFB(G, FB_CCmd, FB_Errors)
        "CmdLoad-Error: must load object topology before loading trajectory!" ENDFB(G);
      ok = false;
    }
    break;
  case cLoadTypeCRD:
    if(origObj) {
      ObjectMoleculeLoadRSTFile(G, (ObjectMolecule *) origObj, fname, state, quiet, 1);
    } else {
      PRINTFB(G, FB_CCmd, FB_Errors)
        "CmdLoad-Error: must load object topology before loading coordinate file!"
        ENDFB(G);
      ok = false;
    }
    break;
  case cLoadTypeRST:
    if(origObj) {
      ObjectMoleculeLoadRSTFile(G, (ObjectMolecule *) origObj, fname, state, quiet, 0);
    } else {
      PRINTFB(G, FB_CCmd, FB_Errors)
        "CmdLoad-Error: must load object topology before loading restart file!"
        ENDFB(G);
      ok = false;
    }
    break;
  case cLoadTypePMO:
    PRINTFB(G, FB_CCmd, FB_Errors)
      "CmdLoad-Error: PMO format no longer supported\n" ENDFB(G);
    ok = false;
    break;
  case cLoadTypeDXMap:
    obj = (CObject *) ObjectMapLoadDXFile(G, (ObjectMap *) origObj, fname,
        state, quiet);
    break;
  case cLoadTypeFLDMap:
    obj = (CObject *) ObjectMapLoadFLDFile(G, (ObjectMap *) origObj, fname,
        state, quiet);
    break;
  case cLoadTypeBRIXMap:
    obj = (CObject *) ObjectMapLoadBRIXFile(G, (ObjectMap *) origObj, fname,
        state, quiet);
    break;
  case cLoadTypeGRDMap:
    obj = (CObject *) ObjectMapLoadGRDFile(G, (ObjectMap *) origObj, fname,
        state, quiet);
    break;
  case cLoadTypeACNTMap:
    obj = (CObject *) ObjectMapLoadACNTFile(G, (ObjectMap *) origObj, fname,
        state, quiet);
    break;
  case cLoadTypeXPLORMap:
  case cLoadTypeXPLORStr:
    obj = (CObject *) ObjectMapLoadXPLOR(G, (ObjectMap *) origObj, content,
        state, false, quiet);
    break;
  case cLoadTypePHIMap:
  case cLoadTypePHIStr:
    obj = (CObject *) ObjectMapLoadPHI(G, (ObjectMap *) origObj, content,
        state, true, size, quiet);
    break;
  case cLoadTypeCCP4Map:
  case cLoadTypeCCP4Str:
    obj = (CObject *) ObjectMapLoadCCP4(G, (ObjectMap *) origObj, content,
        state, true, size, quiet);
    break;
  case cLoadTypeCGO:
    obj = (CObject *) ObjectCGOFromFloatArray(G, (ObjectCGO *) origObj,
        (float *) content, size, state,
        quiet);
    break;
  case cLoadTypeMOL:
  case cLoadTypeMOLStr:
  case cLoadTypeMOL2:
  case cLoadTypeMOL2Str:
  case cLoadTypeSDF2:
  case cLoadTypeSDF2Str:
  case cLoadTypeXYZ:
  case cLoadTypeXYZStr:
  case cLoadTypeMMD:
  case cLoadTypeMMDStr:
    {
      const char * next_entry = content;
      char new_name[WordLength] = "";

      OVLexicon *loadproplex = NULL;
      bool loadpropertiesall = false;

      // (some of) these file types support multiple molecules per file,
      // and we support to load them into separate objects (multiplex).
      do {
        obj = (CObject *) ObjectMoleculeReadStr(G, (ObjectMolecule *) origObj,
            &next_entry, content_format,
            state, discrete,
            quiet, multiplex, new_name,
            loadpropertiesall, loadproplex);

        if(new_name[0]) {
          // multiplexing
          ObjectSetName(obj, new_name);
          ExecutiveDelete(G, obj->Name);       // just in case there is a collision
          ExecutiveManageObject(G, obj, zoom, true);
          new_name[0] = 0;
          obj = NULL;
        }
      } while(next_entry);

      OVLexicon_Del(loadproplex);
    }
    break;
  default:
    if(plugin[0]) {
      obj = PlugIOManagerLoad(G, origObj ? &origObj : NULL, fname, state, quiet, plugin);
    } else {
      PRINTFB(G, FB_Executive, FB_Errors)
        "ExecutiveLoad-Error: unable to read that file type from C (%d, '%s')\n",
        content_format, plugin ENDFB(G);
      return false;
    }
  }

  if(origObj && obj) {
    if(finish)
      ExecutiveUpdateObjectSelection(G, origObj);

    if(fname)
      sprintf(buf, " CmdLoad: \"%s\" appended into object \"%s\", state %d.\n",
          fname, object_name, state + 1);
  } else if(obj) {
    ObjectSetName(obj, object_name);
    ExecutiveManageObject(G, obj, zoom, true);

    if(fname)
      sprintf(buf, " CmdLoad: \"%s\" loaded as \"%s\".\n", fname, obj->Name);
    else
      sprintf(buf, " CmdLoad: loaded as \"%s\".\n", obj->Name);
  }

  mfree(buffer);

  if(!quiet && buf[0]) {
    PRINTFB(G, FB_Executive, FB_Actions)
      "%s", buf ENDFB(G);
  }

#ifndef _PYMOL_NO_UNDO
#endif

  return (ok);

}

/* ExecutiveGetExistingCompatible
 *
 * PARAMS
 *  oname -- object name
 *  type  -- new object type
 *
 * RETURNS
 *  (CObject *) Base-class object ptr
 *
 * SIDE EFFECTS
 *  If an object with the same name but different type already exists,
 *  then it is deleted.
 */
CObject *ExecutiveGetExistingCompatible(PyMOLGlobals * G, const char *oname, int type)
{
  CObject *origObj = NULL;
  origObj = ExecutiveFindObjectByName(G, oname);
  /* check for existing object of right type, delete if not */
  if(origObj) {
    int new_type = -1;
    switch (type) {
    case cLoadTypePlugin:
      // let PlugIOManager delete incompatible objects
      return origObj;
    case cLoadTypeChemPyModel:
    case cLoadTypePDB:
    case cLoadTypePDBStr:
    case cLoadTypeVDBStr:
    case cLoadTypeCIF:
    case cLoadTypeCIFStr:
    case cLoadTypeMMTF:
    case cLoadTypeMMTFStr:
    case cLoadTypeXYZ:
    case cLoadTypeXYZStr:
    case cLoadTypeMOL:
    case cLoadTypeMOLStr:
    case cLoadTypeMMD:
    case cLoadTypeMMDSeparate:
    case cLoadTypeMMDStr:
    case cLoadTypeTOP:
    case cLoadTypeTRJ:
    case cLoadTypeCRD:
    case cLoadTypeRST:
    case cLoadTypeMOL2:
    case cLoadTypeMOL2Str:
    case cLoadTypeSDF2:
    case cLoadTypeSDF2Str:
    case cLoadTypePQR:
    case cLoadTypePDBQT:
    case cLoadTypeXTC:
    case cLoadTypeDTR:
    case cLoadTypeTRR:
    case cLoadTypeGRO:
    case cLoadTypeTRJ2:
    case cLoadTypeG96:
    case cLoadTypeDCD:
      new_type = cObjectMolecule;
      break;
    case cLoadTypeChemPyBrick:
    case cLoadTypeChemPyMap:
    case cLoadTypeXPLORMap:
    case cLoadTypeXPLORStr:
    case cLoadTypeCCP4Map:
    case cLoadTypeCCP4Str:
    case cLoadTypeFLDMap:
    case cLoadTypeBRIXMap:
    case cLoadTypeGRDMap:
    case cLoadTypeDXMap:
      new_type = cObjectMap;
      break;
    case cLoadTypeCallback:
      new_type = cObjectCallback;
      break;
    case cLoadTypeCGO:
      new_type = cObjectCGO;
      break;
    }
    if(new_type == -1 || new_type != origObj->type) {
      ExecutiveDelete(G, origObj->Name);
      origObj = NULL;
    }
  }
  return origObj;
}

int ExecutiveProcessPDBFile(PyMOLGlobals * G, CObject * origObj,
                            const char *fname, const char *buffer,
                            const char *oname, int frame, int discrete, int finish,
                            OrthoLineType buf, int variant, int quiet,
                            int multiplex, int zoom)
{
  int ok = true;
  CObject *obj;
  char pdb_name[WordLength] = "";
  char cur_name[WordLength] = "";
  const char *next_pdb = NULL;
  int repeat_flag = true;
  ProcPDBRec *processed = NULL;
  int n_processed = 0;
  int m4x_mode = 0;             /* 0 = annotate, 1 = alignment */
  ProcPDBRec *target_rec = NULL;
  char nbrhood_sele[] = "m4x_nearby";
  ProcPDBRec *current = NULL;
  PDBInfoRec pdb_info_rec, *pdb_info = NULL;
  int model_number;
  CObject *deferred_zoom_obj = NULL;

  UtilZeroMem(&pdb_info_rec, sizeof(PDBInfoRec));
  pdb_info = &pdb_info_rec;
  pdb_info->multiplex = multiplex;
  pdb_info->variant = variant;

  if(ok) {
    processed = VLACalloc(ProcPDBRec, 10);
  }
  while(repeat_flag && ok) {
    const char *start_at = buffer;
    int is_repeat_pass = false;
    int eff_frame = frame;
    int is_new = false;
    CObject *tmpObj;

    VLACheck(processed, ProcPDBRec, n_processed);
    current = processed + n_processed;

    PRINTFD(G, FB_CCmd) " ExecutiveProcessPDBFile-DEBUG: loading PDB\n" ENDFD;

    if(next_pdb) {
      start_at = next_pdb;
      is_repeat_pass = true;
    }

    M4XAnnoInit(&current->m4x);

    repeat_flag = false;
    next_pdb = NULL;
    if(!origObj) {

      is_new = true;
      pdb_name[0] = 0;
      model_number = 0;
      obj = (CObject *) ObjectMoleculeReadPDBStr(G, (ObjectMolecule *) origObj,
                                                 start_at, eff_frame, discrete,
                                                 &current->m4x, pdb_name,
                                                 &next_pdb, pdb_info, quiet,
                                                 &model_number);

    } else {
      model_number = 0;
      ObjectMoleculeReadPDBStr(G, (ObjectMolecule *) origObj,
                               start_at, eff_frame, discrete, &current->m4x,
                               pdb_name, &next_pdb, pdb_info, quiet, &model_number);

      if(finish) {
        ExecutiveUpdateObjectSelection(G, origObj);
        ExecutiveDoZoom(G, origObj, false, zoom, quiet);
      }
      if(eff_frame < 0)
        eff_frame = ((ObjectMolecule *) origObj)->NCSet - 1;
      if(buf) {
        if(fname)
          sprintf(buf, " CmdLoad: \"%s\" appended into object \"%s\", state %d.\n",
                  fname, oname, eff_frame + 1);
        else
          sprintf(buf, " CmdLoad: PDB-string appended into object \"%s\", state %d.\n",
                  oname, eff_frame + 1);
      }
      obj = origObj;
    }

    if(obj) {
      if(next_pdb) {
        /* NOTE: if set, assume that multiple PDBs are present in the file */
        repeat_flag = true;
      }
    }

    if(is_new) {
      if(obj) {
        if(current->m4x.xname_flag) {   /* USER XNAME trumps the PDB Header name */
          ObjectSetName(obj, current->m4x.xname);       /* from PDB */
          if((tmpObj = ExecutiveFindObjectByName(G, obj->Name))) {
            if(tmpObj->type != cObjectMolecule)
              ExecutiveDelete(G, current->m4x.xname);   /* just in case */
            else {
              if(is_repeat_pass) {
                /* this is a workaround for when PLANET accidentally duplicates the target */
                {
                  int a;
                  for(a = 0; a < n_processed; a++) {
                    ProcPDBRec *cur = processed + a;
                    if(cur->obj == (ObjectMolecule *) tmpObj) {
                      cur->m4x.invisible = false;
                    }
                  }
                }
                ObjectMoleculeFree((ObjectMolecule *) obj);
                obj = NULL;
              }
            }
          }
        } else if(next_pdb) {
          if(pdb_name[0] == 0) {
            if(cur_name[0]) {
              sprintf(pdb_name, "%s_%04d", cur_name, n_processed + 1);
            } else {
              sprintf(pdb_name, "%s_%04d", oname, n_processed + 1);
            }
          } else if(multiplex > 0) {
            if(pdb_info->multi_object_status == 1) {    /* this is a multi-object PDB file */
              strcpy(cur_name, pdb_name);
            } else if(cur_name[0] == 0) {
              strcpy(cur_name, oname);
            }
            if(model_number > 0) {
              sprintf(pdb_name, "%s_%04d", cur_name, model_number);
            } else {
              sprintf(pdb_name, "%s_%04d", cur_name, n_processed + 1);
            }
          }
          ObjectSetName(obj, pdb_name);
          ExecutiveDelete(G, obj->Name); /* just in case */
        } else {
          if(is_repeat_pass) {
            if(pdb_name[0] == 0) {
              if(cur_name[0]) {
                sprintf(pdb_name, "%s_%04d", cur_name, n_processed + 1);
              } else {
                sprintf(pdb_name, "%s_%04d", oname, n_processed + 1);
              }
            } else if(multiplex > 0) {
              if(pdb_info->multi_object_status == 1) {  /* this is a multi-object PDB file */
                strcpy(cur_name, pdb_name);
              } else if(cur_name[0] == 0) {
                strcpy(cur_name, oname);
              }
              if(model_number > 0) {
                sprintf(pdb_name, "%s_%04d", cur_name, model_number);
              } else {
                sprintf(pdb_name, "%s_%04d", cur_name, n_processed + 1);
              }
            }
            ObjectSetName(obj, pdb_name);       /* from PDB */
            ExecutiveDelete(G, obj->Name);       /* just in case */
          } else {
            ObjectSetName(obj, oname);  /* from filename/parameter */
          }
        }

        if(obj) {
          int do_zoom = repeat_flag ? 0 : zoom;
          if(do_zoom != zoom)
            deferred_zoom_obj = obj;
          else
            deferred_zoom_obj = NULL;
          ExecutiveManageObject(G, obj, do_zoom, true);
          if(eff_frame < 0)
            eff_frame = ((ObjectMolecule *) obj)->NCSet - 1;
          if(buf) {
            if(n_processed < 1) {
              if(fname)
                sprintf(buf, " CmdLoad: \"%s\" loaded as \"%s\".\n", fname, oname);
              else
                sprintf(buf,
                        " CmdLoad: PDB-string loaded into object \"%s\", state %d.\n",
                        oname, eff_frame + 1);
            } else {
              if(fname) {
                sprintf(buf, " CmdLoad: loaded %d objects from \"%s\".\n",
                        n_processed + 1, fname);
              } else {
                sprintf(buf, " CmdLoad: loaded %d objects from string.\n",
                        n_processed + 1);
              }
            }
          }

        }
      }
    }

    if(obj && current) {
      current->obj = (ObjectMolecule *) obj;
      n_processed++;
    }
  }

  if(deferred_zoom_obj) {
    ExecutiveDoZoom(G, deferred_zoom_obj, true, zoom, true);
  }

  /* BEGIN METAPHORICS ANNOTATION AND ALIGNMENT CODE */

  /* sanity check -- make sure all objects are present */
  if(ok && n_processed) {
    int a;
    for(a = 0; a < n_processed; a++) {
      ProcPDBRec *current = processed + a;
      if(!ExecutiveValidateObjectPtr(G, (CObject *) current->obj, cObjectMolecule)) {
        PRINTFB(G, FB_Executive, FB_Errors)
          " Error: Missing object! possible invalid/corrupt file.\n" ENDFB(G);
        ok = false;
        break;
      }
    }
  }

  if(ok && n_processed) {       /* first, perform any Metaphorics alignment */
    /* is there a target structure? */
    {
      int a;
      for(a = 0; a < n_processed; a++) {
        ProcPDBRec *current = processed + a;
        M4XAnnoType *m4x = &current->m4x;

        if(m4x->annotated_flag && m4x->align) {
          if(WordMatchExact(G, current->obj->Obj.Name, m4x->align->target, true)) {
            target_rec = current;
            break;
          }
        }
      }
    }
    if(target_rec) {            /* there is a target.. */

      /* first, convert all IDs to genuine atom indices */

      {
        int a;
        for(a = 0; a < n_processed; a++) {
          ProcPDBRec *current = processed + a;
          M4XAnnoType *m4x = &current->m4x;
          if(m4x->align) {
            ObjectMoleculeConvertIDsToIndices(current->obj,
                                              m4x->align->id_at_point,
                                              m4x->align->n_point);
          }
        }
      }

      /* next, peform the alignments against the target */

      {
        int a;
        char aligned_name[] = "m4x_aligned";
        char tmp_sele[WordLength * 4];

        SelectorCreateEmpty(G, "m4x_aligned", -1);

        for(a = 0; a < n_processed; a++) {
          ProcPDBRec *current = processed + a;
          if(current != target_rec) {
            M4XAnnoType *m4x = &current->m4x;
            if(m4x->align) {
              ObjMolPairwise pairwise;

              m4x_mode = 1;     /* performing an alignment */

              ObjMolPairwiseInit(&pairwise);
              pairwise.trg_obj = target_rec->obj;
              pairwise.mbl_obj = current->obj;

              /* create ordered matches */

              {
                M4XAlignType *trg_align = target_rec->m4x.align;
                M4XAlignType *mbl_align = m4x->align;

                int n_point;
                int a;

                n_point = trg_align->n_point;
                if(n_point > mbl_align->n_point)
                  n_point = mbl_align->n_point;

                VLACheck(pairwise.trg_vla, int, n_point);
                VLACheck(pairwise.mbl_vla, int, n_point);

                for(a = 0; a < n_point; a++) {
                  int trg_index = trg_align->id_at_point[a];
                  int mbl_index = mbl_align->id_at_point[a];
                  if((trg_index >= 0) && (mbl_index >= 0) &&
                     (mbl_align->fitness[a] >= 0.0F)) {
                    pairwise.trg_vla[pairwise.n_pair] = trg_index;
                    pairwise.mbl_vla[pairwise.n_pair] = mbl_index;
                    pairwise.n_pair++;
                  }
                }

                {
                  char trg_sele[WordLength], mbl_sele[WordLength];
                  char align_name[WordLength];
                  SelectorGetUniqueTmpName(G, trg_sele);
                  SelectorGetUniqueTmpName(G, mbl_sele);

                  SelectorCreateOrderedFromObjectIndices(G, trg_sele, pairwise.trg_obj,
                                                         pairwise.trg_vla,
                                                         pairwise.n_pair);
                  SelectorCreateOrderedFromObjectIndices(G, mbl_sele, pairwise.mbl_obj,
                                                         pairwise.mbl_vla,
                                                         pairwise.n_pair);

                  sprintf(align_name, "%s_%s_alignment",
                          pairwise.trg_obj->Obj.Name, pairwise.mbl_obj->Obj.Name);

                  ExecutiveRMS(G, mbl_sele, trg_sele, 2, 0.0F, 0, 0,
                               align_name, 0, 0, true, 0, NULL);
                  ExecutiveColor(G, align_name, "white", 0, true);
                  if(target_rec->m4x.invisible)
                    sprintf(tmp_sele, "(%s) | (%s)", aligned_name, mbl_sele);
                  else
                    sprintf(tmp_sele, "(%s) | (%s) | (%s)", aligned_name, trg_sele,
                            mbl_sele);
                  SelectorCreateSimple(G, aligned_name, tmp_sele);
                  /*ExecutiveDelete(G,trg_sele);
                     ExecutiveDelete(G,mbl_sele); */
                }

              }
              ObjMolPairwisePurge(&pairwise);
            }
          }
        }
        sprintf(tmp_sele, "bychain %s", aligned_name);
        SelectorCreateSimple(G, aligned_name, tmp_sele);
        sprintf(tmp_sele, "byres (%s expand 3.5)", aligned_name);
        SelectorCreateSimple(G, nbrhood_sele, tmp_sele);
      }
    }
  }

  if(ok && n_processed) {       /* next, perform any and all Metaphorics annotations */
    int a;
    int nbr_sele = SelectorIndexByName(G, nbrhood_sele);

    for(a = 0; a < n_processed; a++) {
      ProcPDBRec *current = processed + a;
      if(current->m4x.annotated_flag) {
        char annotate_script[] = "@$PYMOL_SCRIPTS/metaphorics/annotate.pml";
        char align_script[] = "@$PYMOL_SCRIPTS/metaphorics/alignment.pml";
        char *script_file = NULL;

        if(a == (n_processed - 1)) {
          /* for multi-PDB files, don't execute script until after the last file */
          switch (m4x_mode) {
          case 0:
            script_file = annotate_script;
            break;
          case 1:
            script_file = align_script;
            break;
          }
        }

        if((current != target_rec) || (!current->m4x.invisible)) {
          /* suppress annotations if target invisible */
          ObjectMoleculeM4XAnnotate(current->obj, &current->m4x, script_file,
                                    (m4x_mode == 1), nbr_sele);
        }
        M4XAnnoPurge(&current->m4x);
      }
    }
  }
  /* END METAPHORICS ANNOTATION AND ALIGNMENT CODE */

  VLAFreeP(processed);
  return ok;
}

int ExecutiveAssignSS(PyMOLGlobals * G, const char *target, int state, const char *context,
                      int preserve, ObjectMolecule * single_object, int quiet)
{
  int sele0 = -1;
  int sele1 = -1;
  int ok = false;
  sele0 = SelectorIndexByName(G, target);
  if(sele0 >= 0) {
    if((!context) || (!context[0])) {
      sele1 = sele0;
    } else {
      sele1 = SelectorIndexByName(G, context);
    }
    if(sele1 >= 0) {
      ok = SelectorAssignSS(G, sele0, sele1, state, preserve, single_object, quiet);
    }
  }
  return (ok);
}

static int * getRepArrayFromBitmask(int visRep);

PyObject *ExecutiveGetVisAsPyDict(PyMOLGlobals * G)
{
  PyObject *result = NULL, *list;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  result = PyDict_New();
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->name[0] != '_') {
      list = PyList_New(4);
      PyList_SetItem(list, 0, PyInt_FromLong(rec->visible));

      PyList_SetItem(list, 1, PyList_New(0));

      if(rec->type != cExecObject) {
        PyList_SetItem(list, 2, PConvAutoNone(Py_None));
        PyList_SetItem(list, 3, PConvAutoNone(Py_None));
      } else {
        auto vla = getRepArrayFromBitmask(rec->obj->visRep);
        PyList_SetItem(list, 2, PConvIntVLAToPyList(vla));
        VLAFreeP(vla);

        PyList_SetItem(list, 3, PyInt_FromLong(rec->obj->Color));
      }

      PyDict_SetItemString(result, rec->name, list);
      Py_DECREF(list);
    }
  }
  return (result);
}

static int * getRepArrayFromBitmask(int visRep) {
  int n_vis = 0;
  int *RepVis = VLACalloc(int, cRepCnt);

  for(int a = 0; a < cRepCnt; a++)
    if(GET_BIT(visRep, a))
      RepVis[n_vis++] = a;

  VLASize(RepVis, int, n_vis);
  return RepVis;
}

#ifdef _PYMOL_LIB
/*
 * Returns a list (VLA) of enabled atom representations (AtomInfoType.visRep)
 * in selection (e.g. {cRepLine, cRepNonbonded})
 */
int *ExecutiveGetRepsInSceneForObject(PyMOLGlobals *G, const char *name){
  int visRep = 0;

  for (SeleAtomIterator iter(G, name); iter.next();) {
    AtomInfoType * ai = iter.getAtomInfo();
    visRep |= ai->visRep;
  }

  return getRepArrayFromBitmask(visRep);
}

/*
 * Returns a list (VLA) of enabled object representations (rec->obj->visRep)
 * (e.g. {cRepCell, cRepExtent})
 */
int *ExecutiveGetRepsForObject(PyMOLGlobals *G, const char *name){
  SpecRec *rec = ExecutiveFindSpec(G, (char*)name);

  if(rec)
    return getRepArrayFromBitmask(rec->obj->visRep);

  return NULL;
}
#endif

int ExecutiveSetVisFromPyDict(PyMOLGlobals * G, PyObject * dict)
{
#ifdef _PYMOL_NOPY
  return 0;
#else

  int ok = true;
  WordType name;
  PyObject *key, *list, *col;
  PyObject *vis_list = NULL;
  Py_ssize_t pos = 0;
  SpecRec *rec, *grec, **recstack = NULL;
  int n_vis;
  int rep;
  int a;
  int ll = 0;
  if(ok)
    ok = (dict != NULL);
  if(ok)
    ok = PyDict_Check(dict);
  if(ok) {

    SceneObjectDel(G, NULL, true);    /* remove all objects from scene */
    ExecutiveInvalidateSceneMembers(G);

    // stack for putative visible records
    recstack = Calloc(SpecRec*, PyDict_Size(dict) + 1);

    while(PyDict_Next(dict, &pos, &key, &list)) {
      if(!PConvPyStrToStr(key, name, sizeof(WordType))) {
        ok = false;
      } else {
        rec = ExecutiveFindSpec(G, name);
        if(rec) {
          if(ok)
            ok = (list != NULL);
          if(ok)
            ok = PyList_Check(list);
          if(ok)
            ll = PyList_Size(list);
          if(ok)
            ok = (ll >= 2);
          if(ok)
            ok = PConvPyObjectToInt(PyList_GetItem(list, 0), &rec->visible);

          /* before version 1.8 item 1 was rec reps (repOn) */

          if(ok && (rec->type == cExecObject)) {        /* object properties */

            if(ll > 2) {        /* object visibility */
              vis_list = PyList_GetItem(list, 2);
              if(ok)
                ok = (vis_list != NULL);
              if(ok) {
                if(PyList_Check(vis_list)) {
                  n_vis = PyList_Size(vis_list);
                  rec->obj->visRep = 0;
                  for(a = 0; a < n_vis; a++) {
                    if(PConvPyObjectToInt(PyList_GetItem(vis_list, a), &rep)) {
                      if((rep >= 0) && (rep < cRepCnt))
                        SET_BIT(rec->obj->visRep, rep);
                    }
                  }
                } else if (PyInt_Check(vis_list)) {
                  PConvPyObjectToInt(vis_list, &rec->obj->visRep);
                }
              }
            }
            if(ll > 3) {        /* object color */
              col = PyList_GetItem(list, 3);
              if(ok)
                ok = (col != NULL);
              if(ok)
                if(PyInt_Check(col)) {
                  ok = PConvPyObjectToInt(col, &rec->obj->Color);
                  if(rec->obj->fInvalidate)
                    rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvColor, -1);
                }
            }
          }
          if(rec->visible && (rec->type == cExecObject)) {
            (*(++recstack)) = rec;
          }
        }
      }
    }

    // add visible objects to scene
    for(; (rec = *recstack); recstack--) {
      // check visibility of all parent groups
      for(grec = rec; grec->visible && (grec = grec->group););
      if(!grec) {
        // ok, no invisible parent found
        rec->in_scene = SceneObjectAdd(G, rec->obj);
        ExecutiveInvalidateSceneMembers(G);
      }
    }
    mfree(recstack);
  }
  return ok;
#endif
}

/*
 * returns a pointer to the data in a volume or map object
 */
CField * ExecutiveGetVolumeField(PyMOLGlobals * G, const char * objName, int state) {
  ObjectMapState *oms;
  CObject *obj;

  obj = ExecutiveFindObjectByName(G, objName);
  ok_assert(1, obj);

  switch (obj->type) {
  case cObjectVolume:
    return ObjectVolumeGetField((ObjectVolume *) obj);
  case cObjectMap:
    oms = ObjectMapGetState((ObjectMap *) obj, state);
    ok_assert(1, oms && oms->Field);
    return oms->Field->data;
  }

ok_except1:
  return NULL;
}

/*
 * returns allocated memory
 */
float * ExecutiveGetHistogram(PyMOLGlobals * G, const char * objName, int n_points, float min_val, float max_val) {
  CObject *obj;
  ObjectMapState *oms = NULL;

  obj = ExecutiveFindObjectByName(G, objName);
  ok_assert(1, obj);

  switch (obj->type) {
  case cObjectMap:
    oms = ObjectMapGetState((ObjectMap *) obj, 0);
    break;
  case cObjectVolume:
    oms = ObjectVolumeGetMapState((ObjectVolume *) obj);
    break;
  default:
    PRINTFB(G, FB_Executive, FB_Errors)
      " GetHistogram-Error: wrong object type." ENDFB(G);
  }

  if(oms) {
    float *hist = Calloc(float, n_points + 4);
    float range = SettingGet_f(G, obj->Setting, NULL, cSetting_volume_data_range);
    ObjectMapStateGetHistogram(G, oms, n_points, range, hist, min_val, max_val);
    return hist;
  }

ok_except1:
  return NULL;
}

PyObject* ExecutiveGetVolumeRamp(PyMOLGlobals * G, const char * objName) {
#ifdef _PYMOL_NOPY
  return NULL;
#else
  CObject *obj;
  PyObject* result = NULL;

  PRINTFD(G, FB_Executive) "Executive-GetVolumeRamp Entered.\n" ENDFD;

  obj = ExecutiveFindObjectByName(G, objName);
  if(obj && obj->type==cObjectVolume) {
    result = ObjectVolumeGetRamp((ObjectVolume *) obj);
  }

  PRINTFD(G, FB_Executive) "Executive-GetVolumeRamp Exited.\n" ENDFD;

  return result;

#endif
}

int ExecutiveSetVolumeRamp(PyMOLGlobals * G, const char * objName, float *ramp_list, int list_size) {
  CObject *obj;
  int result = false;

  obj = ExecutiveFindObjectByName(G, objName);
  if(obj && obj->type==cObjectVolume) {
    result = ObjectVolumeSetRamp((ObjectVolume *) obj, ramp_list, list_size);
  }

  return result;
}

int ExecutiveIsolevel(PyMOLGlobals * G, const char *name, float level, int state, int query,
                      float *result, int quiet)
{
  int ok = true;
  CObject *obj;
  obj = ExecutiveFindObjectByName(G, name);
  if(obj) {
    switch (obj->type) {
    case cObjectMesh:
      if(!query) {
        ObjectMeshSetLevel((ObjectMesh *) obj, level, state, quiet);
        SceneChanged(G);
      } else if(result) {
        ok = ObjectMeshGetLevel((ObjectMesh *) obj, state, result);
      }
      break;
    case cObjectSurface:
      if(!query) {
        ObjectSurfaceSetLevel((ObjectSurface *) obj, level, state, quiet);
        SceneChanged(G);
      } else if(result) {
        ok = ObjectSurfaceGetLevel((ObjectSurface *) obj, state, result);
      }
      break;
    default:
      ok = false;
      PRINTFB(G, FB_Executive, FB_Errors)
        " Isolevel-Error: object \"%s\" is of wrong type.", name ENDFB(G);
      break;
    }
  }
  return (ok);

}

int ExecutiveSpectrum(PyMOLGlobals * G, const char *s1, const char *expr, float min, float max,
                      int first, int last, const char *prefix, int digits, int byres, int quiet,
                      float *min_ret, float *max_ret)
{
  int ok = true;
  int n_color, n_atom;
  ObjectMoleculeOpRec op;
  WordType buffer;
  int *color_index = NULL;
  float *value = NULL;
  int a, b;
  char pat[] = "%0Xd";
  int pref_len;
  char *at;
  float range;

  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  if(sele1 >= 0) {

    if(digits > 9)
      digits = 9;
    pat[2] = ('0' + digits);
    UtilNCopy(buffer, prefix, sizeof(WordType) - digits);

    pref_len = strlen(prefix);
    at = buffer + pref_len;

    n_color = abs(first - last) + 1;
    if(n_color) {
      color_index = Alloc(int, n_color);
      for(a = 0; a < n_color; a++) {
        b = first + ((last - first) * a) / (n_color - 1);
        sprintf(at, pat, b);
        color_index[a] = ColorGetIndex(G, buffer);
      }

      // set up iterator
      SeleAtomIterator iter(G, sele1);
      SelectorUpdateTable(G, cSelectorUpdateTableAllStates, -1);

      // count atoms
      for (n_atom = 0; iter.next();) {
        ++n_atom;
      }

      if(n_atom) {
        value = Calloc(float, n_atom);

        if(WordMatchExact(G, "count", expr, true)) {
          for(a = 0; a < n_atom; a++) {
            value[a] = (float) a + 1;
          }
        } else {
          if (WordMatchExact(G, "pc", expr, true)) {
            expr = "partial_charge";
          } else if (WordMatchExact(G, "resi", expr, true)) {
            expr = "resv";
          }

          // look up expression definition
          auto ap = PyMOL_GetAtomPropertyInfo(G->PyMOL, expr);
          if (!ap) {
            PRINTFB(G, FB_Executive, FB_Errors)
              " Spectrum-Error: Unknown expr '%s'\n", expr ENDFB(G);
            ok_raise(1);
          }

          // for enumerated values
          std::map<size_t, unsigned int> enumerated_values;
          union {
            size_t value_e;
            char   value_s[sizeof(size_t)];
          };

          for (a = 0, iter.reset(); iter.next(); ++a) {
            const auto ai = iter.getAtomInfo();
            const auto raw_ptr = reinterpret_cast<const char*>(ai) + ap->offset;

            // numeric values
            switch (ap->Ptype) {
              case cPType_float:
                value[a] = *reinterpret_cast<const float*>(raw_ptr);
                continue;
              case cPType_int:
              case cPType_int_custom_type:
                value[a] = *reinterpret_cast<const int*>(raw_ptr);
                continue;
              case cPType_schar:
                value[a] = *reinterpret_cast<const signed char*>(raw_ptr);
                continue;
              case cPType_char_as_type:
                value[a] = ai->hetatm;
                continue;
              case cPType_index:
                value[a] = iter.getAtm() + 1.f;
                continue;
            }

            // enumerated values
            switch (ap->Ptype) {
              case cPType_int_as_string:
                value_e = *reinterpret_cast<const lexidx_t*>(raw_ptr);
                break;
              case cPType_string:
                // works for small strings
                strncpy(value_s, raw_ptr, sizeof(value_e));
                break;
              case cPType_model:
                value_e = (size_t) iter.obj;
                break;
              default:
                PRINTFB(G, FB_Executive, FB_Errors)
                  " Spectrum-Error: Unsupported Ptype for expr '%s'\n", expr ENDFB(G);
                ok_raise(1);
            }

            // lookup or insert value
            auto& e = enumerated_values[value_e];
            if (e == 0)
              e = enumerated_values.size();
            value[a] = e - 1.f;
          }

          if (!quiet && !enumerated_values.empty()) {
            PRINTFB(G, FB_Executive, FB_Actions)
              " Spectrum: Expression is non-numeric, enumerating values\n" ENDFB(G);
          }
        }

        if(max < min) {
          max = value[0];
          min = value[0];
          for(a = 1; a < n_atom; a++) {
            if(value[a] < min)
              min = value[a];
            if(value[a] > max)
              max = value[a];
          }
        }
        range = max - min;

        if(!quiet) {
          PRINTFB(G, FB_Executive, FB_Actions)
            " Spectrum: range (%8.5f to %8.5f).\n", min, max ENDFB(G);
        }
        if(range == 0.0F)
          range = 1.0F;
        *min_ret = min;
        *max_ret = max;

        op.code = OMOP_Spectrum;
        op.i1 = n_color - 1;
        op.i2 = n_atom;
        op.i3 = 0;
        op.i4 = byres;
        op.ii1 = color_index;
        op.ff1 = value;
        op.f1 = min;
        op.f2 = range;

        ExecutiveObjMolSeleOp(G, sele1, &op);

        op.code = OMOP_INVA;
        op.i1 = cRepBitmask;
        op.i2 = cRepInvColor;
        ExecutiveObjMolSeleOp(G, sele1, &op);

      }
    }

ok_except1:
    FreeP(color_index);
    FreeP(value);
  }
  return (ok);
}

static int fStrOrderFn(const char ** array, int l, int r) {
  return strcmp(array[l], array[r]) < 0;
}

/*
 * Returns an VLA with pointers into G->Lexicon
 */
const char **ExecutiveGetChains(PyMOLGlobals * G, const char *sele, int state)
{
  const char **result = NULL;
  std::set<ov_word> chains;
  int c = 0;
  ObjectMoleculeOpRec op;

  SelectorTmp tmpsele1(G, sele);
  int sele1 = tmpsele1.getIndex();

  if(sele1 >= 0) {

    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_GetChains;
    op.ii1 = (int*) (void*) &chains; // pointer pack
    op.i1 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op);
    result = VLAlloc(const char*, chains.size());
    for (std::set<ov_word>::iterator it = chains.begin(),
        it_end = chains.end(); it != it_end; ++it) {
      result[c++] = LexStr(G, *it);
    }
    // sort the array
    UtilSortInPlace(G, result, chains.size(), sizeof(char *),
        (UtilOrderFn *) fStrOrderFn);
  } else {
    ErrMessage(G, "ExecutiveGetChains", "Bad selection.");
  }
  return (result);
}

int ExecutiveValidateObjectPtr(PyMOLGlobals * G, CObject * ptr, int object_type)
{
  /* this routine needs to be sped up significantly... */

  CExecutive *I = G->Executive;
  int ok = false;
  SpecRec *rec = NULL;

  while(ListIterate(I->Spec, rec, next)) {
    if(rec->obj == ptr) {
      if(rec->type == cExecObject) {
        if((!object_type) || (rec->obj->type == object_type)) {
          ok = true;
          break;
        }
      }
    }
  }
  return (ok);
}

int ExecutiveRampNew(PyMOLGlobals * G, const char *name, const char *src_name,
                     float *range, float *color,
                     int src_state, const char *sele, float beyond,
                     float within, float sigma, int zero, int calc_mode, int quiet)
{
  ObjectGadgetRamp *obj = NULL;
  ObjectGadgetRamp *origRamp = NULL;
  CObject *src_obj = NULL;
  CObject *origObj = ExecutiveFindObjectByName(G, name);
  float *vert_vla = NULL;
  int rampType = -1;

  if (origObj &&
      origObj->type == cObjectGadget &&
      ((ObjectGadget*)origObj)->GadgetType == cGadgetRamp) {
    origRamp = (ObjectGadgetRamp*)origObj;
    rampType = origRamp->RampType;
  } else if (!range || !(color || calc_mode)) {
    PRINTFB(G, FB_Executive, FB_Errors)
      " ExecutiveRampNew-Error: missing 'range' or 'color' to create new ramp.\n" ENDFB(G);
    return false;
  }

  if (src_name && src_name[0]) {
    if (WordMatchExact(G, src_name, cKeywordNone, true)) {
      rampType = cRampNone;
    } else {
      src_obj = ExecutiveFindObjectByName(G, src_name);
      if(src_obj) {
        switch (src_obj->type) {
          case cObjectMap:
            rampType = cRampMap;
            break;
          case cObjectMolecule:
            rampType = cRampMol;
            break;
          default:
            PRINTFB(G, FB_Executive, FB_Errors)
              "ExecutiveRampNew: Error: object '%s' is not a map or molecule.\n", src_name
              ENDFB(G);
            return false;
        }
      } else {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExecutiveRampNew: Error: object '%s' not found.\n", src_name ENDFB(G);
        return false;
      }
    }
  }

  switch (rampType) {
    case cRampMap:
      /* mapping this ramp from a selection */
      if(sele && sele[0]) {
        vert_vla = ExecutiveGetVertexVLA(G, sele, src_state);
      }
      obj = ObjectGadgetRampMapNewAsDefined(G, origRamp, (ObjectMap *) src_obj,
          range, color, src_state,
          vert_vla, beyond, within,
          sigma, zero, calc_mode);
      VLAFreeP(vert_vla);
      break;
    case cRampNone:
    case cRampMol:
      obj = ObjectGadgetRampMolNewAsDefined(G, origRamp, (ObjectMolecule *) src_obj,
          range, color, src_state,
          calc_mode);
      break;
    default:
      PRINTFB(G, FB_Executive, FB_Errors)
        " ExecutiveRampNew-Error: missing 'name' to create new ramp.\n" ENDFB(G);
      return false;
  }

  if (!obj)
    return false;

  if (obj != origRamp) {
    ExecutiveDelete(G, name);
    ObjectSetName((CObject *) obj, name);
    ColorRegisterExt(G, ((CObject *) obj)->Name, (void *) obj, cColorGadgetRamp);
    ExecutiveManageObject(G, (CObject *) obj, false, quiet);
  }

  ExecutiveInvalidateRep(G, cKeywordAll, cRepAll, cRepInvColor);      /* recolor everything */
  return true;
}

static int ExecutiveSetNamedEntries(PyMOLGlobals * G, PyObject * names, int version,
                                    int part_rest, int part_sess)
{
  CExecutive *I = G->Executive;
  int ok = true;
  int skip = false;
  int a = 0, l = 0, ll = 0;
  PyObject *cur, *el;
  SpecRec *rec = NULL;
  int extra_int;
  int incomplete = false;
  ObjectNameType new_name;

  if(ok)
    ok = (names != NULL);
  if(ok)
    ok = PyList_Check(names);
  if(ok)
    l = PyList_Size(names);

  while(ok && (a < l)) {
    cur = PyList_GetItem(names, a);
    if(cur != Py_None) {        /* skip over None w/o aborting */
      skip = false;
      rec = NULL;
      ListElemCalloc(G, rec, SpecRec);
      rec->next = NULL;
      rec->name[0] = 0;
      if(ok)
        ok = PyList_Check(cur);
      if(ok)
        ll = PyList_Size(cur);
      if(ok)
        ok = PConvPyStrToStr(PyList_GetItem(cur, 0), rec->name, sizeof(WordType));
      if(ok)
        ok = PConvPyIntToInt(PyList_GetItem(cur, 1), &rec->type);
      if(ok)
        ok = CPythonVal_PConvPyIntToInt_From_List(G, cur, 2, &rec->visible);

      /* before version 1.8 item 3 was rec reps (repOn) */

      if(ok)
        ok = PConvPyIntToInt(PyList_GetItem(cur, 4), &extra_int);
      switch (rec->type) {
      case cExecObject:
        if(!ok)
          break;

        el = PyList_GetItem(cur, 5);

        switch (extra_int) {
        case cObjectMolecule:
          ok = ObjectMoleculeNewFromPyList(G, el, (ObjectMolecule **) (void *) &rec->obj);
          break;
        case cObjectMeasurement:
          ok = ObjectDistNewFromPyList(G, el, (ObjectDist **) (void *) &rec->obj);
          break;
        case cObjectMap:
          ok = ObjectMapNewFromPyList(G, el, (ObjectMap **) (void *) &rec->obj);
          break;
        case cObjectMesh:
          ok = ObjectMeshNewFromPyList(G, el, (ObjectMesh **) (void *) &rec->obj);
          break;
        case cObjectSlice:
          ok = ObjectSliceNewFromPyList(G, el, (ObjectSlice **) (void *) &rec->obj);
          break;
        case cObjectSurface:
          ok = ObjectSurfaceNewFromPyList(G, el, (ObjectSurface **) (void *) &rec->obj);
          break;
        case cObjectCGO:
          ok = ObjectCGONewFromPyList(G, el, (ObjectCGO **) (void *) &rec->obj, version);
          break;
        case cObjectGadget:
          ok = ObjectGadgetNewFromPyList(G, el, (ObjectGadget **) (void *) &rec->obj, version);
          break;
        case cObjectAlignment:
          ok = ObjectAlignmentNewFromPyList(G, el, (ObjectAlignment **) (void *) &rec->obj,
                                              version);
          break;
        case cObjectGroup:
          if(part_rest) {
            // if group already exists, do not create new one
            CObject *obj = ExecutiveFindObjectByName(G, rec->name);
            if(obj && obj->type == cObjectGroup) {
              skip = 1;
              break;
            }
          }
          ok = ObjectGroupNewFromPyList(G, el, (ObjectGroup **) (void *) &rec->obj, version);
          break;
        case cObjectVolume:
          ok = ObjectVolumeNewFromPyList(G, el, (ObjectVolume **) (void *) &rec->obj);
          break;
#ifndef _PYMOL_NOPY
        case cObjectCallback:
          // skip dummy entries from old sessions and failed-to-pickle sessions
          skip = !ObjectCallbackNewFromPyList(G, el, (ObjectCallback **) (void *) &rec->obj);
          break;
#endif
        default:
          PRINTFB(G, FB_Executive, FB_Errors)
            " Executive: skipping unrecognized object \"%s\" of type %d.\n",
            rec->name, extra_int ENDFB(G);
          skip = true;
          break;
        }

        CPythonVal_Free(el);

        break;
      case cExecSelection:     // on the first pass, just create an entry in the rec list
        rec->sele_color = extra_int;
        if(part_rest || part_sess) {    // don't attempt to restore selections with partial sessions
          skip = true;
        }
        break;
      }

      if(ll > 6) {
        if(ok){
          ok = PConvPyStrToStr(PyList_GetItem(cur, 6), rec->group_name, sizeof(WordType));
	}
      }

      if(PyErr_Occurred()) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetNamedEntries-Error: after object \"%s\".\n", rec->name ENDFB(G);
        PyErr_Print();
      }

      if(ok && !skip) {
        if(part_rest && ExecutiveProcessObjectName(G, rec->name, new_name)) {
          // rename duplicates
          strcpy(rec->obj->Name, new_name);
          strcpy(rec->name, new_name);
        }

        // replace existing object (unless auto_rename_duplicate_objects=1)
        if(ExecutiveValidName(G, rec->name)) {
          ExecutiveDelete(G, rec->name);
        }

        switch (rec->type) {
        case cExecObject:
          if(rec->visible) {
            rec->in_scene = SceneObjectAdd(G, rec->obj);
            ExecutiveInvalidateSceneMembers(G);
          }
          ExecutiveUpdateObjectSelection(G, rec->obj);
          break;
        }

        rec->cand_id = TrackerNewCand(I->Tracker, (TrackerRef *) rec);
        TrackerLink(I->Tracker, rec->cand_id, I->all_names_list_id, 1);

        switch (rec->type) {
        case cExecObject:
          TrackerLink(I->Tracker, rec->cand_id, I->all_obj_list_id, 1);
          break;
        case cExecSelection:
          TrackerLink(I->Tracker, rec->cand_id, I->all_sel_list_id, 1);
          break;
        }
        ListAppend(I->Spec, rec, next, SpecRec);
        ExecutiveAddKey(I, rec);
        ExecutiveInvalidateGroups(G, false);
        ExecutiveInvalidatePanelList(G);
      } else {
        ListElemFree(rec);
      }
    }
    a++;
    if(!ok) {
      incomplete = true;
      ok = true;
    }
  }
  return (!incomplete);
}

static int ExecutiveSetSelectionsFromPyList(PyMOLGlobals * G, PyObject * names)
{
  /* must already have objects loaded at this point... */

  int ok = true;
  int a = 0, l = 0;
  PyObject *cur;
  SpecRec *rec = NULL;
  int extra;
  int incomplete = false;

  if(ok)
    ok = (names != NULL);
  if(ok)
    ok = PyList_Check(names);
  if(ok)
    l = PyList_Size(names);
  while(ok && (a < l)) {
    cur = PyList_GetItem(names, a);
    if(cur != Py_None) {        /* skip over None w/o aborting */
      rec = NULL;
      ListElemCalloc(G, rec, SpecRec);
      rec->next = NULL;

      if(ok)
        ok = PyList_Check(cur);
      if(ok)
        ok = PConvPyStrToStr(PyList_GetItem(cur, 0), rec->name, sizeof(WordType));
      if(ok)
        ok = PConvPyIntToInt(PyList_GetItem(cur, 1), &rec->type);
      if(ok)
        ok = PConvPyIntToInt(PyList_GetItem(cur, 2), &rec->visible);
      if(ok)
        ok = PConvPyIntToInt(PyList_GetItem(cur, 4), &extra);
      switch (rec->type) {
      case cExecSelection:
        ok = SelectorFromPyList(G, rec->name, PyList_GetItem(cur, 5));
        break;
      }
      ListElemFree(rec);
    }
    a++;
    if(!ok) {
      incomplete = true;
      ok = true;
    }
  }
  return (!incomplete);
}

static PyObject *ExecutiveGetExecObjectAsPyList(PyMOLGlobals * G, SpecRec * rec)
{

  PyObject *result = NULL;
  int recobjtype = rec->obj->type;
  switch (recobjtype){
  case cObjectMesh:
    { /* If a mesh no longer has its dependent map, then it gets saved as a CGO */
      int allMapsExist = ObjectMeshAllMapsInStatesExist((ObjectMesh *) rec->obj);
      if (!allMapsExist){
	recobjtype = cObjectCGO;
      }
    }
  }
  result = PyList_New(7);
  PyList_SetItem(result, 0, PyString_FromString(rec->obj->Name));
  PyList_SetItem(result, 1, PyInt_FromLong(cExecObject));
  PyList_SetItem(result, 2, PyInt_FromLong(rec->visible));
  /* before version 1.8 item 3 was rec reps (repOn) */
  PyList_SetItem(result, 3, PConvAutoNone(NULL));
  PyList_SetItem(result, 4, PyInt_FromLong(recobjtype));
  switch (rec->obj->type) {
  case cObjectGadget:
    PyList_SetItem(result, 5, ObjectGadgetAsPyList((ObjectGadget *) rec->obj));
    break;
  case cObjectMolecule:
    PyList_SetItem(result, 5, ObjectMoleculeAsPyList((ObjectMolecule *) rec->obj));
    break;
  case cObjectMeasurement:
    PyList_SetItem(result, 5, ObjectDistAsPyList((ObjectDist *) rec->obj));
    break;
  case cObjectMap:
    PyList_SetItem(result, 5, ObjectMapAsPyList((ObjectMap *) rec->obj));
    break;
  case cObjectMesh:
    PyList_SetItem(result, 5, ObjectMeshAsPyList((ObjectMesh *) rec->obj));
    break;
  case cObjectSlice:
    PyList_SetItem(result, 5, ObjectSliceAsPyList((ObjectSlice *) rec->obj));
    break;
  case cObjectSurface:
    PyList_SetItem(result, 5, ObjectSurfaceAsPyList((ObjectSurface *) rec->obj));
    break;
  case cObjectCGO:
    PyList_SetItem(result, 5, ObjectCGOAsPyList((ObjectCGO *) rec->obj));
    break;
  case cObjectAlignment:
    PyList_SetItem(result, 5, ObjectAlignmentAsPyList((ObjectAlignment *) rec->obj));
    break;
  case cObjectGroup:
    PyList_SetItem(result, 5, ObjectGroupAsPyList((ObjectGroup *) rec->obj));
    break;
  case cObjectVolume:
    PyList_SetItem(result, 5, ObjectVolumeAsPyList((ObjectVolume *) rec->obj));
    break;
  case cObjectCallback:
    PyList_SetItem(result, 5, ObjectCallbackAsPyList((ObjectCallback *) rec->obj));
    break;
  default:
    PyList_SetItem(result, 5, PConvAutoNone(NULL));
    break;
  }
  PyList_SetItem(result, 6, PyString_FromString(rec->group_name));

  return (result);
}

static PyObject *ExecutiveGetExecSeleAsPyList(PyMOLGlobals * G, SpecRec * rec)
{
  PyObject *result = NULL;
  int sele;

  sele = SelectorIndexByName(G, rec->name);
  if(sele >= 0) {
    result = PyList_New(7);
    PyList_SetItem(result, 0, PyString_FromString(rec->name));
    PyList_SetItem(result, 1, PyInt_FromLong(cExecSelection));
    PyList_SetItem(result, 2, PyInt_FromLong(rec->visible));
    /* before version 1.8 item 3 was rec reps (repOn) */
    PyList_SetItem(result, 3, PConvAutoNone(NULL));
    PyList_SetItem(result, 4, PyInt_FromLong(-1));
    PyList_SetItem(result, 5, SelectorAsPyList(G, sele));
    PyList_SetItem(result, 6, PyString_FromString(rec->group_name));

  }
  return (PConvAutoNone(result));
}

static PyObject *ExecutiveGetNamedEntries(PyMOLGlobals * G, int list_id, int partial)
{
  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  PyObject *result = NULL;
  int count = 0, total_count = 0;
  int iter_id = 0;
  SpecRec *rec = NULL, *list_rec = NULL;

  SelectorUpdateTable(G, cSelectorUpdateTableAllStates, -1);

  if(list_id) {
    total_count = TrackerGetNCandForList(I_Tracker, list_id);
    iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  } else {
    total_count = ExecutiveCountNames(G);
  }
  result = PyList_New(total_count);

  /* critical reliance on short-circuit behavior */

  while((iter_id && TrackerIterNextCandInList(I_Tracker, iter_id,
                                              (TrackerRef **) (void *) &list_rec)) ||
        ((!iter_id) && ListIterate(I->Spec, rec, next))) {

    if(list_id)
      rec = list_rec;
    if(count >= total_count)
      break;
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        PyList_SetItem(result, count, ExecutiveGetExecObjectAsPyList(G, rec));
        break;
      case cExecSelection:
        if(!partial) {
          PyList_SetItem(result, count, ExecutiveGetExecSeleAsPyList(G, rec));
        } else {
          /* cannot currently save selections in partial sessions */
          PyList_SetItem(result, count, PConvAutoNone(NULL));
        }
        break;
      default:
        PyList_SetItem(result, count, PConvAutoNone(NULL));
        break;
      }
    } else {
      PyList_SetItem(result, count, PConvAutoNone(NULL));
    }
    count++;
  }

  while(count < total_count) {  /* insure that all members of outgoing list are defined */
    PyList_SetItem(result, count, PConvAutoNone(NULL));
    count++;
  }

  if(iter_id) {
    TrackerDelIter(I_Tracker, iter_id);
  }
  return (PConvAutoNone(result));
}

#ifdef PYMOL_EVAL
#include "ExecutiveEvalMessage.h"
#endif

int ExecutiveGetSession(PyMOLGlobals * G, PyObject * dict, const char *names, int partial,
                        int quiet)
{
  int ok = true;
  int list_id = 0;
  SceneViewType sv;
  PyObject *tmp;

  if(names && names[0]) {
    list_id = ExecutiveGetNamesListFromPattern(G, names, true, cExecExpandKeepGroups);
  }

  tmp = MovieScenesAsPyList(G);
  PyDict_SetItemString(dict, "moviescenes", tmp);
  Py_XDECREF(tmp);

  tmp = PyInt_FromLong(_PyMOL_VERSION_int);
  PyDict_SetItemString(dict, "version", tmp);
  Py_XDECREF(tmp);

  tmp = ExecutiveGetNamedEntries(G, list_id, partial);
  PyDict_SetItemString(dict, "names", tmp);
  Py_XDECREF(tmp);

  tmp = ColorAsPyList(G);
  PyDict_SetItemString(dict, "colors", tmp);
  Py_XDECREF(tmp);

  tmp = ColorExtAsPyList(G);
  PyDict_SetItemString(dict, "color_ext", tmp);
  Py_XDECREF(tmp);

  tmp = SettingUniqueAsPyList(G);
  PyDict_SetItemString(dict, "unique_settings", tmp);
  Py_XDECREF(tmp);

  if(partial) {                 /* mark this as a partial session */

    PyDict_SetItemString(dict, "partial", PConvAutoNone(Py_None));

  } else {

    /* none of the following information is saved in partial sessions */

    tmp = SelectorSecretsAsPyList(G);
    PyDict_SetItemString(dict, "selector_secrets", tmp);
    Py_XDECREF(tmp);

    tmp = SettingGetGlobalsAsPyList(G);
    PyDict_SetItemString(dict, "settings", tmp);
    Py_XDECREF(tmp);

    SceneGetView(G, sv);
    tmp = PConvFloatArrayToPyList(sv, cSceneViewSize);
    PyDict_SetItemString(dict, "view", tmp);
    Py_XDECREF(tmp);

    tmp = MovieAsPyList(G);
    PyDict_SetItemString(dict, "movie", tmp);
    Py_XDECREF(tmp);

    tmp = EditorAsPyList(G);
    PyDict_SetItemString(dict, "editor", tmp);
    Py_XDECREF(tmp);

    tmp = MainAsPyList();
    PyDict_SetItemString(dict, "main", tmp);
    Py_XDECREF(tmp);

#ifdef PYMOL_EVAL
    ExecutiveEvalMessage(G, dict);
#endif

  }

  if(Feedback(G, FB_Executive, FB_Errors)) {
    if(PyErr_Occurred()) {
      PRINTF
        " ExecutiveGetSession: a Python error occured during creation of the session object:\n"
        ENDF(G);
      PyErr_Print();
    }
  }

  return (ok);
}

static void ExecutiveMigrateSession(PyMOLGlobals * G, int session_version)
{
  if (session_version < 1700) {
    if (SettingGetGlobal_i(G, cSetting_seq_view_label_color) == 0 /* white */) {
      SettingSetGlobal_i(G, cSetting_seq_view_label_color, cColorFront);
    }
  }
  if(session_version < 100) {
    /* migrate lighting model */
    SettingSetGlobal_f(G, cSetting_direct, 1.8 * SettingGetGlobal_f(G, cSetting_direct));
    SettingSetGlobal_f(G, cSetting_reflect,
                       0.5 * SettingGetGlobal_f(G, cSetting_reflect));
    SettingSetGlobal_f(G, cSetting_ambient,
                       1.166 * SettingGetGlobal_f(G, cSetting_ambient));
    SettingSetGlobal_f(G, cSetting_gamma, 0.769 * SettingGetGlobal_f(G, cSetting_gamma));

    /* try best to meet existing expectations with existing sessions */
    SettingSetGlobal_f(G, cSetting_ray_legacy_lighting, 1.0F);

    /* force use of movie_delay in preference to movie_fps */

    SettingSetGlobal_f(G, cSetting_movie_fps, 0.0F);

    /* and labels */
    SettingSetGlobal_i(G, cSetting_label_digits, 2);
  }
  if(session_version < 99) {
    SettingSetGlobal_f(G, cSetting_cartoon_ladder_mode, 0);
    SettingSetGlobal_f(G, cSetting_cartoon_tube_cap, 0);
    SettingSetGlobal_f(G, cSetting_cartoon_nucleic_acid_mode, 1);
    {
      float old_sulfur[3] = { 1.0, 0.5, 0.0 };
      ColorDef(G, "sulfur", old_sulfur, 0, true);
    }
  }
  if(session_version < 98) {
    /* produce expected rendering quality & performance with old sessions */
    SettingSetGlobal_b(G, cSetting_ray_orthoscopic, 1);
  }
  if(session_version < 96) {
    SettingSetGlobal_f(G, cSetting_ray_transparency_contrast, 1.0F);
  }
  if(session_version < 95) {
    {
      /* adjust fog to reflect current importance of seeing to the Z-slab center w/o fog */

      float fog_start = SettingGetGlobal_f(G, cSetting_fog_start);
      float ray_trace_fog_start = SettingGetGlobal_f(G, cSetting_ray_trace_fog_start);
      if((fog_start == 0.40F) || (fog_start == 0.35F) || (fog_start == 0.30F)) {
        SettingSetGlobal_f(G, cSetting_fog_start, 0.45F);
      }
      if((ray_trace_fog_start == 0.45F) || (ray_trace_fog_start == 0.40F)
         || (ray_trace_fog_start == 0.35F)) {
        SettingSetGlobal_f(G, cSetting_ray_trace_fog_start, 0.50F);
      }
    }

    {                           /* adjust GUI width */

      int gui_width = SettingGetGlobal_i(G, cSetting_internal_gui_width);

      if(gui_width == 160) {
        SettingSetGlobal_i(G, cSetting_internal_gui_width, 220);
      }
    }

    {                           /* enable antialiasing */

      int antialias = SettingGetGlobal_i(G, cSetting_antialias);

      if(antialias == 0) {
        SettingSetGlobal_i(G, cSetting_antialias, 1);
      }

    }
  }
}

int ExecutiveSetSession(PyMOLGlobals * G, PyObject * session,
                        int partial_restore, int quiet)
{
  int ok = true;
  int incomplete = false;
  PyObject *tmp;
  SceneViewType sv;
  int version = -1, version_full;
  int migrate_sessions = SettingGetGlobal_b(G, cSetting_session_migration);
  char active[WordLength] = "";
  int have_active = false;
  int partial_session = false;

  G->Color->HaveOldSessionColors = false;
  G->Color->HaveOldSessionExtColors = false;

  if(!partial_restore) {        /* if user has requested partial restore */
    ExecutiveDelete(G, "all");
    ColorReset(G);
  }

  if(!session || !PyDict_Check(session)) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Error: not a dict\n" ENDFB(G);
    return 0;
  }

  if(ok) {                      /* if session is partial, then don't error about missing stuff */
    tmp = PyDict_GetItemString(session, "partial");
    if(tmp) {
      partial_session = true;
    }
  }

  if (partial_restore) {
    G->SettingUnique->old2new = OVOneToOne_New(G->Context->heap);
  }

  if(ok) {
    tmp = PyDict_GetItemString(session, "version");
    if(tmp) {
      ok = PConvPyIntToInt(tmp, &version);
      if(ok) {
	version_full = version;
	while (version_full < 210)  /* any version less than 2.1 (account for next major version 2) should be 4 digits, otherwise 3 */
	  version_full *= 10;
        float version_float = version_full / (version >= 1000000 ? 1000000.f : 1000.f);
        if(version > _PyMOL_VERSION_int) {
          if(!quiet) {
            PRINTFB(G, FB_Executive, FB_Errors)
              "Warning: This session was created with a newer version of PyMOL (%1.6f).\n",
              version_float ENDFB(G);
            if(SettingGetGlobal_i(G, cSetting_session_version_check)) {
              PRINTFB(G, FB_Executive, FB_Errors)
                "Error: Please update first -- see http://www.pymol.org\n" ENDFB(G);
              ok = false;
            } else {
              PRINTFB(G, FB_Executive, FB_Errors)
                "Warning: Some content may not load completely.\n" ENDFB(G);
            }
          }
        } else {
          if(!quiet) {
            PRINTFB(G, FB_Executive, FB_Details)
              " Executive: Loading version %1.6f session...\n", version_float ENDFB(G);
          }
        }
      }
    }
  }
#ifndef PYMOL_EVAL
  if(ok) {
    tmp = PyDict_GetItemString(session, "eval_nag");
    if(tmp) {
      ok = PyString_Check(tmp);
      if(ok) {
        const char *st = PyString_AsString(tmp);
        if(st) {
          if(Feedback(G, FB_Nag, FB_Warnings)) {
            OrthoAddOutput(G, st);
          }
        }
      }
    }
  }
#endif

  if(ok) {                      /* colors must be restored before settings and objects */
    tmp = PyDict_GetItemString(session, "colors");
    if(tmp) {
      ok = ColorFromPyList(G, tmp, partial_restore);
    }

    if(tmp || (!partial_restore)) {     /* ignore missing if partial restore */

      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after colors.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }

  if(ok) {
    tmp = PyDict_GetItemString(session, "color_ext");
    if(tmp) {
      ok = ColorExtFromPyList(G, tmp, partial_restore);
    }

    if(tmp || (!partial_session)) {     /* ignore missing if partial restore */
      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after color_ext.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }
  if(ok) {
    tmp = PyDict_GetItemString(session, "settings");
    if(tmp && !partial_restore) {
      SettingSetGlobalsFromPyList(G, tmp);
    }

    if(tmp || (!(partial_restore | partial_session))) { /* ignore missing if partial restore */
      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after settings.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }
  if(ok) {
    tmp = PyDict_GetItemString(session, "unique_settings");
    if(tmp) {
      ok = SettingUniqueFromPyList(G, tmp, partial_restore);
    }

    if(tmp || (!partial_session)) {     /* ignore missing if partial restore */
      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after settings.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }
  if(ok) {
    tmp = PyDict_GetItemString(session, "names");
    if(tmp) {
      if(ok)
        ok = ExecutiveSetNamedEntries(G, tmp, version, partial_restore, partial_session);
      if(!(partial_restore || partial_session)) {
        if(ok)
          ok = ExecutiveSetSelectionsFromPyList(G, tmp);
        if(ok)
          have_active = ExecutiveGetActiveSeleName(G, active, false, false);
      }
    }
    if(PyErr_Occurred()) {
      PyErr_Print();
      ok = false;
    }
    if(!ok) {
      PRINTFB(G, FB_Executive, FB_Errors)
        "ExectiveSetSession-Error: after names.\n" ENDFB(G);
    }
    if(!ok) {
      incomplete = true;
      ok = true;                /* keep trying...don't give up */
    }
  }
  if(ok && !(partial_restore)) {
    tmp = PyDict_GetItemString(session, "selector_secrets");
    if(tmp) {
      if(ok)
        ok = SelectorSecretsFromPyList(G, tmp);
    }

    if(tmp || (!(partial_restore | partial_session))) { /* ignore missing if partial restore */
      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after selector secrets.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }
  if(ok && !(partial_restore)) {
    tmp = PyDict_GetItemString(session, "view");
    if(tmp) {
      ok = PConvPyListToFloatArrayInPlace(tmp, sv, cSceneViewSize);
    }
    if(tmp || (!(partial_restore | partial_session))) { /* ignore missing if partial restore */
      if(ok)
        SceneSetView(G, sv, true, 0, 0);
      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after view.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }

  if (ok && !partial_restore) {
    tmp = CPythonVal_PyDict_GetItemString(G, session, "moviescenes");
    if (tmp) {
      MovieScenesFromPyList(G, tmp);
      CPythonVal_Free(tmp);
    }
  }

  if(ok && !(partial_restore)) {
    int warning;
    tmp = PyDict_GetItemString(session, "movie");
    if(tmp) {
      ok = MovieFromPyList(G, tmp, &warning);
    }
    if(tmp || (!(partial_restore | partial_session))) { /* ignore missing if partial restore */

      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after movie.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }

  if(ok && !(partial_restore)) {
    tmp = PyDict_GetItemString(session, "editor");
    if(tmp) {
      ok = EditorFromPyList(G, tmp);
    }
    if(tmp || (!(partial_restore | partial_session))) { /* ignore missing if partial restore */

      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after editor.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }
  if(ok) {                      /* update mouse in GUI */
    PParse(G, "cmd.mouse(quiet=1)");
    if(!G->Option->presentation && !SettingGetGlobal_b(G, cSetting_suspend_updates))
      PParse(G, "viewport");    /* refresh window/internal_gui status */
  }
  // Do not load viewport size when we have a GUI
  if(ok) {
    tmp = PyDict_GetItemString(session, "main");
    if(tmp) {
      if (!G->HaveGUI &&
          /* PYMOL-775 added suspend_updates check, but does it make sense? */
          !SettingGetGlobal_b(G, cSetting_suspend_updates) &&
          !partial_restore) {
        ok = MainFromPyList(tmp);
#ifndef _PYMOL_NOPY
      } else if (!quiet) {
        int viewport[2];
        PConvPyListToIntArrayInPlace(tmp, viewport, 2);
        PRINTFB(G, FB_Executive, FB_Actions)
          " Session was saved with: viewport %d, %d\n",
          viewport[0], viewport[1] ENDFB(G);
#endif
      }
    }
    if(tmp || (!(partial_restore | partial_session))) { /* ignore missing if partial restore */
      if(PyErr_Occurred()) {
        PyErr_Print();
        ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "ExectiveSetSession-Error: after main.\n" ENDFB(G);
      }
      if(!ok) {
        incomplete = true;
        ok = true;              /* keep trying...don't give up */
      }
    }
  }

  if(ok && migrate_sessions) {  /* migrate sessions */
    tmp = PyDict_GetItemString(session, "version");
    if(tmp) {
      ok = PConvPyIntToInt(tmp, &version);
      if(ok) {
        ExecutiveMigrateSession(G, version);
      }
    }
  }
  if(ok) {
    if(have_active)
      ExecutiveSetObjVisib(G, active, true, false);
  }

  OVOneToOne_DEL_AUTO_NULL(G->SettingUnique->old2new);

  if(incomplete) {
    PRINTFB(G, FB_Executive, FB_Warnings)
      "ExectiveSetSession-Warning: restore may be incomplete.\n" ENDFB(G);
  }
  G->ShaderMgr->Set_Reload_Bits(RELOAD_ALL_SHADERS);
  OrthoBackgroundTextureNeedsUpdate(G);
  ExecutiveInvalidateSelectionIndicatorsCGO(G);
  OrthoInvalidateDoDraw(G);
  SceneChanged(G);
  return (ok);
}


#define ExecScrollBarMargin DIP2PIXEL(1)
#define ExecScrollBarWidth DIP2PIXEL(13)

void ExecutiveObjMolSeleOp(PyMOLGlobals * G, int sele, ObjectMoleculeOpRec * op);

static CObject **ExecutiveSeleToObjectVLA(PyMOLGlobals * G, const char *s1)
{
  /* return VLA containing list of atoms references by selection */

  CObject **result = NULL;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  CObject *obj = NULL;
  int n = 0;
  ObjectMoleculeOpRec op2;
  int sele;

  result = VLAlloc(CObject *, 50);
  if(WordMatchExact(G, s1, cKeywordAll, true)) {
    /* all objects */
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        VLACheck(result, CObject *, n);
        result[n] = rec->obj;
        n++;
      }
    }
  } else {
    sele = SelectorIndexByName(G, s1);
    if(sele >= 0) {
      ObjectMoleculeOpRecInit(&op2);
      op2.code = OMOP_GetObjects;
      op2.obj1VLA = (ObjectMolecule **) result;
      op2.i1 = 0;
      ExecutiveObjMolSeleOp(G, sele, &op2);
      n = op2.i1;
      result = (CObject **) op2.obj1VLA;
    } else {
      obj = ExecutiveFindObjectByName(G, s1);
      if(obj) {
        VLACheck(result, CObject *, n);
        result[n] = obj;
        n++;
      }
    }
  }
  VLASize(result, CObject *, n);
  return (result);
}

int ExecutiveGetSymmetry(PyMOLGlobals * G, const char *sele, int state, float *a, float *b, float *c,
                        float *alpha, float *beta, float *gamma, char *sgroup, int *defined)
{
  int ok = false;

  ObjectMolecule *objMol;
  ObjectMap *objMap;
  int n_obj;
  CObject **objVLA = NULL;
  CObject *obj = NULL;
  CSymmetry* symm;

  if(state<0) {
    state = 0;
  } else if(state>0) {
    state--;
  }

  objVLA = ExecutiveSeleToObjectVLA(G, sele);
  n_obj = VLAGetSize(objVLA);

  switch(n_obj) {

    /* No object found */
  case 0:
    {
      PRINTFB(G, FB_Executive, FB_Errors)
	"Error: invalid selection.\n" ENDFB(G);
      ok = false;
    }
    break;

    /* One unique object found */
  case 1:
    {
      obj = objVLA[0];

      if(obj->type==cObjectMolecule) {
	objMol = (ObjectMolecule*) obj;

	if(objMol->Symmetry && objMol->Symmetry->Crystal) {
	  *a = objMol->Symmetry->Crystal->Dim[0];
	  *b = objMol->Symmetry->Crystal->Dim[1];
	  *c = objMol->Symmetry->Crystal->Dim[2];
	  *alpha = objMol->Symmetry->Crystal->Angle[0];
	  *beta = objMol->Symmetry->Crystal->Angle[1];
	  *gamma = objMol->Symmetry->Crystal->Angle[2];
	  UtilNCopy(sgroup, objMol->Symmetry->SpaceGroup, sizeof(WordType));
	  *defined = true;
	  ok = true;
	}
      } else if(obj->type==cObjectMap) {
	objMap = (ObjectMap*) obj;

	/* maps can have multiple symmetry states */
	if(state>objMap->NState) {
	  ok = false;
	  break;
	}

	symm = (objMap->State + state)->Symmetry;
	
	if(symm && symm->Crystal) {

	  *a = symm->Crystal->Dim[0];
	  *b = symm->Crystal->Dim[1];
	  *c = symm->Crystal->Dim[2];
	  *alpha = symm->Crystal->Angle[0];
	  *beta = symm->Crystal->Angle[1];
	  *gamma = symm->Crystal->Angle[2];
	  UtilNCopy(sgroup, symm->SpaceGroup, sizeof(WordType));
	  *defined = true;
	  ok = true;
	}
      }
    }
    break;

    /* Too many objects found */
  default:
    PRINTFB(G, FB_Executive, FB_Errors)
      "Error: selection must refer to exactly one object.\n" ENDFB(G);
    ok = false;
    break;
  }

  VLAFreeP(objVLA);

  return (ok);
}

int ExecutiveSetSymmetry(PyMOLGlobals * G, const char *sele, int state, float a, float b, float c,
                        float alpha, float beta, float gamma, const char *sgroup)
{
  CObject **objVLA = NULL;
  CObject *obj;
  ObjectMolecule *objMol;
  ObjectMap *objMap;
  int ok = true;
  CSymmetry *symmetry = NULL;
  int n_obj;
  int i;

  /* create a new symmetry object for copying */
  symmetry = SymmetryNew(G);
  ok_assert(1, ok = (symmetry != NULL));
  symmetry->Crystal->Dim[0] = a;
  symmetry->Crystal->Dim[1] = b;
  symmetry->Crystal->Dim[2] = c;
  symmetry->Crystal->Angle[0] = alpha;
  symmetry->Crystal->Angle[1] = beta;
  symmetry->Crystal->Angle[2] = gamma;
  UtilNCopy(symmetry->SpaceGroup, sgroup, sizeof(WordType));
  SymmetryUpdate(symmetry);

  objVLA = ExecutiveSeleToObjectVLA(G, sele);
  n_obj = VLAGetSize(objVLA);
  if(n_obj) {
    for(i = 0; i < n_obj; i++) {
      obj = objVLA[i];
      switch (obj->type) {
      case cObjectMolecule:
        objMol = (ObjectMolecule *) obj;
        if(symmetry) {
	  /* right now, ObjectMolecules only have one-state symmetry information */
	  SymmetryFree(objMol->Symmetry);
	  objMol->Symmetry = SymmetryCopy(symmetry);
        }
        break;
      case cObjectMap:
	objMap = (ObjectMap *) obj;
	
	if(symmetry) {
	  for(StateIterator iter(G, obj->Setting, state, objMap->NState); iter.next();) {
	    ObjectMapState *oms = objMap->State + iter.state;
	    SymmetryFree(oms->Symmetry);
	    oms->Symmetry = SymmetryCopy(symmetry);
	  }
	  ObjectMapRegeneratePoints(objMap);
	}
	break;
      }
    }
  } else {
    ok = false;
    PRINTFB(G, FB_Executive, FB_Errors)
      " ExecutiveSetSymmetry: no object selected\n" ENDFB(G);
  }
  if(symmetry)
    SymmetryFree(symmetry);
  VLAFreeP(objVLA);
ok_except1:
  return (ok);
}

int ExecutiveSymmetryCopy(PyMOLGlobals * G, const char *source_name, const char *target_name,
			  int source_mode, int target_mode,
			  int source_state, int target_state,
			  int target_undo, int log, int quiet) {

  /* Copy the symmetry info from source to target; currently maps can have
   * multiple states for symmetry, but ObjectMolecule cannot */

  int ok = true;
  CObject *source_obj = NULL;
  CObject *target_obj = NULL;
  CSymmetry * source_symm = NULL;
  CSymmetry ** target_symm = NULL;

  ObjectMolecule * tmp_mol = NULL;
  ObjectMap * tmp_map = NULL, *targ_map = NULL;

  /* defaults */
  if(source_state==-1)
    source_state = 0;
  if(target_state==-1)
    target_state = 0;
  
  /* SOURCE OBJECT and its SYMMETRY INFO */
  source_obj = ExecutiveFindObjectByName(G, source_name);

  if(source_obj) {
    /* ObjectMolecule */
    if(source_obj->type==cObjectMolecule){
      /* OVERRIDE STATE for ObjectMolecules */
      source_state = 0;
      tmp_mol = (ObjectMolecule*) source_obj;
      source_symm = tmp_mol->Symmetry + source_state;
    }
    /* ObjectMap */
    else if(source_obj->type==cObjectMap){
      tmp_map = (ObjectMap*) source_obj;

      if(source_state+1>tmp_map->NState) {
	PRINTFB(G, FB_Executive, FB_Errors)
	  " SymmetryCopy-Error: source state '%d' greater than number of states in object '%s'.", tmp_map->NState, source_name  ENDFB(G);
	ok = false;
      }
      if(ok) {
	source_symm = (tmp_map->State + source_state)->Symmetry;
      }
    }
    else {
      /* object is not a molecule or a map -- bad input */
      PRINTFB(G, FB_Executive, FB_Errors)
	" SymmetryCopy-Error: source '%s' is not a molecular or map object.", source_name  ENDFB(G);
      ok = false;
    }
  } else {
    /* no source object found */
    PRINTFB(G, FB_Executive, FB_Errors)
      " SymmetryCopy-Error: source object not found."  ENDFB(G);
    ok = false;
  }

  /* TARGET OBJECT and its SYMMETRY INFO */
  target_obj = ExecutiveFindObjectByName(G, target_name);

  if(target_obj) {
    /* ObjectMolecule */
    if(target_obj->type==cObjectMolecule){
      /* OVERRIDE STATE for ObjectMolecules */
      target_state = 0;
      tmp_mol = (ObjectMolecule*) target_obj;
      target_symm = &(tmp_mol->Symmetry); /* + target_state; */
    }
    /* ObjectMap */
    else if(target_obj->type==cObjectMap){
      targ_map = (ObjectMap*) target_obj;

      if(target_state+1>targ_map->NState) {
	PRINTFB(G, FB_Executive, FB_Errors)
	  " SymmetryCopy-Error: target state '%d' greater than number of states in object '%s'.", targ_map->NState, target_name  ENDFB(G);
	ok = false;
      }
      if(ok) {
	target_symm =  (CSymmetry**)  &((targ_map->State + target_state)->Symmetry);
      }
    }
    else {
      /* object is not a molecule or a map -- bad input */
      PRINTFB(G, FB_Executive, FB_Errors)
	" SymmetryCopy-Error: target '%s' is not a molecular or map object.", target_name  ENDFB(G);
      ok = false;
    }
  } else {
    /* no target object found */
    PRINTFB(G, FB_Executive, FB_Errors)
      " SymmetryCopy-Error: target object not found."  ENDFB(G);
    ok = false;
  }

  /* Do the copy */
  if(ok) {
    if(target_symm) {
      if(*target_symm)
	SymmetryFree(*target_symm);
      
      *target_symm = SymmetryCopy(source_symm);

      /* Invalidate cRepCell */
      /* if the unit cell is shown for molecule, redraw it */
      if(tmp_mol) {
	if((tmp_mol->Obj.visRep & cRepCellBit)) {
	  if(tmp_mol->Symmetry) {
	    if(tmp_mol->Symmetry->Crystal) {
	      if(tmp_mol->UnitCellCGO)
		CGOFree(tmp_mol->UnitCellCGO);
	      tmp_mol->UnitCellCGO = CrystalGetUnitCellCGO(tmp_mol->Symmetry->Crystal);
	    }
	  }
	}
      }
      if (targ_map){
	ObjectMapRegeneratePoints(targ_map);
      }

      if(! *target_symm)
	ok = false;
    }
  }

  return ok;
}

int ExecutiveSmooth(PyMOLGlobals * G, const char *selection, int cycles,
                    int window, int first, int last, int ends, int quiet)
{
  SelectorTmp tmpsele1(G, selection);
  int sele = tmpsele1.getIndex();
  const char *name = tmpsele1.getName();

  ObjectMoleculeOpRec op;
  int state;
  int n_state;
  float *coord0 = NULL, *coord1 = NULL;
  int *flag0 = NULL, *flag1 = NULL;
  int a, b, c, d, st, cnt;
  float i_cnt;
  int n_atom;
  int ok = true;
  int backward;
  int forward;
  int range, offset;
  int end_skip = 0;
  float *v0, *v1;
  float sum[3];
  int loop = false;
  /*  WordType all = "_all"; */

  PRINTFD(G, FB_Executive)
    " ExecutiveSmooth: entered %s,%d,%d,%d,%d,%d\n", name, cycles, first, last, window,
    ends ENDFD;

  /* given a valid selection */
  if(sele >= 0) {
    /* count the number of states over which to smooth */
    int max_state = ExecutiveCountStates(G, name) - 1;
    if(last < 0)
      last = max_state;
    if(first < 0)
      first = 0;
    if(last < first) {
      state = last;
      last = first;
      first = state;
    }
    if(last > max_state)
      last = max_state;

    n_state = last - first + 1;

    backward = window / 2;
    forward = window / 2;

    if((forward - backward) == (window + 1))
      forward--;                /* even sizes window */

    switch (ends) {
    case 0:
      end_skip = 1;
      break;
    case 1:
      end_skip = 0;
      break;
    case 2:
      end_skip = backward;
      break;
    case 3:                    /* cyclic averaging */
      end_skip = 0;
      loop = true;
      break;
    default:
      end_skip = 0;
      break;
    }

    if(ends) {
      range = (last - first) + 1;
      offset = 0;
    } else {
      range = (last - end_skip) - (first + end_skip) + 1;
      offset = end_skip;
    }

    PRINTFD(G, FB_Executive)
      " ExecutiveSmooth: first %d last %d n_state %d backward %d forward %d range %d\n",
      first, last, n_state, backward, forward, range ENDFD;

    if(n_state >= window) {

      /* determine storage req */
      ObjectMoleculeOpRecInit(&op);
      op.code = OMOP_CountAtoms;
      op.i1 = 0;
      ExecutiveObjMolSeleOp(G, sele, &op);
      n_atom = op.i1;
      if(n_atom) {
        /* allocate storage */
        coord0 = Alloc(float, 3 * n_atom * n_state);
        coord1 = Alloc(float, 3 * n_atom * n_state);
        flag0 = Alloc(int, n_atom * n_state);
        flag1 = Alloc(int, n_atom * n_state);

        /* clear the arrays */

        UtilZeroMem(coord0, sizeof(float) * 3 * n_atom * n_state);
        UtilZeroMem(flag0, sizeof(int) * n_atom * n_state);

        /* get the data */
        if(!quiet) {
          PRINTFB(G, FB_Executive, FB_Actions)
            " Smooth: copying coordinates to temporary arrays..\n" ENDFB(G);
        }
        op.code = OMOP_CSetIdxGetAndFlag;
        op.i1 = n_atom;
        op.i2 = 0;
        op.cs1 = first;
        op.cs2 = last;
        op.vv1 = coord0;
        op.ii1 = flag0;
        op.nvv1 = 0;
        ExecutiveObjMolSeleOp(G, sele, &op);

        PRINTFD(G, FB_Executive)
          " ExecutiveSmooth: got %d %d\n", op.i2, op.nvv1 ENDFD;

        UtilZeroMem(coord1, sizeof(float) * 3 * n_atom * n_state);
        UtilZeroMem(flag1, sizeof(int) * n_atom * n_state);

        for(a = 0; a < cycles; a++) {
          if(!quiet) {
            PRINTFB(G, FB_Executive, FB_Actions)
              " Smooth: smoothing (pass %d)...\n", a + 1 ENDFB(G);
          }
          for(b = 0; b < range; b++) {
            for(c = 0; c < n_atom; c++) {
              zero3f(sum);
              cnt = 0;
              for(d = -backward; d <= forward; d++) {
                st = b + offset + d;
                if(loop) {
                  if(st < 0) {
                    st = n_state + st;
                  } else if(st >= n_state) {
                    st = st - n_state;
                  }
                } else {
                  if(st < 0) {
                    st = 0;
                  } else if(st >= n_state) {
                    st = n_state - 1;
                  }
                }

                /*if(c==0) printf("averaging from slot %d\n",st); */
                cnt += flag0[(n_atom * st) + c];
                v0 = coord0 + 3 * (n_atom * st + c);
		/* atom's avg position */
                add3f(sum, v0, sum);
              }
              if(cnt) {
                st = b + offset;
                if((st >= end_skip) && (st < (n_state - end_skip))) {
                  /* if(c==0) printf("dumping into slot %d\n",st); */
                  flag1[(n_atom * st) + c] = flag0[(n_atom * st) + c];
                  /* don't flag states that weren't originally flagged */
                  i_cnt = 1.0F / cnt;
                  v1 = coord1 + 3 * ((n_atom * st) + c);
                  scale3f(sum, i_cnt, v1);
                }
              }
            }
          }
          for(b = 0; b < range; b++) {
            for(c = 0; c < n_atom; c++) {
              st = b + offset;
              if(flag1[(n_atom * st) + c]) {
                v0 = coord0 + 3 * ((n_atom * st) + c);
                v1 = coord1 + 3 * ((n_atom * st) + c);
                copy3f(v1, v0);
              }
            }
          }
        }

        if(!quiet) {
          PRINTFB(G, FB_Executive, FB_Actions)
            " Smooth: updating coordinates...\n" ENDFB(G);
        }

        /* set the new coordinates */

        op.code = OMOP_CSetIdxSetFlagged;
        op.i1 = n_atom;
        op.i2 = 0;
        if(ends) {
          op.cs1 = first;
          op.cs2 = last;
          op.vv1 = coord1;
          op.ii1 = flag1;
        } else {
          op.cs1 = first + end_skip;
          op.cs2 = last - end_skip;
          op.vv1 = coord1 + (end_skip * 3 * n_atom);
          op.ii1 = flag1 + (end_skip * n_atom);
        }
        op.nvv1 = 0;

        ExecutiveObjMolSeleOp(G, sele, &op);
        PRINTFD(G, FB_Executive)
          " ExecutiveSmooth: put %d %d\n", op.i2, op.nvv1 ENDFD;

        FreeP(coord0);
        FreeP(coord1);
        FreeP(flag0);
        FreeP(flag1);
      }
    }
  } else {
    PRINTFB(G, FB_Executive, FB_Errors)
      " ExecutiveSmooth: selection not found\n" ENDFB(G);
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveDebug(PyMOLGlobals * G, const char *name)
{
  ObjectMolecule *obj;
  ObjectMoleculeBPRec bp;
  int a;

  obj = (ObjectMolecule *) ExecutiveFindObjectByName(G, name);
  if(obj) {
    ObjectMoleculeInitBondPath(obj, &bp);
    ObjectMoleculeGetBondPaths(obj, 0, 10, &bp);
    for(a = 0; a < bp.n_atom; a++) {
      printf("%d %d %d\n", a, bp.list[a], bp.dist[bp.list[a]]);
    }

    ObjectMoleculePurgeBondPath(obj, &bp);
  }
  return (1);
}


/*========================================================================*/
int ***ExecutiveGetBondPrint(PyMOLGlobals * G, const char *name, int max_bond, int max_type,
                             int *dim)
{
  int ***result = NULL;
  CObject *obj;
  ObjectMolecule *objMol;

  obj = ExecutiveFindObjectByName(G, name);
  if(obj->type == cObjectMolecule) {
    objMol = (ObjectMolecule *) obj;
    result = ObjectMoleculeGetBondPrint(objMol, max_bond, max_type, dim);
  }
  return (result);
}


/*========================================================================*/
#define cMapOperatorMinimum 0
#define cMapOperatorMaximum 1
#define cMapOperatorSum     2
#define cMapOperatorAverage 3
#define cMapOperatorDifference 4
#define cMapOperatorCopy     5
#define cMapOperatorUnique   6

int ExecutiveMapSet(PyMOLGlobals * G, const char *name, int operator_, const char *operands,
                    int target_state, int source_state, int zoom, int quiet)
{
  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  int ok = true;
  int isNew = false;
  ObjectMap *target = ExecutiveFindObjectMapByName(G, name);
  ObjectMap *first_operand = NULL;
  int src_state_start = 0, src_state_stop = 0;
  int list_id = ExecutiveGetNamesListFromPattern(G, operands, true, true);

  if(target_state < 0)          /* if we're targeting all states, 0 is the offset */
    target_state = 0;

  /* first, figure out what the range of input states is */

  if(source_state < 0) {        /* all source states */
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    int max_n_state = 0;
    SpecRec *rec;
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecObject:
          if(rec->obj->type == cObjectMap) {
            ObjectMap *obj = (ObjectMap *) rec->obj;
            if(obj->NState > max_n_state)
              max_n_state = obj->NState;        /* count states */
          }
        }
      }
    }
    TrackerDelIter(I_Tracker, iter_id);
    src_state_start = 0;
    src_state_stop = max_n_state;
  } else {
    src_state_start = source_state;
    src_state_stop = source_state + 1;
  }

  {
    /* next, find the first operand */

    OrthoLineType first_op_st;
    ParseWordCopy(first_op_st, operands, sizeof(OrthoLineType) - 1);    /* copy the first operand */
    {
      int sub_list_id = ExecutiveGetNamesListFromPattern(G, first_op_st, true, true);
      int sub_iter_id = TrackerNewIter(I_Tracker, 0, sub_list_id);
      SpecRec *rec;

      while(TrackerIterNextCandInList(I_Tracker, sub_iter_id,
                                      (TrackerRef **) (void *) &rec)) {
        if(rec) {
          switch (rec->type) {
          case cExecObject:
            if(rec->obj->type == cObjectMap) {
              ObjectMap *obj = (ObjectMap *) rec->obj;
              first_operand = obj;
            }
            break;
          }
        }
        if(first_operand)
          break;
      }
      TrackerDelList(I_Tracker, sub_list_id);
      TrackerDelIter(I_Tracker, sub_iter_id);
    }
  }

  {

    /* okay, next thing we need to worry about is where we're putting the data.

       Case 1. If the map already exists, then we'll use the existing map points for storing
       the result.

       Case 2. If the operation implies a copy of existing map geometry, then we'll create that
       copy first before performing the calulation.

       Case 3. If the operation implies a new map geometry, then we need to compute that geometry and
       create the map.

     */

    if(!target) {               /* target map doesn't exist... */
      int need_union_geometry = false;
      int need_first_geometry = false;
      switch (operator_) {
      case cMapOperatorSum:
      case cMapOperatorAverage:
      case cMapOperatorMinimum:
      case cMapOperatorMaximum:
      case cMapOperatorDifference:
        need_union_geometry = true;
        break;
      case cMapOperatorUnique:
      case cMapOperatorCopy:
        need_first_geometry = true;
        break;
      }

      if(need_union_geometry) {
        int src_state, trg_state;
        ObjectMapDesc desc;
        target = ObjectMapNew(G);

        ObjectSetName((CObject *) target, name);
        isNew = true;

        for(src_state = src_state_start; src_state < src_state_stop; src_state++) {
          trg_state = src_state + target_state;
          desc.mode = cObjectMap_OrthoMinMaxGrid;       /* Orthorhombic: min, max, 
                                                           spacing, 
                                                           centered over range  */
          desc.init_mode = 0;   /* zeros */
          desc.Grid[0] = 1.0F;
          desc.Grid[1] = 1.0F;
          desc.Grid[2] = 1.0F;

          {
            int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
            float grid_sum[3] = { 0.0F, 0.0F, 0.0F };
            int grid_count = 0;
            int first_extent = true;

            SpecRec *rec;
            while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                            (TrackerRef **) (void *) &rec)) {
              if(rec) {
                /* compute an average grid and get the effective "union" extent */
                switch (rec->type) {
                case cExecObject:
                  if(rec->obj->type == cObjectMap) {

                    ObjectMap *obj = (ObjectMap *) rec->obj;
                    ObjectMapState *ms = obj->State + src_state;
                    if(src_state < obj->NState) {
                      if(ms->Active) {
                        if(first_extent) {
                          copy3f(ms->ExtentMin, desc.MinCorner);
                          copy3f(ms->ExtentMax, desc.MaxCorner);
                          first_extent = false;
                        } else {
                          int b;
                          for(b = 0; b < 3; b++) {
                            if(ms->ExtentMin[b] < desc.MinCorner[b])
                              desc.MinCorner[b] = ms->ExtentMin[b];
                            if(ms->ExtentMax[b] > desc.MaxCorner[b])
                              desc.MaxCorner[b] = ms->ExtentMax[b];
                          }
                        }
                        if(!ObjectMapStateValidXtal(ms)) {
                          /* other general-purpose maps currently handled */
                          int b;
                          for(b = 0; b < 3; b++) {
                            grid_sum[b] += ms->Grid[b];
                          }
                          grid_count++;
                        }
                      }
                    }
                  }
                }
              }
            }
            TrackerDelIter(I_Tracker, iter_id);
            if(grid_count) {
              int b;
              for(b = 0; b < 3; b++) {
                desc.Grid[b] = grid_sum[b] / grid_count;
              }
            }
            if(!first_extent) {
              add3f(desc.Grid, desc.MaxCorner, desc.MaxCorner);
              subtract3f(desc.MinCorner, desc.Grid, desc.MinCorner);
              ObjectMapNewStateFromDesc(G, target, &desc, trg_state, quiet);
              if(trg_state >= target->NState)
                target->NState = trg_state + 1;
              target->State[trg_state].Active = true;
            }
          }
        }
        /* need union geometry */
      } else if(need_first_geometry) {
        if(first_operand) {
          if(ObjectMapNewCopy(G, first_operand, &target, source_state, target_state)) {
            if(target) {
              ObjectSetName((CObject *) target, name);
              isNew = true;
            }
          }
        }
      }
    }
  }

  if(!target) {
    ok = false;
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: cannot find or construct target map.\n" ENDFB(G);
  }

  /* now do the actual operation */

  if(ok && target) {
    int src_state;
    for(src_state = src_state_start; src_state < src_state_stop; src_state++) {
      int trg_state = src_state + target_state;
      ObjectMapState *ms;
      VLACheck(target->State, ObjectMapState, trg_state);

      ms = target->State + target_state;
      if(ms->Active) {
        int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
        int n_pnt = (ms->Field->points->size / ms->Field->points->base_size) / 3;
        float *pnt = (float *) ms->Field->points->data;
        float *r_value = Alloc(float, n_pnt);
        float *l_value = Calloc(float, n_pnt);
        int *present = Calloc(int, n_pnt);
        int *inside = Alloc(int, n_pnt);
        SpecRec *rec;

        while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                        (TrackerRef **) (void *) &rec)) {
          if(rec) {
            if(rec->type == cExecObject) {
              if(rec->obj->type == cObjectMap) {
                ObjectMap *obj = (ObjectMap *) rec->obj;
                ObjectMapInterpolate(obj, src_state, pnt, r_value, inside, n_pnt);
                {
                  int a;
                  float *rv = r_value;
                  float *lv = l_value;
                  int *flg = inside;
                  int *pre = present;

                  switch (operator_) {
                  case cMapOperatorCopy:
                    for(a = 0; a < n_pnt; a++) {
                      if(flg) {
                        *lv = *rv;
                      }
                      rv++;
                      lv++;
                      flg++;
                    }
                    break;
                  case cMapOperatorMinimum:
                    for(a = 0; a < n_pnt; a++) {
                      if(flg) {
                        if(*pre) {
                          if(*lv > *rv)
                            *lv = *rv;
                        } else {        /* first map */
                          *pre = 1;
                          *lv = *rv;
                        }

                      }
                      rv++;
                      lv++;
                      flg++;
                      pre++;
                    }
                    break;
                  case cMapOperatorMaximum:
                    for(a = 0; a < n_pnt; a++) {
                      if(flg) {
                        if(*pre) {
                          if(*lv < *rv)
                            *lv = *rv;
                        } else {        /* first map */
                          *pre = 1;
                          *lv = *rv;
                        }
                      }
                      rv++;
                      lv++;
                      flg++;
                      pre++;
                    }
                    break;
                  case cMapOperatorSum:
                    for(a = 0; a < n_pnt; a++) {
                      if(flg) {
                        *lv += *rv;
                      }
                      rv++;
                      lv++;
                      flg++;
                    }
                    break;
                  case cMapOperatorAverage:
                    for(a = 0; a < n_pnt; a++) {
                      if(flg) {
                        *lv += *rv;
                      }
                      (*pre)++;
                      rv++;
                      lv++;
                      flg++;
                      pre++;
                    }
                    break;
                  case cMapOperatorDifference:
                    if(obj != first_operand) {
                      for(a = 0; a < n_pnt; a++) {
                        if(flg) {
                          *lv -= *rv;
                        }
                        rv++;
                        lv++;
                        flg++;
                      }
                    } else {
                      for(a = 0; a < n_pnt; a++) {
                        if(flg) {
                          *lv += *rv;
                        }
                        rv++;
                        lv++;
                        flg++;
                      }
                    }
                    break;
                  case cMapOperatorUnique:
                    if(obj != first_operand) {
                      for(a = 0; a < n_pnt; a++) {
                        if(flg) {
                          *lv -= *rv;
                        }
                        rv++;
                        lv++;
                        flg++;
                      }
                    } else {
                      for(a = 0; a < n_pnt; a++) {
                        if(flg) {
                          *lv += *rv;
                        }
                        rv++;
                        lv++;
                        flg++;
                      }
                    }

                    break;
                  }
                }
              }
            }
          }
        }

        {
          int a;
          float *lv = l_value;
          int *pre = present;

          switch (operator_) {
          case cMapOperatorUnique:
            lv = l_value;
            for(a = 0; a < n_pnt; a++) {
              if(*lv < 0.0F)
                *lv = 0.0F;
              lv++;
            }
            break;
          case cMapOperatorAverage:
            lv = l_value;
            pre = present;
            for(a = 0; a < n_pnt; a++) {
              if(*pre)
                *lv /= *pre;
              lv++;
              pre++;
            }
          }
        }

        /* copy after calculation so that operand can include target */

        memcpy(ms->Field->data->data, l_value, n_pnt * sizeof(float));

        FreeP(present);
        FreeP(l_value);
        FreeP(r_value);
        FreeP(inside);
        TrackerDelIter(I_Tracker, iter_id);
      }
    }
  }

  /* and finally, update */

  if(target) {
    ObjectMapUpdateExtents(target);
    if(isNew) {
      ExecutiveManageObject(G, &target->Obj, -1, quiet);
    } else {
      ExecutiveDoZoom(G, &target->Obj, false, zoom, true);
    }
    SceneChanged(G);
  }
  TrackerDelList(I_Tracker, list_id);

  return ok;
}


const char * ExecutiveMapGenerate(PyMOLGlobals * G, const char * name, const char * reflection_file, const char * tempFile,
				  char * amplitudes, const char * phases, const char * weights, double reso_low,
				  double reso_high, const char * space_group, double cell[6], int quiet, int zoom)
{
  /* FIXME: this should be returned in memory!! */
  /* In the meantime, use mkstemp and load in Python */
  int ok;

  ok = 0;

  if (weights && (!strncmp(weights,"None",4))) 
    weights=NULL;

  /* printf("Passing to primex driver: space_group=%s, cell=[%f %f %f %f %f %f], reso_high=%f, rseo_low=%f, refl_file=%s, ampl=%s, phases=%s, weights=%s, map_file=%s", space_group, cell[0], cell[1], cell[2], cell[3], cell[4], cell[5], reso_high, reso_low, reflection_file, amplitudes, phases, weights, tempFile); */

#ifndef NO_MMLIBS
  ok = !(primex_pymol_driver2(space_group, cell, reso_high, reso_low, reflection_file, amplitudes,
			    phases, weights, tempFile)); 
#else
  PRINTFB(G, FB_Executive, FB_Errors)
    " Error: MTZ map loading not supported in this PyMOL build.\n" ENDFB(G);
#endif

  if (!ok) 
    return NULL;
  else
    return (const char*) tempFile;

}

int ExecutiveMapNew(PyMOLGlobals * G, const char *name, int type, float *grid,
                    const char *sele, float buffer,
                    float *minCorner,
                    float *maxCorner, int state, int have_corners,
                    int quiet, int zoom, int normalize, float clamp_floor,
                    float clamp_ceiling, float resolution)
{
  CObject *origObj = NULL;
  ObjectMap *objMap;
  ObjectMapState *ms = NULL;
  int a;
  float v[3];
  ObjectMapDesc _md, *md;
  int ok = true;
  int sele0 = SelectorIndexByName(G, sele);
  int isNew = true;
  int n_state;
  int valid_extent = false;
  int st;
  int st_once_flag = true;
  int n_st;
  int extent_state;
  int clamp_flag = (clamp_floor <= clamp_ceiling);

  md = &_md;

  if((state == -2) || (state == -3))    /* TO DO: support per-object states */
    state = SceneGetState(G);

  /* remove object if it already exists */

  origObj = ExecutiveFindObjectByName(G, name);

  if(origObj) {
    if(origObj->type != cObjectMap) {
      ExecutiveDelete(G, origObj->Name);
    } else {
      isNew = false;
    }
  }

  n_st = ExecutiveCountStates(G, NULL);

  for(st = 0; st < n_st; st++) {
    if(state == -1)
      st_once_flag = false;     /* each state, separate map, separate extent */
    if(!st_once_flag)
      state = st;
    extent_state = state;
    if(state <= -3)
      extent_state = -1;
    if(strlen(sele) && (!have_corners)) {
      valid_extent = ExecutiveGetExtent(G, sele, md->MinCorner,
                                        md->MaxCorner, true, extent_state, false);
      /* TODO restrict to state */
    } else {
      valid_extent = 1;
      copy3f(minCorner, md->MinCorner);
      copy3f(maxCorner, md->MaxCorner);
    }
    copy3f(grid, md->Grid);

    subtract3f(md->MaxCorner, md->MinCorner, v);
    for(a = 0; a < 3; a++) {
      if(v[a] < 0.0)
        std::swap(md->MaxCorner[a], md->MinCorner[a]);
    };
    subtract3f(md->MaxCorner, md->MinCorner, v);

    if(buffer < -0.5F) { // buffer == -1
      buffer = SettingGetGlobal_f(G, cSetting_gaussian_resolution);
    }

    if(buffer > 0.0F) {
      for(a = 0; a < 3; a++) {
        md->MinCorner[a] -= buffer;
        md->MaxCorner[a] += buffer;
      }
    }
    md->mode = cObjectMap_OrthoMinMaxGrid;
    md->init_mode = -1;         /* no initialization */

    /* validate grid */
    for(a = 0; a < 3; a++)
      if(md->Grid[a] <= R_SMALL8)
        md->Grid[a] = R_SMALL8;

    if(ok) {
      if(isNew)
        objMap = ObjectMapNew(G);
      else
        objMap = (ObjectMap *) origObj;
      if(objMap) {
        int once_flag = true;
        n_state = SelectorCountStates(G, sele0);
        if(valid_extent)
          for(a = 0; a < n_state; a++) {
            if(state == -5)
              once_flag = false;        /* api: state=-4 = each state, separate map, shared extent */
            if(state == -4)
              state = -1;       /* api: state=-3 all states, but one map */
            if(!once_flag)
              state = a;
            ms = ObjectMapNewStateFromDesc(G, objMap, md, state, quiet);
            if(!ms)
              ok = false;

            if(ok && ms) {

              switch (type) {
              case 0:          /* vdw */
                SelectorMapMaskVDW(G, sele0, ms, 0.0F, state);
                break;
              case 1:          /* coulomb */
                SelectorMapCoulomb(G, sele0, ms, 0.0F, state, false, false, 1.0F);
                break;
              case 2:          /* gaussian */
                SelectorMapGaussian(G, sele0, ms, 0.0F, state, normalize, false, quiet, resolution);
                break;
              case 3:          /* coulomb_neutral */
                SelectorMapCoulomb(G, sele0, ms, 0.0F, state, true, false, 1.0F);
                break;
              case 4:          /* coulomb_local */
                SelectorMapCoulomb(G, sele0, ms,
                                   SettingGetGlobal_f(G, cSetting_coulomb_cutoff), state,
                                   false, true, 2.0F);
                break;
              case 5:          /* gaussian_max */
                SelectorMapGaussian(G, sele0, ms, 0.0F, state, normalize, true, quiet, resolution);
                break;
              }
              if(!ms->Active)
                ObjectMapStatePurge(G, ms);
              else if(clamp_flag) {
                ObjectMapStateClamp(ms, clamp_floor, clamp_ceiling);
              }
            }
            if(once_flag)
              break;
          }

        ObjectSetName((CObject *) objMap, name);
        ObjectMapUpdateExtents(objMap);
        if(isNew) {
          ExecutiveManageObject(G, (CObject *) objMap, -1, quiet);
        } else {
          ExecutiveDoZoom(G, (CObject *) objMap, false, zoom, true);
        }
        isNew = false;
        origObj = (CObject *) objMap;
      }
      SceneChanged(G);
    }
    if(st_once_flag)
      break;
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveSculptIterateAll(PyMOLGlobals * G)
{
  int active = false;
  float center_array[8] = { 0.0F, 0.0F, 0.0F, 0.0F };
  float *center = center_array;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *objMol;
  CGOReset(G->DebugCGO);

  if(SettingGetGlobal_b(G, cSetting_sculpting)) {
    if(!SettingGetGlobal_b(G, cSetting_sculpt_auto_center))
      center = NULL;

    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          objMol = (ObjectMolecule *) rec->obj;
          if(SettingGet_b(G, NULL, objMol->Obj.Setting, cSetting_sculpting)) {
            int state = ObjectGetCurrentState(rec->obj, true);
            if(state<0)
              state = SceneGetState(G);
            if((state > objMol->NCSet) ) {
              if((objMol->NCSet == 1)
                 && SettingGetGlobal_b(G, cSetting_static_singletons)) {
                state = 0;
              }
            }
            ObjectMoleculeSculptIterate(objMol, state,
                                        SettingGet_i(G, NULL, objMol->Obj.Setting,
                                                     cSetting_sculpting_cycles), center);
            active = true;
          }
        }
      }
    }
    if(center && (center[3] > 1.0F)) {
      float pos[3];
      SceneGetCenter(G, pos);
      center[3] = 1.0F / center[3];
      scale3f(center, center[3], center);
      center[7] = 1.0F / center[7];
      scale3f(center + 4, center[7], center + 4);
      subtract3f(center, center + 4, center);
      add3f(pos, center, center);
      ExecutiveCenter(G, NULL, -1, true, false, center, true);
    }
  }
  if (active){
    EditorInvalidateShaderCGO(G);
  }
  return (active);
}


/*========================================================================*/
float ExecutiveSculptIterate(PyMOLGlobals * G, const char *name, int state, int n_cycle)
{
  CObject *obj = ExecutiveFindObjectByName(G, name);
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *objMol;
  float total_strain = 0.0F;

  if(state < 0)
    state = SceneGetState(G);

  if(WordMatchExact(G, name, cKeywordAll, true)) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          objMol = (ObjectMolecule *) rec->obj;
          total_strain += ObjectMoleculeSculptIterate(objMol, state, n_cycle, NULL);
        }
      }
    }
  } else if(!obj) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: object %s not found.\n", name ENDFB(G);
  } else if(obj->type != cObjectMolecule) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: object %s is not a molecular object.\n", name ENDFB(G);
  } else {
    total_strain =
      ObjectMoleculeSculptIterate((ObjectMolecule *) obj, state, n_cycle, NULL);
  }
  return (total_strain);
}


/*========================================================================*/
int ExecutiveSculptActivate(PyMOLGlobals * G, const char *name, int state, int match_state,
                            int match_by_segment)
{
  CObject *obj = ExecutiveFindObjectByName(G, name);
  SpecRec *rec = NULL;
  ObjectMolecule *objMol;
  CExecutive *I = G->Executive;
  int ok = true;
  if(state < 0)
    state = SceneGetState(G);

  if(WordMatchExact(G, name, cKeywordAll, true)) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          objMol = (ObjectMolecule *) rec->obj;
          ObjectMoleculeSculptImprint(objMol, state, match_state, match_by_segment);
        }
      }
    }
  } else if(!obj) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: object %s not found.\n", name ENDFB(G);
    ok = false;
  } else if(obj->type != cObjectMolecule) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: object %s is not a molecular object.\n", name ENDFB(G);
    ok = false;
  } else {
    ObjectMoleculeSculptImprint((ObjectMolecule *) obj, state, match_state,
                                match_by_segment);
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveSculptDeactivate(PyMOLGlobals * G, const char *name)
{
  CObject *obj = ExecutiveFindObjectByName(G, name);
  SpecRec *rec = NULL;
  ObjectMolecule *objMol;
  CExecutive *I = G->Executive;

  int ok = true;

  if(WordMatchExact(G, name, cKeywordAll, true)) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          objMol = (ObjectMolecule *) rec->obj;
          ObjectMoleculeSculptClear(objMol);
        }
      }
    }
  } else if(!obj) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: object %s not found.\n", name ENDFB(G);
    ok = false;
  } else if(obj->type != cObjectMolecule) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Executive-Error: object %s is not a molecular object.\n", name ENDFB(G);
    ok = false;
  } else {
    ObjectMoleculeSculptClear((ObjectMolecule *) obj);
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveSetGeometry(PyMOLGlobals * G, const char *s1, int geom, int valence)
{
  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  ObjectMoleculeOpRec op1;
  int ok = false;

  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op1);
    op1.code = OMOP_SetGeometry;
    op1.i1 = geom;
    op1.i2 = valence;
    op1.i3 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    if(op1.i3)
      ok = true;
  } else {
    ErrMessage(G, "SetGeometry", "Invalid selection.");
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveMapSetBorder(PyMOLGlobals * G, const char *name, float level, int state)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;

  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type == cObjectMap) {
          ObjectMap *obj = (ObjectMap *) rec->obj;
          result = ObjectMapSetBorder(obj, level, state);

          if(result) {
            ExecutiveInvalidateMapDependents(G, obj->Obj.Name);
          }
        }
        break;
      }
    }
  }

  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}

int ExecutiveMapDouble(PyMOLGlobals * G, const char *name, int state)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;

  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type == cObjectMap) {
          ObjectMap *obj = (ObjectMap *) rec->obj;
          result = ObjectMapDouble(obj, state);
          if(result) {
            ExecutiveInvalidateMapDependents(G, obj->Obj.Name);
          }
          if(result && rec->visible)
            SceneChanged(G);
        }
        break;
      }
    }
  }

  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}

int ExecutiveMapHalve(PyMOLGlobals * G, const char *name, int state, int smooth)
{
  CExecutive *I = G->Executive;
  int result = true;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  SpecRec *rec;

  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecObject:
        if(rec->obj->type == cObjectMap) {
          ObjectMap *obj = (ObjectMap *) rec->obj;
          result = ObjectMapHalve(obj, state, smooth);
          if(result) {
            ExecutiveInvalidateMapDependents(G, obj->Obj.Name);
          }
          if(result && rec->visible)
            SceneChanged(G);
        }
        break;
      }
    }
  }

  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);
  return result;
}

int ExecutiveMapTrim(PyMOLGlobals * G, const char *name,
                     const char *sele, float buffer, int map_state, int sele_state, int quiet)
{
  CExecutive *I = G->Executive;
  int result = true;
  float mn[3], mx[3];
  if(ExecutiveGetExtent(G, sele, mn, mx, true, sele_state, false)) {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    SpecRec *rec;

    {
      int a;
      float t;
      for(a = 0; a < 3; a++) {
        mn[a] -= buffer;
        mx[a] += buffer;
        if(mn[a] > mx[a]) {
          t = mn[a];
          mn[a] = mx[a];
          mx[a] = t;
        }
      }
    }
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecObject:
          if(rec->obj->type == cObjectMap) {
            ObjectMap *obj = (ObjectMap *) rec->obj;
            result = result && ObjectMapTrim(obj, map_state, mn, mx, quiet);
            if(result)
              ExecutiveInvalidateMapDependents(G, obj->Obj.Name);
            if(result && rec->visible)
              SceneChanged(G);
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  return result;
}

void ExecutiveSelectRect(PyMOLGlobals * G, BlockRect * rect, int mode)
{
  Multipick smp;
  OrthoLineType buffer, buf2;
  char selName[WordLength] = cLeftButSele;
  char prefix[3] = "";
  int log_box = 0;
  int logging;
  char empty_string[1] = "";
  char *sel_mode_kw = empty_string;

  logging = SettingGetGlobal_i(G, cSetting_logging);
  if(logging)
    log_box = SettingGetGlobal_b(G, cSetting_log_box_selections);
  /*  if(logging==cPLog_pml)
     strcpy(prefix,"_ "); */
  smp.picked = VLAlloc(Picking, 1000);
  smp.x = rect->left;
  smp.y = rect->bottom;
  smp.w = rect->right - rect->left;
  smp.h = rect->top - rect->bottom;
  SceneMultipick(G, &smp);
  if(smp.picked[0].src.index) {
    SelectorCreate(G, cTempRectSele, NULL, NULL, 1, &smp);
    if(log_box)
      SelectorLogSele(G, cTempRectSele);
    switch (mode) {
    case cButModeRect:
      if(mode == cButModeRect) {
        SelectorCreate(G, cLeftButSele, cTempRectSele, NULL, 1, NULL);
        if(log_box) {
          sprintf(buf2, "%scmd.select(\"%s\",\"%s\",enable=1)\n", prefix, cLeftButSele,
                  cTempRectSele);
          PLog(G, buf2, cPLog_no_flush);
        }
      }
      break;
    case cButModeSeleSetBox:
    case cButModeSeleAddBox:
    case cButModeSeleSubBox:
      ExecutiveGetActiveSeleName(G, selName, true, SettingGetGlobal_i(G, cSetting_logging));
      sel_mode_kw = SceneGetSeleModeKeyword(G);
      /* intentional omission of break! */
    case cButModeRectAdd:
    case cButModeRectSub:
      if(SelectorIndexByName(G, selName) >= 0) {
        if((mode == cButModeRectAdd) || (mode == cButModeSeleAddBox)) {
          sprintf(buffer, "(?%s or %s(%s))", selName, sel_mode_kw, cTempRectSele);
          SelectorCreate(G, selName, buffer, NULL, 0, NULL);
          if(log_box) {
            sprintf(buf2, "%scmd.select(\"%s\",\"(%s)\",enable=1)\n", prefix, selName,
                    buffer);
            PLog(G, buf2, cPLog_no_flush);
          }
        } else if((mode == cButModeRectSub) || (mode == cButModeSeleSubBox)) {
          sprintf(buffer, "(%s(?%s) and not %s(%s))", sel_mode_kw, selName, sel_mode_kw,
                  cTempRectSele);
          SelectorCreate(G, selName, buffer, NULL, 0, NULL);
          if(log_box) {
            sprintf(buf2, "%scmd.select(\"%s\",\"%s\",enable=1)\n", prefix, selName,
                    buffer);
            PLog(G, buf2, cPLog_no_flush);
          }
        } else {
          sprintf(buffer, "(%s(?%s))", sel_mode_kw, cTempRectSele);
          SelectorCreate(G, selName, buffer, NULL, 0, NULL);
          if(log_box) {
            sprintf(buf2, "%scmd.select(\"%s\",\"%s\",enable=1)\n", prefix, selName,
                    buffer);
            PLog(G, buf2, cPLog_no_flush);
          }
        }
      } else {
        if((mode == cButModeRectAdd) || (mode == cButModeSeleAddBox)) {
          sprintf(buffer, "%s(?%s)", sel_mode_kw, cTempRectSele);
          SelectorCreate(G, selName, buffer, NULL, 0, NULL);
          if(log_box) {
            sprintf(buf2, "%scmd.select(\"%s\",\"%s\",enable=1)\n", prefix, selName,
                    buffer);
            PLog(G, buf2, cPLog_no_flush);
          }
        } else if((mode == cButModeRectSub) || (mode == cButModeSeleSubBox)) {
          SelectorCreate(G, selName, "(none)", NULL, 0, NULL);
          if(log_box) {
            sprintf(buf2, "%scmd.select(\"%s\",\"(none)\",enable=1)\n", prefix, selName);
            PLog(G, buf2, cPLog_no_flush);
          }
        } else {
          sprintf(buffer, "%s(?%s)", sel_mode_kw, cTempRectSele);
          SelectorCreate(G, selName, buffer, NULL, 0, NULL);
          if(log_box) {
            sprintf(buf2, "%scmd.select(\"%s\",\"%s\",enable=1)\n", prefix, selName,
                    buffer);
            PLog(G, buf2, cPLog_no_flush);
          }
        }
      }
      if(SettingGetGlobal_b(G, cSetting_auto_show_selections)) {
        ExecutiveSetObjVisib(G, selName, true, false);
      }
      break;
    }
    if(log_box) {
      sprintf(buf2, "%scmd.delete(\"%s\")\n", prefix, cTempRectSele);
      PLog(G, buf2, cPLog_no_flush);
      PLogFlush(G);
    }
    ExecutiveDelete(G, cTempRectSele);
    WizardDoSelect(G, selName);
  } else {
    switch (mode) {
    case cButModeSeleSetBox:
      {
        OrthoLineType buf2;
        ObjectNameType name;

        if(ExecutiveGetActiveSeleName(G, name, false, SettingGetGlobal_i(G, cSetting_logging))) {
          ExecutiveSetObjVisib(G, name, 0, false);
          if(SettingGetGlobal_i(G, cSetting_logging)) {
            sprintf(buf2, "cmd.disable('%s')\n", name);
            PLog(G, buf2, cPLog_no_flush);
          }
        }
      }
      break;
    }
  }
  VLAFreeP(smp.picked);
}

int ExecutiveTranslateAtom(PyMOLGlobals * G, const char *sele, float *v, int state, int mode,
                           int log)
{
  int ok = true;
  ObjectMolecule *obj0;
  SelectorTmp tmpsele1(G, sele);
  int sele0 = tmpsele1.getIndex();
  int i0;
  if(sele0 < 0) {
    PRINTFB(G, FB_Executive, FB_Errors)
      "Error: bad selection %s.\n", sele ENDFB(G);
    ok = false;
  } else {
    obj0 = SelectorGetSingleObjectMolecule(G, sele0);
    if(!obj0) {
      PRINTFB(G, FB_Executive, FB_Errors)
        "Error: selection isn't a single atom.\n" ENDFB(G);
      ok = false;
    } else {
      i0 = ObjectMoleculeGetAtomIndex(obj0, sele0);
      if(i0 < 0) {
        PRINTFB(G, FB_Executive, FB_Errors)
          "Error: selection isn't a single atom.\n" ENDFB(G);
        ok = false;
      } else {
        ObjectMoleculeMoveAtom(obj0, state, i0, v, mode, log);
      }
    }
  }
  return (ok);
}

int ExecutiveCombineObjectTTT(PyMOLGlobals * G, const char *name, float *ttt, int reverse_order, int store)
{
  int ok = true;
  CExecutive *I = G->Executive;
  if((!name)||(!name[0])||(!strcmp(name,cKeywordAll))||(!strcmp(name,cKeywordSame))) { 
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      switch(rec->type) {
      case cExecObject:
        {
          CObject *obj = rec->obj;
          if((ObjectGetSpecLevel(rec->obj,0)>=0)||(!strcmp(name,cKeywordAll))) {
            ObjectCombineTTT(obj, ttt, reverse_order, store);
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
          }
        }
        break;
      }
    }
    if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }
  } else { /* pattern */
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {

        switch (rec->type) {
        case cExecObject: 
          {
            CObject *obj = rec->obj;
            ObjectCombineTTT(obj, ttt, reverse_order, store);
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
    if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }

  }
  SceneInvalidate(G);
  return ok;
}

int ExecutiveTranslateObjectTTT(PyMOLGlobals * G, const char *name, float *trans, int store, int quiet)
{
  int ok = true;
  CExecutive *I = G->Executive;
  if((!name)||(!name[0])||(!strcmp(name,cKeywordAll))||(!strcmp(name,cKeywordSame))) { 
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      switch(rec->type) {
      case cExecObject:
        {
          CObject *obj = rec->obj;
          if((ObjectGetSpecLevel(rec->obj,0)>=0)||(!strcmp(name,cKeywordAll))) {
            ObjectTranslateTTT(obj, trans, store);
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
          }
        }
        break;
      }
    }
    if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }
  } else { /* pattern */
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecObject: 
          {
            CObject *obj = rec->obj;
            ObjectTranslateTTT(obj, trans, store);
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
    if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }
  }
  SceneInvalidate(G);
  return ok;
}

int ExecutiveSetObjectTTT(PyMOLGlobals * G, const char *name, const float *ttt, int state, int quiet, int store)
{
  int ok = true;
  CExecutive *I = G->Executive;
  if((!name)||(!name[0])||(!strcmp(name,cKeywordAll))||(!strcmp(name,cKeywordSame))) { 
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      switch(rec->type) {
      case cExecObject:
        {
          CObject *obj = rec->obj;
          if((ObjectGetSpecLevel(rec->obj,0)>=0)||(!strcmp(name,cKeywordAll))) {
            ObjectSetTTT(obj, ttt, state, store);
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
          }
        }
        break;
      }
    }
    if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }
  } else { /* pattern */
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {

        switch (rec->type) {
        case cExecObject: 
          {
            CObject *obj = rec->obj;
             ObjectSetTTT(obj, ttt, state, store);
            if(obj->fInvalidate)
              obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
    if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
      ExecutiveMotionReinterpolate(G);
    }
  }
  SceneInvalidate(G);
  return ok;
}

int ExecutiveGetObjectTTT(PyMOLGlobals * G, const char *name, const float **ttt, int state, int quiet)
{
  CObject *obj = ExecutiveFindObjectByName(G, name);
  int ok = true;

  if(!obj) {
    PRINTFB(G, FB_ObjectMolecule, FB_Errors)
      "Error: object %s not found.\n", name ENDFB(G);
    ok = false;
  } else {
    ObjectGetTTT(obj, ttt, state);
  }
  return (ok);
}

int ExecutiveTransformSelection(PyMOLGlobals * G, int state, const char *s1, int log,
                                float *ttt, int homogenous)
{
  ObjectMolecule *obj = NULL;
  ObjectMolecule **vla = NULL;
  int nObj;
  int ok = true;
  int a;

  SelectorTmp tmpsele1(G, s1);
  int sele = tmpsele1.getIndex();

  if(sele < 0)
    ok = false;
  if(ok) {
    vla = SelectorGetObjectMoleculeVLA(G, sele);
    if(!vla)
      ok = false;
  }
  if(ok) {
    nObj = VLAGetSize(vla);
    for(a = 0; a < nObj; a++) {
      obj = vla[a];
      ObjectMoleculeTransformSelection(obj, state, sele, ttt, log,
          tmpsele1.getName(), homogenous, true);
    }
  }
  SceneInvalidate(G);
  VLAFreeP(vla);
  return (ok);
}

int ExecutiveTransformObjectSelection2(PyMOLGlobals * G, CObject * obj, int state,
                                       const char *s1, int log, float *matrix,
                                       int homogenous, int global)
{
  int ok = true;

  switch (obj->type) {
  case cObjectMolecule:
    {
      int sele = -1;
      ObjectMolecule *objMol = (ObjectMolecule *) obj;

      if(s1 && s1[0]) {
        sele = SelectorIndexByName(G, s1);
        if(sele < 0)
          ok = false;
      }
      if(!ok) {
        PRINTFB(G, FB_ObjectMolecule, FB_Errors)
          "Error: selection object %s not found.\n", s1 ENDFB(G);
      } else {
        ObjectMoleculeTransformSelection(objMol, state, sele, matrix, log, s1, homogenous,
                                         global);
      }
      EditorDihedralInvalid(G, objMol);
      SceneInvalidate(G);
    }
    break;
  case cObjectMap:
    {
      double matrixd[116];
      if(homogenous) {
        convert44f44d(matrix, matrixd);
      } else {
        convertTTTfR44d(matrix, matrixd);
      }
      ObjectMapTransformMatrix((ObjectMap *) obj, state, matrixd);
    }
    break;
  case cObjectGroup:
    {
      double matrixd[116];
      if(homogenous) {
        convert44f44d(matrix, matrixd);
      } else {
        convertTTTfR44d(matrix, matrixd);
      }
      ObjectGroupTransformMatrix((ObjectGroup *) obj, state, matrixd);
    }
    break;
  }
  return (ok);
}

int ExecutiveTransformObjectSelection(PyMOLGlobals * G, const char *name, int state,
                                      const char *s1, int log, float *matrix,
                                      int homogenous, int global)
{
  int ok = true;

  CObject *obj = ExecutiveFindObjectByName(G, name);
  if(obj) {
    return ExecutiveTransformObjectSelection2(G, obj, state, s1, log, matrix, homogenous,
                                              global);
  }
  return ok;
}

int ExecutiveValidName(PyMOLGlobals * G, const char *name)
{
  if(!ExecutiveFindSpec(G, name)) {
    int ignore_case = SettingGetGlobal_b(G, cSetting_ignore_case);

    if(!WordMatchExact(G, name, cKeywordAll, ignore_case))
      if(!WordMatchExact(G, name, cKeywordSame, ignore_case))
        if(!WordMatchExact(G, name, cKeywordCenter, ignore_case))
          if(!WordMatchExact(G, name, cKeywordOrigin, ignore_case))
            return false;
  }
  return true;
}

int ExecutivePhiPsi(PyMOLGlobals * G, const char *s1, ObjectMolecule *** objVLA, int **iVLA,
                    float **phiVLA, float **psiVLA, int state)
{
  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  int result = false;
  ObjectMoleculeOpRec op1;
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op1);
    op1.i1 = 0;
    op1.i2 = state;
    op1.obj1VLA = VLAlloc(ObjectMolecule *, 1000);
    op1.i1VLA = VLAlloc(int, 1000);
    op1.f1VLA = VLAlloc(float, 1000);
    op1.f2VLA = VLAlloc(float, 1000);
    op1.code = OMOP_PhiPsi;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    result = op1.i1;
    VLASize(op1.i1VLA, int, op1.i1);
    VLASize(op1.obj1VLA, ObjectMolecule *, op1.i1);
    VLASize(op1.f1VLA, float, op1.i1);
    VLASize(op1.f2VLA, float, op1.i1);
    *iVLA = op1.i1VLA;
    *objVLA = op1.obj1VLA;
    *phiVLA = op1.f1VLA;
    *psiVLA = op1.f2VLA;
  } else {
    *objVLA = NULL;
    *iVLA = NULL;
    *phiVLA = NULL;
    *psiVLA = NULL;
  }
  return (result);
}

int ExecutiveAlign(PyMOLGlobals * G, const char *s1, const char *s2, const char *mat_file, float gap,
                   float extend, int max_gap, int max_skip, float cutoff, int cycles,
                   int quiet, const char *oname, int state1, int state2,
                   ExecutiveRMSInfo * rms_info, int transform, int reset, float seq_wt,
                   float radius, float scale, float base, float coord_wt, float expect,
                   int window, float ante)
{
  int sele1 = SelectorIndexByName(G, s1);
  int sele2 = SelectorIndexByName(G, s2);
  int *vla1 = NULL;
  int *vla2 = NULL;
  int na, nb;
  int c;
  int ok = true;
  int use_sequence = (mat_file && mat_file[0] && (seq_wt != 0.0F));
  int use_structure = (seq_wt >= 0.0F); /* negative seq_wt means sequence only! */
  ObjectMolecule *mobile_obj = NULL;
  CMatch *match = NULL;

  if(!use_structure)
    window = 0;

  if((scale == 0.0F) && (seq_wt == 0.0F) && (ante < 0.0F) && window)
    ante = window;

  if(ante < 0.0F)
    ante = 0.0F;

  if((sele1 >= 0)) {
    mobile_obj = SelectorGetSingleObjectMolecule(G, sele1);
    if(!mobile_obj) {
      ok = false;
      PRINTFB(G, FB_Executive, FB_Errors)
        " ExecutiveAlign: mobile selection must derive from one object only.\n" ENDFB(G);
    }
  }
  if(ok && (sele1 >= 0) && (sele2 >= 0) && rms_info) {
    vla1 = SelectorGetResidueVLA(G, sele1, use_structure, NULL);
    vla2 = SelectorGetResidueVLA(G, sele2, use_structure, mobile_obj);
    if(vla1 && vla2) {
      na = VLAGetSize(vla1) / 3;
      nb = VLAGetSize(vla2) / 3;
      if(na && nb) {
        match = MatchNew(G, na, nb, window);
        if(match) {
          if(use_sequence) {
            if(ok)
              ok = MatchResidueToCode(match, vla1, na);
            if(ok)
              ok = MatchResidueToCode(match, vla2, nb);
            if(ok)
              ok = MatchMatrixFromFile(match, mat_file, quiet);
            if(ok)
              ok = MatchPreScore(match, vla1, na, vla2, nb, quiet);
          }
          if(use_structure) {
	    /* avoid degenerate alignments */
	    ok = ((na>1) && (nb>1) && ok);
            if(ok) {
              ok = SelectorResidueVLAsTo3DMatchScores(G, match,
                                                      vla1, na, state1,
                                                      vla2, nb, state2, seq_wt,
                                                      radius, scale, base,
                                                      coord_wt, expect);
	    } else {
	      PRINTFB(G, FB_Executive, FB_Errors)
		" ExecutiveAlign: No alignment found.\n" ENDFB(G);
	    }
	  }
          if(ok)
            ok = MatchAlign(match, gap, extend, max_gap, max_skip, quiet, window, ante);
          if(ok) {
            rms_info->raw_alignment_score = match->score;
            rms_info->n_residues_aligned = match->n_pair;
            if(match->pair) {

              c = SelectorCreateAlignments(G, match->pair,
                                           sele1, vla1, sele2, vla2,
                                           "_align1", "_align2", false, false);

              if(c) {
                int mode = 2;
                if(!quiet) {
                  PRINTFB(G, FB_Executive, FB_Actions)
                    " ExecutiveAlign: %d atoms aligned.\n", c ENDFB(G);
                }
                if(oname && oname[0] && reset)
                  ExecutiveDelete(G, oname);
                if(!transform)
                  mode = 1;
                ok = ExecutiveRMS(G, "_align1", "_align2", mode, cutoff, cycles,
                                  quiet, oname, state1, state2, false, 0, rms_info);
              } else {
                if(!quiet) {
                  PRINTFB(G, FB_Executive, FB_Actions)
                    " ExecutiveAlign-Error: atomic alignment failed (mismatched identifiers?).\n"
                    ENDFB(G);
                }
                ok = false;
              }
            }
          }
          MatchFree(match);
        }
      } else {
        ok = false;
        PRINTFB(G, FB_Executive, FB_Errors)
          " ExecutiveAlign: invalid selections for alignment.\n" ENDFB(G);
      }
    }
  }

  VLAFreeP(vla1);
  VLAFreeP(vla2);
  return ok;
}

int ExecutivePairIndices(PyMOLGlobals * G, const char *s1, const char *s2, int state1, int state2,
                         int mode, float cutoff, float h_angle,
                         int **indexVLA, ObjectMolecule *** objVLA)
{
  int result = 0;
  int sele1, sele2;

  sele1 = SelectorIndexByName(G, s1);
  sele2 = SelectorIndexByName(G, s2);
  if((sele1 >= 0) && (sele2 >= 0)) {
    result = SelectorGetPairIndices(G, sele1, state1, sele2, state2,
                                    mode, cutoff, h_angle, indexVLA, objVLA);
  } else {
    ErrMessage(G, "ExecutivePairIndices", "One or more bad selections.");
  }
  return (result);
}

int ExecutiveCartoon(PyMOLGlobals * G, int type, const char *s1)
{
  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  ObjectMoleculeOpRec op1;

  ObjectMoleculeOpRecInit(&op1);
  op1.i2 = 0;
  if(sele1 >= 0) {
    op1.code = OMOP_Cartoon;
    op1.i1 = type;
    op1.i2 = 0;
    op1.i3 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    if (op1.i3>0){
        op1.code = OMOP_INVA;
        op1.i1 = cRepCartoonBit;
        op1.i2 = cRepInvRep;
        ExecutiveObjMolSeleOp(G, sele1, &op1);
    }
  } else {
    ErrMessage(G, "Cartoon", "Invalid selection.");
  }
  return (op1.i2);
}


/*========================================================================*/
float *ExecutiveGetVertexVLA(PyMOLGlobals * G, const char *s1, int state)
{
  /* returns NULL if none found */

  float *result = NULL;
  ObjectMoleculeOpRec op1;
  int sele1;
  sele1 = SelectorIndexByName(G, s1);
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op1);
    op1.nvv1 = 0;
    op1.vv1 = VLAlloc(float, 1000);
    if(state >= 0) {
      op1.cs1 = state;
      op1.code = OMOP_SingleStateVertices;
    } else {
      op1.code = OMOP_VERT;
    }
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    VLASize(op1.vv1, float, op1.nvv1 * 3);
    result = op1.vv1;
  }
  return (result);
}


/*========================================================================*/
PyObject *ExecutiveGetSettingOfType(PyMOLGlobals * G, int index,
                                    const char *object, int state, int type)
{
#ifdef _PYMOL_NOPY
  return NULL;
#else
  /* Assumes blocked Python interpreter */
  PyObject *result = NULL;
  CObject *obj = NULL;
  CSetting **handle = NULL, *set_ptr1 = NULL, *set_ptr2 = NULL;
  int ok = true;

  if(object)
    if(object[0]) {
      obj = ExecutiveFindObjectByName(G, object);
      if(!obj)
        ok = false;
    }
  if(!ok) {
    PRINTFB(G, FB_Executive, FB_Errors)
      " SettingGet-Error: object \"%s\" not found.\n", object ENDFB(G);
    ok = false;
  } else if(obj) {
    handle = obj->fGetSettingHandle(obj, -1);
    if(handle)
      set_ptr1 = *handle;
    if(state >= 0) {
      handle = obj->fGetSettingHandle(obj, state);
      if(handle)
        set_ptr2 = *handle;
      else {
        PRINTFB(G, FB_Executive, FB_Errors)
          " SettingGet-Error: object \"%s\" lacks state %d.\n", object, state + 1
          ENDFB(G);
        ok = false;
      }
    }
  }
  if(ok) {
    switch (type) {
    case cSetting_boolean:
      {
        int value = SettingGet_b(G, set_ptr2, set_ptr1, index);
        result = Py_BuildValue("i", value);
      }
      break;
    case cSetting_int:
      {
        int value = SettingGet_i(G, set_ptr2, set_ptr1, index);
        result = Py_BuildValue("i", value);
      }
      break;
    case cSetting_float:
      {
        float value = SettingGet_f(G, set_ptr2, set_ptr1, index);
        result = Py_BuildValue("f", value);
      }
      break;
    case cSetting_float3:
      {
        const float * value = SettingGet_3fv(G, set_ptr2, set_ptr1, index);
        result = Py_BuildValue("fff", value[0], value[1], value[2]);
      }
      break;
    case cSetting_color:
      {
        int value = SettingGet_color(G, set_ptr2, set_ptr1, index);
        result = Py_BuildValue("i", value);
      }
      break;
    case cSetting_string:
      {
        OrthoLineType buffer = "";
        result = Py_BuildValue("s",
            SettingGetTextPtr(G, set_ptr2, set_ptr1, index, buffer));
      }
      break;
    default:
      result = Py_BuildValue("i", 0);
      break;
    }
  }
  return (result);
#endif

}


/*========================================================================*/
PyObject *ExecutiveGetSettingText(PyMOLGlobals * G, int index, const char *object, int state)
{
#ifdef _PYMOL_NOPY
  return NULL;
#else
  /* Assumes blocked Python interpreter */
  PyObject *result = NULL;
  OrthoLineType buffer = "";
  CObject *obj = NULL;
  CSetting **handle = NULL, *set_ptr1 = NULL, *set_ptr2 = NULL;
  int ok = true;

  if(object)
    if(object[0]) {
      obj = ExecutiveFindObjectByName(G, object);
      if(!obj)
        ok = false;
    }
  if(!ok) {
    PRINTFB(G, FB_Executive, FB_Errors)
      " SettingGet-Error: object \"%s\" not found.\n", object ENDFB(G);
    ok = false;
  } else if(obj) {
    handle = obj->fGetSettingHandle(obj, -1);
    if(handle)
      set_ptr1 = *handle;
    if(state >= 0) {
      handle = obj->fGetSettingHandle(obj, state);
      if(handle)
        set_ptr2 = *handle;
      else {
        PRINTFB(G, FB_Executive, FB_Errors)
          " SettingGet-Error: object \"%s\" lacks state %d.\n", object, state + 1
          ENDFB(G);
        ok = false;
      }
    }
  }
  if(ok) {
    result = Py_BuildValue("s",
        SettingGetTextPtr(G, set_ptr2, set_ptr1, index, buffer));
  }

  return (result);
#endif

}


/*========================================================================*/
PyObject *ExecutiveGetSettingTuple(PyMOLGlobals * G, int index, const char *object, int state)
{                               /* Assumes blocked Python interpreter */
#ifdef _PYMOL_NOPY
  return NULL;
#else
  PyObject *result = NULL;
  CSetting **handle = NULL;
  CObject *obj = NULL;
  int ok = true;
  PRINTFD(G, FB_Executive)
    " ExecutiveGetSettingTuple: object %p state %d\n", object, state ENDFD;

  if(object[0] == 0)            /* global */
    result = SettingGetTuple(G, NULL, NULL, index);
  else {

    if(strlen(object)) {
      obj = ExecutiveFindObjectByName(G, object);
      if(!obj)
        ok = false;
    } else
      ok = false;
    if(!ok) {
      PRINTFB(G, FB_Executive, FB_Errors)
        " Executive: object not found.\n" ENDFB(G);
    } else {
      handle = obj->fGetSettingHandle(obj, state);
      if(handle && (*handle) && index < cSetting_INIT
          && (*handle)->info[index].defined)
        result = SettingGetTuple(G, *handle, NULL, index);
    }
  }
  if(!ok) {
    result = PConvAutoNone(Py_None);
  }
  return (result);
#endif
}


/*========================================================================*/
void ExecutiveSetLastObjectEdited(PyMOLGlobals * G, CObject * o)
{
  CExecutive *I = G->Executive;
  I->LastEdited = o;
}


/*========================================================================*/
CObject *ExecutiveGetLastObjectEdited(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  return (I->LastEdited);
}


/*========================================================================*/
int ExecutiveSaveUndo(PyMOLGlobals * G, const char *s1, int state)
  {
  int sele1;
  ObjectMoleculeOpRec op1;

  if(state < 0)
    state = SceneGetState(G);
  sele1 = SelectorIndexByName(G, s1);
  ObjectMoleculeOpRecInit(&op1);
  op1.i2 = 0;
  if(sele1 >= 0) {
    op1.code = OMOP_SaveUndo;
    op1.i1 = state;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
  }
  return (op1.i2);
}


/*========================================================================*/
int ExecutiveSetTitle(PyMOLGlobals * G, const char *name, int state, const char *text)
{
  int result = false;
  ObjectMolecule *obj;
  obj = ExecutiveFindObjectMoleculeByName(G, name);
  if(!obj) {
    PRINTFB(G, FB_ObjectMolecule, FB_Errors)
      "Error: object %s not found.\n", name ENDFB(G);
  } else {
    result = ObjectMoleculeSetStateTitle(obj, state, text);
  }
  SceneDirty(G);
  return (result);
}


/*========================================================================*/
const char *ExecutiveGetTitle(PyMOLGlobals * G, const char *name, int state)
{
  ObjectMolecule *obj;
  obj = ExecutiveFindObjectMoleculeByName(G, name);
  if(!obj) {
    PRINTFB(G, FB_ObjectMolecule, FB_Errors)
      "Error: object %s not found.\n", name ENDFB(G);
    return NULL;
  }
  return ObjectMoleculeGetStateTitle(obj, state);
}


/*========================================================================*/
void ExecutiveHideSelections(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;

  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecSelection) {
      if(rec->visible) {
        rec->visible = false;
        SceneInvalidate(G);
        SeqDirty(G);
	ReportEnabledChange(G, rec);
      }
    }
  }
}

void ExecutiveInvalidateSelectionIndicators(PyMOLGlobals *G){
  CExecutive *I = G->Executive;
  ExecutiveInvalidateSelectionIndicatorsCGO(G);
  I->selectorTextureSize = 0;
}

void ExecutiveInvalidateSelectionIndicatorsCGO(PyMOLGlobals *G){
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  if (I){
    if (I->selIndicatorsCGO){
      CGOFree(I->selIndicatorsCGO);
      I->selIndicatorsCGO = 0;
    }
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
	  CGOFree(rec->gridSlotSelIndicatorsCGO);	  
      }
    }
  }
}

static void ExecutiveRegenerateTextureForSelector(PyMOLGlobals *G, int round_points, int *widths_arg){
  CExecutive *I = G->Executive;
  unsigned char *temp_buffer = Alloc(unsigned char, widths_arg[0] * widths_arg[0] * 4);
  int a, b;
  float mid_point, disty, distx, dist, wminusd;
  float widths[] = { widths_arg[0]/2.f, widths_arg[1]/2.f, widths_arg[2]/2.f };
  unsigned char *q;
  mid_point = ((widths_arg[0]-1.f)/2.f);
  TextureInitTextTexture(G);
  if (I->selectorTextureAllocatedSize < widths_arg[0]){
    // need to re-allocate a new part of the texture for the selection indicator
    TextureGetPlacementForNewSubtexture(G, widths_arg[0], widths_arg[0], &I->selectorTexturePosX, &I->selectorTexturePosY);
    I->selectorTextureAllocatedSize = widths_arg[0];
  }
  q = temp_buffer;
  if (round_points){
    for(b = 0; b < widths_arg[0]; b++) {
      disty = fabs(mid_point - b);
      for(a = 0; a < widths_arg[0]; a++) {
	distx = fabs(mid_point - a);
	dist = sqrt(distx*distx + disty*disty);
	wminusd = widths[0] - dist;
	if (dist < widths[2]){
	  // white
	  q[0] = q[1] = q[2] = q[3] = 255;
	} else if (dist < widths[1]){
	  // black
	  q[0] = q[1] = q[2] = 0; q[3] = 255;
	} else if (fabs(wminusd) < .5f) {
	  // color plus transparency
	  q[0] = 255;
	  q[1] = 51;
	  q[2] = 153;
	  q[3] = (unsigned char)((wminusd + .5)*255);
	} else if (dist < widths[0]) {
	  // color (pink by default 1.f, .2f, .6f)
	  q[0] = 255;
	  q[1] = 51;
	  q[2] = 153;
          q[3] = 255;
	} else {
	  // black
	  q[0] = q[1] = q[2] = q[3] = 0;
	}
	//	printf("%3d ", q[1]);
	q += 4;
      }
      //      printf("\n");
    }
  } else {
    for(b = 0; b < widths_arg[0]; b++) {
      dist = disty = fabs(mid_point - b);
      for(a = 0; a < widths_arg[0]; a++) {
	distx = fabs(mid_point - a);
	dist = disty;
	if (distx > dist){
	  dist = distx;
	}
	if (dist < widths[2]){
	  // white
	  q[0] = q[1] = q[2] = q[3] = 255;
	} else if (dist < widths[1]){
	  // black
	  q[0] = q[1] = q[2] = 0; q[3] = 255;
	} else {
	  // color (pink by default 1.f, .2f, .6f)
	  q[0] = 255;
	  q[1] = 51;
	  q[2] = 153;
          q[3] = 255;
	}
	//	printf("%3d ", q[1]);
	q += 4;
      }
      //      printf("\n");
    }
  }
  glTexSubImage2D(GL_TEXTURE_2D, 0, I->selectorTexturePosX, I->selectorTexturePosY,
		  widths_arg[0], widths_arg[0], GL_RGBA, GL_UNSIGNED_BYTE, temp_buffer);  
  FreeP(temp_buffer);
}

static void ExecutiveRenderIndicatorCGO(PyMOLGlobals * G, CGO *selIndicatorsCGO){
  CExecutive *I = G->Executive;
  CShaderPrg *shaderPrg;
  float text_texture_dim = TextureGetTextTextureSize(G);
  float textureScale;
  int no_depth = (int) SettingGetGlobal_f(G, cSetting_selection_overlay);
  shaderPrg = G->ShaderMgr->Enable_IndicatorShader();
  if (!shaderPrg)return;
  glEnable(GL_POINT_SPRITE);
  glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
  shaderPrg->SetLightingEnabled(0);
  shaderPrg->SetAttrib4fLocation("a_Color", 1.f, 1.f, 1.f, 1.f);
  shaderPrg->Set1f("g_pointSize", DIP2PIXEL(I->selectorTextureSize));
  shaderPrg->Set2f("textureLookup", I->selectorTexturePosX/text_texture_dim, I->selectorTexturePosY/text_texture_dim);
  textureScale = I->selectorTextureSize/text_texture_dim ;
  shaderPrg->Set2f("textureScale", textureScale, textureScale);
  int v[4];
  glGetIntegerv(GL_VIEWPORT, v);
  shaderPrg->Set4f("viewport", v[0], v[1], v[2], v[3]);
  if(no_depth)
    glDisable(GL_DEPTH_TEST);
  CGORenderGL(selIndicatorsCGO, NULL, NULL, NULL, NULL, NULL);
  if(no_depth)
    glEnable(GL_DEPTH_TEST);
  glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
  glDisable(GL_POINT_SPRITE);
  shaderPrg->Disable();
}

static void ExecutiveSetupIndicatorPassGLImmediate(PyMOLGlobals * G, SpecRec *rec, int pass, float gl_width, int width){
#ifndef PURE_OPENGL_ES_2
  switch (pass){
  case 0:
    if(rec->sele_color < 0)
      glColor3f(1.0F, 0.2F, 0.6F);
    else
      glColor3fv(ColorGet(G, rec->sele_color));
    glPointSize(gl_width);
    break;
  case 1:
    if(width > 2) {
      switch (width) {
      case 1: case 2: case 3:
	glPointSize(1.0F);
	break;
      case 4:
	glPointSize(2.0F);
	break;
      case 5:
	glPointSize(3.0F);
	break;
      case 6: case 7: case 8: case 9:
	glPointSize(4.0F);
	break;
      default:
	glPointSize(6.0F);
	break;
      }
      glColor3f(0.0F, 0.0F, 0.0F);
      break;
    }
  case 2:
    if(width > 4) {
      if(width > 5) {
	glPointSize(2.0F);
      } else {
	glPointSize(1.0F);
      }
      glColor3f(1.0F, 1.0F, 1.0F);
    }
    break;
  }
#endif
}

/*========================================================================*/
void ExecutiveRenderSelections(PyMOLGlobals * G, int curState, int slot, GridInfo *grid)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  int any_active = false;
  int no_depth = (int) SettingGetGlobal_f(G, cSetting_selection_overlay);
  short use_shader = (short) SettingGetGlobal_b(G, cSetting_use_shaders);
  float min_width;
  float gl_width;
  int width;
  int max_width = (int) SettingGetGlobal_f(G, cSetting_selection_width_max);
  float width_scale = SettingGetGlobal_f(G, cSetting_selection_width_scale);
  int round_points = SettingGetGlobal_b(G, cSetting_selection_round_points);
  short inv_indicators = false;
  min_width = SettingGetGlobal_f(G, cSetting_selection_width);
  if(width_scale >= 0.0F) {
    width = (int) ((width_scale *
		    fabs(SettingGetGlobal_f(G, cSetting_stick_radius)) /
		    SceneGetScreenVertexScale(G, NULL)));
    if(width < min_width)
      width = (int) min_width;
    else if(width > max_width)
      width = (int) max_width;
  } else
    width = (int) min_width;
  if(round_points) {
    width = (int) (width * 1.44F);
  }
  gl_width = (float) width;
  if(width > 6) {   /* keep it even above 6 */
    if(width & 0x1) {
      width--;
      gl_width = (float) width;
    }
  }

  if (use_shader){
    if (I->selectorTextureSize!=(int)gl_width || round_points != I->selectorIsRound ){
      inv_indicators = true;
    } else {
      if (slot){
	while(ListIterate(I->Spec, rec, next)) {
	  if(rec->type == cExecObject) {
	    if (SceneGetDrawFlagGrid(G, grid, rec->obj->grid_slot)){
	      if (rec->gridSlotSelIndicatorsCGO){
		ExecutiveRenderIndicatorCGO(G, rec->gridSlotSelIndicatorsCGO);
	      }
	    }
	  }
	}
	rec = NULL;
      } else if (I->selIndicatorsCGO){
	ExecutiveRenderIndicatorCGO(G, I->selIndicatorsCGO);
	return;
      }
    }
  } else {
    inv_indicators = true;
  }
  if (inv_indicators){
      CGOFree(I->selIndicatorsCGO);
    if (slot){
      while(ListIterate(I->Spec, rec, next)) {
	if(rec->type == cExecObject) {
	  if (SceneGetDrawFlagGrid(G, grid, rec->obj->grid_slot)){
	      CGOFree(rec->gridSlotSelIndicatorsCGO);
	  }
	}
      }
    }
  }
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecSelection) {
      if (rec->visible) {
        any_active = true;
        break;
      }
    }
  }

  if(any_active) {
    SpecRec *rec1;
    int sele;
    int vis_only = SettingGetGlobal_b(G, cSetting_selection_visible_only);
    int fog = SettingGetGlobal_b(G, cSetting_depth_cue) && SettingGetGlobal_f(G, cSetting_fog);

    (void)fog;

    rec = NULL;

    if(round_points) {
      glEnable(GL_POINT_SMOOTH);
      glAlphaFunc(GL_GREATER, 0.5F);
      glEnable(GL_ALPHA_TEST);
      glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
    } else {
      glDisable(GL_POINT_SMOOTH);
      glDisable(GL_ALPHA_TEST);
      glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
    }

    if (use_shader && (I->selectorTextureSize!=(int)gl_width || round_points != I->selectorIsRound )){
      int level_widths[] = { 0, 0, 0 };
      level_widths[0] = (int)gl_width;
      if(width > 2) {
	switch (width) {
	case 1: case 2: case 3:
	  level_widths[1] = 1;
	  break;
	case 4:
	  level_widths[1] = 2;
	  break;
	case 5:
	  level_widths[1] = 3;
	  break;
	case 6: case 7: case 8: case 9:
	  level_widths[1] = 4;
	  break;
	default:
	  level_widths[1] = 6;
	  break;
	}
      }
      if(width > 4) {
	if(width > 5) {
	  level_widths[2] = 2;
	} else {
	  level_widths[2] = 1;
	}
      }
      ExecutiveInvalidateSelectionIndicatorsCGO(G);
      ExecutiveRegenerateTextureForSelector(G, round_points, level_widths);
      I->selectorTextureSize = gl_width;
      I->selectorIsRound = round_points;
    }

    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecSelection) {

        if(rec->visible) {
          int enabled = true;
          SpecRec *group_rec = rec->group;
          while(enabled && group_rec) {
            if(!group_rec->visible)
              enabled = false;
            else
              group_rec = group_rec->group;
          }

          if(enabled) {

            sele = SelectorIndexByName(G, rec->name);   /* TODO: speed this up */
            if(sele >= 0) {
	      int pass, totpass = use_shader ? 1 : 3;

	      if (!use_shader){
		if(no_depth)
		  glDisable(GL_DEPTH_TEST);
		glDisable(GL_FOG);
	      }
	      for (pass=0; pass<totpass; pass++){
		if (use_shader){ // there is only one pass anyway
		  if (!slot){
		    I->selIndicatorsCGO = CGONew(G);
		    CGODotwidth(I->selIndicatorsCGO, gl_width);
		    CGOBegin(I->selIndicatorsCGO, GL_POINTS);
		  }
		} else {
		  ExecutiveSetupIndicatorPassGLImmediate(G, rec, pass, gl_width, width);
		  glBegin(GL_POINTS);
		}
		rec1 = NULL;
		while(ListIterate(I->Spec, rec1, next)) {
		  if(rec1->type == cExecObject) {
		    if(rec1->obj->type == cObjectMolecule) {
		      if (SceneGetDrawFlagGrid(G, grid, rec1->obj->grid_slot)){
			if (!use_shader || !slot){
			  ObjectMoleculeRenderSele((ObjectMolecule *) rec1->obj, curState, sele,
						   vis_only SELINDICATORARGVAR);
			} else if (!rec1->gridSlotSelIndicatorsCGO){
			  if (!use_shader){
			    ObjectMoleculeRenderSele((ObjectMolecule *) rec1->obj, curState, sele,
						     vis_only, NULL);
			  } else {
			    CGO *drawArrayCGO = NULL;
			    rec1->gridSlotSelIndicatorsCGO = CGONew(G);
			    CGODotwidth(rec1->gridSlotSelIndicatorsCGO, gl_width);
			    CGOBegin(rec1->gridSlotSelIndicatorsCGO, GL_POINTS);
			    ObjectMoleculeRenderSele((ObjectMolecule *) rec1->obj, curState, sele,
						     vis_only, rec1->gridSlotSelIndicatorsCGO);
			    CGOEnd(rec1->gridSlotSelIndicatorsCGO);
			    CGOStop(rec1->gridSlotSelIndicatorsCGO);
			    drawArrayCGO = CGOCombineBeginEnd(rec1->gridSlotSelIndicatorsCGO, 0);
			    CGOFree(rec1->gridSlotSelIndicatorsCGO);
			    rec1->gridSlotSelIndicatorsCGO = CGOOptimizeToVBONotIndexedNoShader(drawArrayCGO, 0);
			    CGOFree(drawArrayCGO);
			    rec1->gridSlotSelIndicatorsCGO->use_shader = true;
			    ExecutiveRenderIndicatorCGO(G, rec1->gridSlotSelIndicatorsCGO);
			  }
			}
		      } else {
			CGOFree(rec1->gridSlotSelIndicatorsCGO);
		      }
		    }
		  }
		}
		if (use_shader){
		  if (!slot){
		    CGO *drawArrayCGO = NULL;
		    CGOEnd(I->selIndicatorsCGO);
		    CGOStop(I->selIndicatorsCGO);
		    drawArrayCGO = CGOCombineBeginEnd(I->selIndicatorsCGO, 0);
		    CGOFree(I->selIndicatorsCGO);
		    I->selIndicatorsCGO = CGOOptimizeToVBONotIndexedNoShader(drawArrayCGO, 0);
		    CGOFree(drawArrayCGO);
		    if (I->selIndicatorsCGO){
		      I->selIndicatorsCGO->use_shader = true;
		      return ExecutiveRenderSelections(G, curState, slot, grid);
		    } else
		      return;
		  }
		} else {
		  glEnd();
		}
	      }
	      if(fog)
		glEnable(GL_FOG);
	      if(no_depth)
		glEnable(GL_DEPTH_TEST);
            }
          }
        }
      }
    }
    if(!use_shader && round_points) {
      glAlphaFunc(GL_GREATER, 0.05F);
    }
  }
}

/*========================================================================*/
int ExecutiveGetDistance(PyMOLGlobals * G, const char *s0, const char *s1, float *value, int state)
{
  SelectorTmp tmpsele0(G, s0);
  SelectorTmp tmpsele1(G, s1);

  /* TO DO: add support for averaging over multiple states */

  Vector3f v0, v1;
  int sele0 = -1, sele1 = -1;
  int ok = true;

  if((sele0 = tmpsele0.getIndex()) < 0)
    ok = ErrMessage(G, "GetDistance", "Selection 1 invalid.");
  else if((sele1 = tmpsele1.getIndex()) < 0)
    ok = ErrMessage(G, "GetDistance", "Selection 2 invalid.");
  if(ok) {
    if(!SelectorGetSingleAtomVertex(G, sele0, state, v0))
      ok =
        ErrMessage(G, "GetDistance", "Selection 1 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele1, state, v1))
      ok =
        ErrMessage(G, "GetDistance", "Selection 2 doesn't contain a single atom/vertex.");
  }
  if(ok) {
    (*value) = (float) diff3f(v0, v1);
  }
  return ok;
}


/*========================================================================*/
int ExecutiveGetAngle(PyMOLGlobals * G, const char *s0, const char *s1, const char *s2, float *value,
                      int state)
{
  SelectorTmp tmpsele0(G, s0);
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);

  /* TO DO: add support for averaging over multiple states */

  Vector3f v0, v1, v2;
  int sele0 = -1, sele1 = -1, sele2 = -1;
  int ok = true;
  float d1[3], d2[3];
  if((sele0 = tmpsele0.getIndex()) < 0)
    ok = ErrMessage(G, "GetAngle", "Selection 1 invalid.");
  else if((sele1 = tmpsele1.getIndex()) < 0)
    ok = ErrMessage(G, "GetAngle", "Selection 2 invalid.");
  else if((sele2 = tmpsele2.getIndex()) < 0)
    ok = ErrMessage(G, "GetAngle", "Selection 3 invalid.");
  if(ok) {
    if(!SelectorGetSingleAtomVertex(G, sele0, state, v0))
      ok = ErrMessage(G, "GetAngle", "Selection 1 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele1, state, v1))
      ok = ErrMessage(G, "GetAngle", "Selection 2 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele2, state, v2))
      ok = ErrMessage(G, "GetAngle", "Selection 3 doesn't contain a single atom/vertex.");
  }
  if(ok) {
    subtract3f(v0, v1, d1);
    subtract3f(v2, v1, d2);
    (*value) = rad_to_deg(get_angle3f(d1, d2));
  }
  return ok;
}


/*========================================================================*/
int ExecutiveGetDihe(PyMOLGlobals * G, const char *s0, const char *s1, const char *s2, const char *s3,
                     float *value, int state)
{
  SelectorTmp tmpsele0(G, s0);
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  SelectorTmp tmpsele3(G, s3);

  /* TO DO: add support for averaging over multiple states */

  Vector3f v0, v1, v2, v3;
  int sele0 = -1, sele1 = -1, sele2 = -1, sele3 = -1;
  int ok = true;

  if((sele0 = tmpsele0.getIndex()) < 0)
    ok = ErrMessage(G, "GetDihedral", "Selection 1 invalid.");
  else if((sele1 = tmpsele1.getIndex()) < 0)
    ok = ErrMessage(G, "GetDihedral", "Selection 2 invalid.");
  else if((sele2 = tmpsele2.getIndex()) < 0)
    ok = ErrMessage(G, "GetDihedral", "Selection 3 invalid.");
  else if((sele3 = tmpsele3.getIndex()) < 0)
    ok = ErrMessage(G, "GetDihedral", "Selection 4 invalid.");
  if(ok) {
    if(!SelectorGetSingleAtomVertex(G, sele0, state, v0))
      ok =
        ErrMessage(G, "GetDihedral", "Selection 1 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele1, state, v1))
      ok =
        ErrMessage(G, "GetDihedral", "Selection 2 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele2, state, v2))
      ok =
        ErrMessage(G, "GetDihedral", "Selection 3 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele3, state, v3))
      ok =
        ErrMessage(G, "GetDihedral", "Selection 4 doesn't contain a single atom/vertex.");
  }
  if(ok) {
    (*value) = rad_to_deg(get_dihedral3f(v0, v1, v2, v3));
  }
  return ok;
}


/*========================================================================*/
int ExecutiveSetDihe(PyMOLGlobals * G, const char *s0, const char *s1, const char *s2, const char *s3,
                     float value, int state, int quiet)
{
  SelectorTmp tmpsele0(G, s0);
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  SelectorTmp tmpsele3(G, s3);

  Vector3f v0, v1, v2, v3;
  int sele0 = -1, sele1 = -1, sele2 = -1, sele3 = -1;
  int ok = true;
  int save_state;
  float current;
  float change;

  if((sele0 = tmpsele0.getIndex()) < 0)
    ok = ErrMessage(G, "SetDihedral", "Selection 1 invalid.");
  else if((sele1 = tmpsele1.getIndex()) < 0)
    ok = ErrMessage(G, "SetDihedral", "Selection 2 invalid.");
  else if((sele2 = tmpsele2.getIndex()) < 0)
    ok = ErrMessage(G, "SetDihedral", "Selection 3 invalid.");
  else if((sele3 = tmpsele3.getIndex()) < 0)
    ok = ErrMessage(G, "SetDihedral", "Selection 4 invalid.");
  if(ok) {
    if(!SelectorGetSingleAtomVertex(G, sele0, state, v0))
      ok =
        ErrMessage(G, "SetDihedral", "Selection 1 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele1, state, v1))
      ok =
        ErrMessage(G, "SetDihedral", "Selection 2 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele2, state, v2))
      ok =
        ErrMessage(G, "SetDihedral", "Selection 3 doesn't contain a single atom/vertex.");
    if(!SelectorGetSingleAtomVertex(G, sele3, state, v3))
      ok =
        ErrMessage(G, "SetDihedral", "Selection 4 doesn't contain a single atom/vertex.");
  }
  if(ok) {
    current = rad_to_deg(get_dihedral3f(v0, v1, v2, v3));
    change = value - current;
    save_state = SceneGetState(G);
    SceneSetFrame(G, -1, state);        /* KLUDGE ALERT!
                                         * necessary because the editor 
                                         * can only work on the current state...this
                                         * needs to be changed.*/
    EditorSelect(G,
        tmpsele2.getName(),
        tmpsele1.getName(),
        NULL, NULL, false, true, true);
    EditorTorsion(G, change);
    SceneSetFrame(G, -1, save_state);
    if(!quiet) {
      PRINTFB(G, FB_Editor, FB_Actions)
        " SetDihedral: adjusted to %5.3f\n", value ENDFB(G);
    }

  }
  return ok;
}


/*========================================================================*/
float ExecutiveGetArea(PyMOLGlobals * G, const char *s0, int sta0, int load_b)
{
  ObjectMolecule *obj0;
  RepDot *rep;
  CoordSet *cs;
  float result = -1.0F;
  int a, sele0;
  int known_member = -1;
  int is_member;
  int *ati;
  float *area;
  AtomInfoType *ai = NULL;
  ObjectMoleculeOpRec op;

  SelectorTmp tmpsele0(G, s0);
  sele0 = tmpsele0.getIndex();

  if(sele0 < 0) {
    ErrMessage(G, "Area", "Invalid selection.");
  } else {
    obj0 = SelectorGetSingleObjectMolecule(G, sele0);
    if(!(obj0)) {
      if(SelectorCountAtoms(G, sele0, sta0) > 0)
        ErrMessage(G, "Area", "Selection must be within a single object.");
      else
        result = 0.0F;
    } else {
      cs = ObjectMoleculeGetCoordSet(obj0, sta0);
      if(!cs)
        ErrMessage(G, "Area", "Invalid state.");
      else {
        rep = (RepDot *) RepDotDoNew(cs, cRepDotAreaType, sta0);
        if(!rep)
          ErrMessage(G, "Area", "Can't get dot representation.");
        else {

          if(load_b) {
            /* zero out B-values within selection */
            ObjectMoleculeOpRecInit(&op);
            op.code = OMOP_SetB;
            op.f1 = 0.0;
            op.i1 = 0;
            ExecutiveObjMolSeleOp(G, sele0, &op);
          }

          result = 0.0;

          area = rep->A;
          ati = rep->Atom;

          is_member = false;

          for(a = 0; a < rep->N; a++) {

            if(known_member != (*ati)) {
              known_member = (*ati);
              ai = obj0->AtomInfo + known_member;
              is_member = SelectorIsMember(G, ai->selEntry, sele0);
            }

            if(is_member) {
              result += (*area);
              if(load_b)
                ai->b += (*area);
            }
            area++;
            ati++;
          }

          rep->R.fFree((Rep *) rep);    /* free the representation */
        }
      }
    }
  }
  return (result);
}


/*========================================================================*/
char *ExecutiveGetNames(PyMOLGlobals * G, int mode, int enabled_only, const char *s0)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  char *result;
  int size = 0;
  int stlen;
  int sele0 = -1;
  int incl_flag;
  if(s0[0]) {
    sele0 = SelectorIndexByName(G, s0);
  }
  result = VLAlloc(char, 1000);

  while(ListIterate(I->Spec, rec, next)) {
    incl_flag = 0;
    if((rec->type == cExecObject
        && (((!mode) || (mode == 1) || (mode == 3) || (mode == 4))
            || ((rec->obj->type != cObjectGroup) && ((mode == 6) || (mode == 8)))
            || ((rec->obj->type == cObjectGroup) && ((mode == 7) || (mode == 9)))))
       || (rec->type == cExecSelection
           && ((!mode) || (mode == 2) || (mode == 3) || (mode == 5)))
      ) {
      if((mode < 3) || (mode > 7) || (mode == 9) || (rec->name[0] != '_')) {
        if((!enabled_only) || (rec->visible)) {
          stlen = strlen(rec->name);
          incl_flag = 0;
          if(sele0 < 0)
            incl_flag = 1;
          else
            switch (rec->type) {
            case cExecObject:
              if(rec->obj->type == cObjectMolecule) {
                int a;
                ObjectMolecule *obj_mol = (ObjectMolecule *) rec->obj;
                AtomInfoType *ai = obj_mol->AtomInfo;
                for(a = 0; a < obj_mol->NAtom; a++) {
                  if(SelectorIsMember(G, ai->selEntry, sele0)) {
                    incl_flag = 1;
                    break;
                  }
                  ai++;
                }
              }
              break;
            case cExecSelection:
              if(SelectorCheckIntersection(G, sele0, SelectorIndexByName(G, rec->name))) {
                incl_flag = 1;
                break;
              }
              break;
            }
          if(incl_flag) {
            VLACheck(result, char, size + stlen + 1);
            strcpy(result + size, rec->name);
            size += stlen + 1;
          }
        }
      }
    }
  }
  VLASize(result, char, size);
  return (result);
}


/*========================================================================*/
/*
 * Return true if `name` is the name of an object molecule or a named selection
 */
bool ExecutiveIsMoleculeOrSelection(PyMOLGlobals * G, const char *name)
{
  if (!strcmp(name, cKeywordAll) ||
      !strcmp(name, cKeywordSame))
    return true;

  SpecRec *rec = ExecutiveFindSpec(G, name);
  if (rec && (
        (rec->type == cExecObject && rec->obj->type == cObjectMolecule) ||
        (rec->type == cExecSelection)))
    return true;

  return false;
}


/*========================================================================*/
int ExecutiveGetType(PyMOLGlobals * G, const char *name, WordType type)
{
  SpecRec *rec = NULL;
  int ok = true;
  rec = ExecutiveFindSpec(G, name);
  if(!rec) {
    ok = false;
  } else {
    if(rec->type == cExecObject) {
      strcpy(type, "object:");
      if(rec->obj->type == cObjectMolecule)
        strcat(type, "molecule");
      else if(rec->obj->type == cObjectMap)
        strcat(type, "map");
      else if(rec->obj->type == cObjectMesh)
        strcat(type, "mesh");
      else if(rec->obj->type == cObjectSlice)
        strcat(type, "slice");
      else if(rec->obj->type == cObjectSurface)
        strcat(type, "surface");
      else if(rec->obj->type == cObjectMeasurement)
        strcat(type, "measurement");
      else if(rec->obj->type == cObjectCGO)
        strcat(type, "cgo");
      else if(rec->obj->type == cObjectGroup)
        strcat(type, "group");
      else if(rec->obj->type == cObjectVolume)
	strcat(type, "volume");
      else if(rec->obj->type == cObjectAlignment)
       strcat(type, "alignment");
      else if(rec->obj->type == cObjectGadget)
       strcat(type, "ramp");
    } else if(rec->type == cExecSelection) {
      strcpy(type, "selection");
    }
  }
  return (ok);
}


/*========================================================================*/
void ExecutiveUpdateCmd(PyMOLGlobals * G, const char *s0, const char *s1, int sta0, int sta1,
                        int method, int quiet)
{
  SelectorTmp tmpsele0(G, s0);
  SelectorTmp tmpsele1(G, s1);
  int sele0 = tmpsele0.getIndex();
  int sele1 = tmpsele1.getIndex();

  if((sele0 < 0) || (sele1 < 0)) {
    ErrMessage(G, "Update", "One or more invalid input selections.");
  } else {
    SelectorUpdateCmd(G, sele0, sele1, sta0, sta1, method, quiet);
  }
}


/*========================================================================*/
void ExecutiveRenameObjectAtoms(PyMOLGlobals * G, const char *s, int force, int quiet)
{
  int sele;

  sele = SelectorIndexByName(G, s);
  if(sele >= 0) {
    ObjectMoleculeOpRec op;
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_RenameAtoms;
    op.i1 = 0;
    op.i2 = force;
    ExecutiveObjMolSeleOp(G, sele, &op);

    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Actions)
        " Rename: renamed %d atoms.\n", op.i1 ENDFB(G);
    }
  } else {
    ErrMessage(G, " Executive", "invalid selection.");
  }
}


/*========================================================================*/
int ExecutiveInvert(PyMOLGlobals * G, int quiet)
{
  int ok = false;
  ok = EditorInvert(G, quiet);
  return (ok);
}


/*========================================================================*/
void ExecutiveFuse(PyMOLGlobals * G, const char *s0, const char *s1, int mode,
                   int recolor, int move_flag)
{
  int i0 = -1;
  int i1 = -1;
  int sele0, sele1, sele2;
  ObjectMolecule *obj0, *obj1;
  ObjectMoleculeOpRec op;
  int ok = true;
#define tmp_fuse_sele "tmp_fuse_sele"

  SelectorTmp tmpsele0(G, s0);
  SelectorTmp tmpsele1(G, s1);
  sele0 = tmpsele0.getIndex();
  sele1 = tmpsele1.getIndex();

  if(sele0 < 0 || sele1 < 0) {
    ErrMessage(G, "Fuse", "Need two selections");
  } else {
#ifndef _PYMOL_NO_UNDO
#endif
    {
      EditorInactivate(G);
      obj0 = SelectorGetSingleObjectMolecule(G, sele0);
      obj1 = SelectorGetSingleObjectMolecule(G, sele1);
      if(obj0)
        i0 = ObjectMoleculeGetAtomIndex(obj0, sele0);
      if(obj1)
        i1 = ObjectMoleculeGetAtomIndex(obj1, sele1);
      if(obj0 && obj1 && (i0 >= 0) && (i1 >= 0) && (obj0 != obj1)) {
        ObjectMoleculeVerifyChemistry(obj0, -1);
        ObjectMoleculeVerifyChemistry(obj1, -1);

        SelectorCreate(G, tmp_fuse_sele, NULL, obj0, 1, NULL);
        sele2 = SelectorIndexByName(G, tmp_fuse_sele);
        if(mode) {
          ObjectMoleculeOpRecInit(&op);
          op.code = OMOP_PrepareFromTemplate;
          op.ai = obj1->AtomInfo + i1;
          op.i1 = mode;
          op.i2 = 0;
          op.i3 = recolor;
          if(recolor)
            op.i4 = obj1->Obj.Color;
          ExecutiveObjMolSeleOp(G, sele2, &op);
        }
        SelectorDelete(G, tmp_fuse_sele);

        switch (mode) {
        case 0:
        case 1:
        case 2:
          if((obj0->AtomInfo[i0].protons == 1) && (obj1->AtomInfo[i1].protons == 1))
            ok &= ObjectMoleculeFuse(obj1, i1, obj0, i0, 0, move_flag);
          else if((obj0->AtomInfo[i0].protons != 1) && (obj1->AtomInfo[i1].protons != 1))
            ok &= ObjectMoleculeFuse(obj1, i1, obj0, i0, 1, move_flag);
          else
            ErrMessage(G, "Fuse", "Can't fuse between a hydrogen and a non-hydrogen");
          break;
        case 3:
          ok &= ObjectMoleculeFuse(obj1, i1, obj0, i0, 3, false);
          break;
        }
      }
    }
  }
}


/*========================================================================*/
void ExecutiveSpheroid(PyMOLGlobals * G, const char *name, int average)
{                               /* EXPERIMENTAL */
  CExecutive *I = G->Executive;
  CObject *os = NULL;
  ObjectMolecule *obj;
  SpecRec *rec = NULL;

  if(strlen(name)) {
    os = ExecutiveFindObjectByName(G, name);
    if(!os)
      ErrMessage(G, " Executive", "object not found.");
    else if(os->type != cObjectMolecule) {
      ErrMessage(G, " Executive", "bad object type.");
      os = NULL;
    }
  }

  if(os || (!strlen(name))) {   /* sort one or all */
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject)
        if(rec->obj->type == cObjectMolecule)
          if((!os) || (rec->obj == os)) {
            obj = (ObjectMolecule *) rec->obj;
            ObjectMoleculeCreateSpheroid(obj, average);
            ObjectMoleculeInvalidate(obj, cRepAll, cRepInvRep, -1);
          }
    }
    SceneChanged(G);
  }
}


/*========================================================================*/
void ExecutiveRebuildAll(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  PRINTFD(G, FB_Executive)
    " ExecutiveRebuildAll: entered.\n" ENDFD;
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      switch (rec->obj->type) {
      case cObjectMolecule:
        if(SettingGetGlobal_b(G, cSetting_defer_builds_mode))
          ObjectMoleculeInvalidate((ObjectMolecule *) rec->obj, cRepAll, cRepInvPurge,
                                   -1);
        else
          ObjectMoleculeInvalidate((ObjectMolecule *) rec->obj, cRepAll, cRepInvRep, -1);
        break;
      case cObjectMeasurement:
        ObjectDistInvalidateRep((ObjectDist *) rec->obj, cRepAll);
        break;
      case cObjectSurface:
      case cObjectMesh:
      case cObjectSlice:
      case cObjectAlignment:
      case cObjectCGO:
        if(rec->obj->fInvalidate) {
          rec->obj->fInvalidate((CObject *) rec->obj, cRepAll, cRepInvAll, -1);
        }
        break;
      }
    }
  }
  SeqChanged(G);
  SceneChanged(G);
}


/*========================================================================*/
void ExecutiveRebuildAllObjectDist(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      if(rec->obj->type == cObjectMeasurement) {
        ObjectDistInvalidateRep((ObjectDist *) rec->obj, cRepAll);
      }
    }
  }
  SceneInvalidate(G);
}


/*========================================================================*/
void ExecutiveUndo(PyMOLGlobals * G, int dir)
{
  CExecutive *I = G->Executive;
  CObject *o;
  ObjectMolecule *obj = NULL, *compObj;
  SpecRec *rec = NULL;

  o = ExecutiveGetLastObjectEdited(G);
  PRINTFB(G, FB_Executive, FB_Debugging)
  " ExecutiveUndo: last object %p\n", (void *) o ENDFB(G);
  if(o)
    if(o->type == cObjectMolecule)
      obj = (ObjectMolecule *) o;
  /* make sure this is still a real object */
  if(obj) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject)
        if(rec->obj->type == cObjectMolecule) {
          compObj = (ObjectMolecule *) rec->obj;
          if(obj == compObj) {
            ObjectMoleculeUndo(obj, dir);
            break;
          }
        }
    }
  }

}


/*========================================================================*/
void ExecutiveSort(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  ObjectMolecule *obj;
  SpecRec *rec = NULL;
  ObjectMoleculeOpRec op;
  int sele;
  int ok = true;
  if((!name) || (!name[0]))
    name = cKeywordAll;

  {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    int changed = false;
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecAll:
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
              obj = (ObjectMolecule *) rec->obj;
              if (ok)
		ok &= ObjectMoleculeSort(obj);
	      if (ok){
		changed = true;
		sele = SelectorIndexByName(G, rec->name);
		if(sele >= 0) {
		  ObjectMoleculeOpRecInit(&op);
		  op.code = OMOP_INVA;
		  op.i1 = cRepCartoonBit | cRepRibbonBit;
		  op.i2 = cRepInvRep;
		  ExecutiveObjMolSeleOp(G, sele, &op);
		}
	      }
            }
          }
          break;
        case cExecSelection:
          sele = SelectorIndexByName(G, rec->name);
          if(sele >= 0) {
            op.code = OMOP_Sort;
            ExecutiveObjMolSeleOp(G, sele, &op);
            ObjectMoleculeOpRecInit(&op);
            op.code = OMOP_INVA;
            op.i1 = cRepCartoonBit | cRepRibbonBit;
            op.i2 = cRepInvRep;
            ExecutiveObjMolSeleOp(G, sele, &op);
            ObjectMoleculeOpRecInit(&op);
          }
          break;
        case cExecObject:
          if(rec->obj->type == cObjectMolecule) {
            obj = (ObjectMolecule *) rec->obj;
            if (ok)
	      ok &= ObjectMoleculeSort(obj);
            changed = true;
            sele = SelectorIndexByName(G, rec->name);
            if(sele >= 0) {
              ObjectMoleculeOpRecInit(&op);
              op.code = OMOP_INVA;
              op.i1 = cRepCartoonBit | cRepRibbonBit;
              op.i2 = cRepInvRep;
              ExecutiveObjMolSeleOp(G, sele, &op);
            }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
    if(changed)
      SceneChanged(G);
  }
}


/*========================================================================*/
void ExecutiveRemoveAtoms(PyMOLGlobals * G, const char *s1, int quiet)
{
  int sele;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  ObjectMoleculeOpRec op;

  sele = SelectorIndexByName(G, s1);
  if(sele >= 0) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          ObjectMoleculeOpRecInit(&op);
          op.code = OMOP_Remove;
          op.i1 = 0;
          obj = (ObjectMolecule *) rec->obj;
          ObjectMoleculeVerifyChemistry(obj, -1);       /* remember chemistry for later */
          ObjectMoleculeSeleOp(obj, sele, &op);
          if(op.i1) {
            if(!quiet) {
              PRINTFD(G, FB_Editor)
                " ExecutiveRemove-Debug: purging %i of %i atoms in %s\n",
                op.i1, obj->NAtom, obj->Obj.Name ENDFD;
            }
            ObjectMoleculePurge(obj);
            if(!quiet) {
              PRINTFB(G, FB_Editor, FB_Actions)
                " Remove: eliminated %d atoms in model \"%s\".\n",
                op.i1, obj->Obj.Name ENDFB(G);
            }
          }
        }
      }
    }
  }
}


/*========================================================================*/
void ExecutiveAddHydrogens(PyMOLGlobals * G, const char *s1, int quiet, int state, bool legacy)
{
  ObjectMoleculeOpRec op;

  /* Needs 4 passes */
  int passes = legacy ? 4 : 1;
  for (int cnt = 0; cnt < passes; ++cnt) {
    SelectorTmp tmpsele1(G, s1);
    int sele1 = tmpsele1.getIndex();
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_AddHydrogens;        /* 4 passes completes the job */
    op.i1 = state;
    op.i2 = legacy;
    ExecutiveObjMolSeleOp(G, sele1, &op);
  }
}


/*========================================================================*/
void ExecutiveFixHydrogens(PyMOLGlobals * G, const char *s1, int quiet)
{
  int sele1;
  ObjectMoleculeOpRec op;

  sele1 = SelectorIndexByName(G, s1);
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_FixHydrogens;
    ExecutiveObjMolSeleOp(G, sele1, &op);
  }
}


/*========================================================================*/
void ExecutiveFlag(PyMOLGlobals * G, int flag, const char *s1, int action, int quiet)
{
  int sele1;
  OrthoLineType buffer;
  ObjectMoleculeOpRec op;

  sele1 = SelectorIndexByName(G, s1);
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op);
    switch (action) {
    case 0:
      op.code = OMOP_Flag;
      break;
    case 1:
      op.code = OMOP_FlagSet;
      break;
    case 2:
      op.code = OMOP_FlagClear;
      break;
    default:
      op.code = OMOP_Flag;
      break;
    }
    op.i1 = (((unsigned int) 1) << flag);
    op.i2 = ((unsigned int) 0xFFFFFFFF - (((unsigned int) 1) << flag));
    op.i3 = 0;
    op.i4 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op);
    if(Feedback(G, FB_Executive, FB_Actions)) {
      if(!quiet) {
        switch (action) {
        case 0:
          if(op.i3) {
            PRINTF " Flag: flag %d is set in %d of %d atoms.\n", flag, op.i3,
              op.i4 ENDF(G);
          } else {
            PRINTF " Flag: flag %d cleared on all atoms.\n", flag ENDF(G);
          }
          break;
        case 1:
          PRINTF " Flag: flag %d set on %d atoms.\n", flag, op.i3 ENDF(G);
          break;
        case 2:
          PRINTF " Flag: flag %d cleared on %d atoms.\n", flag, op.i3 ENDF(G);
          break;
        }
      }
    }
    if(SettingGetGlobal_b(G, cSetting_auto_indicate_flags)) {
      sprintf(buffer, "(flag %d)", flag);
      SelectorCreate(G, cIndicateSele, buffer, NULL, true, NULL);
      ExecutiveSetObjVisib(G, cIndicateSele, true, false);
      SceneInvalidate(G);
    }
  }

}


/*========================================================================*/
float ExecutiveOverlap(PyMOLGlobals * G, const char *s1, int state1, const char *s2, int state2,
                       float adjust)
{
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  int sele1 = tmpsele1.getIndex();
  int sele2 = tmpsele2.getIndex();

  float result = 0.0;

  if(state1 < 0)
    state1 = 0;
  if(state2 < 0)
    state2 = 0;

  if((sele1 >= 0) && (sele2 >= 0))
    result = SelectorSumVDWOverlap(G, sele1, state1, sele2, state2, adjust);

  return (result);
}


/*========================================================================*/
void ExecutiveProtect(PyMOLGlobals * G, const char *s1, int mode, int quiet)
{
  ObjectMoleculeOpRec op;

  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_Protect;
    op.i1 = mode;
    op.i2 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op);
    if(!quiet) {
      if(Feedback(G, FB_Executive, FB_Actions)) {
        if(op.i2) {
          if(mode) {
            PRINTF " Protect: %d atoms protected from movement.\n", op.i2 ENDF(G);
          } else {
            PRINTF " Protect: %d atoms deprotected.\n", op.i2 ENDF(G);
          }
        }
      }
    }
  }
}


/*========================================================================*/
void ExecutiveMask(PyMOLGlobals * G, const char *s1, int mode, int quiet)
{
  ObjectMoleculeOpRec op;

  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_Mask;
    op.i1 = mode;
    op.i2 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op);
    if(!quiet) {
      if(Feedback(G, FB_Executive, FB_Actions)) {
        if(op.i2) {
          if(mode) {
            PRINTF " Mask: %d atoms masked (cannot be picked or selected).\n",
              op.i2 ENDF(G);
          } else {
            PRINTF " Mask: %d atoms unmasked.\n", op.i2 ENDF(G);
          }
        }
      }
    }
    op.code = OMOP_INVA;        /* need to invalidate all pickable representations */
    op.i1 = cRepsAtomMask;
    op.i2 = cRepInvPick;
    ExecutiveObjMolSeleOp(G, sele1, &op);
  }
}


/*========================================================================*/
int ExecutiveStereo(PyMOLGlobals * G, int flag)
{
  int ok = 1;
  int stereo_mode;

  switch (flag) {
  case -3:
    SettingSet(G, cSetting_chromadepth, 1);
    SceneSetStereo(G, 0);
    break;
  case -1:
    SettingSetGlobal_f(G, cSetting_stereo_shift, -SettingGetGlobal_f(G, cSetting_stereo_shift));
    break;
  default:                     /* -2 */
    SettingSet(G, cSetting_chromadepth, 0);
    {
      stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
      switch (stereo_mode) {
      case 0:                  /* off */
        break;
      case cStereo_quadbuffer:                  /* hardware stereo-in-a-window */
        SceneSetStereo(G, flag);
#ifndef _PYMOL_NOPY
        PSGIStereo(G, flag);    /* does this have any effect anymore? */
#endif
        break;
      default:
        SceneSetStereo(G, flag);
        break;
      }
    }
  }

  // for chromadepth
  G->ShaderMgr->Set_Reload_Bits(RELOAD_VARIABLES);

  SceneDirty(G);
  return (ok);
}


/*========================================================================*/
int ExecutiveRevalence(PyMOLGlobals * G, const char *s1, const char *s2, const char *src,
                       int target_state, int source_state, int reset, int quiet)
{
  /*  register CExecutive *I=G->Executive; */
  int ok = true;

  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  int sele1 = tmpsele1.getIndex();
  int sele2 = tmpsele2.getIndex();

  if((sele1 >= 0) && (sele2 >= 0)) {
    if(src && src[0]) {
      SelectorTmp tmpsele3(G, src);
      int sele3 = tmpsele3.getIndex();

      if(sele3 >= 0) {
        ObjectMolecule *obj3 = SelectorGetSingleObjectMolecule(G, sele3);
        if(!obj3) {
          ok = false;
          PRINTFB(G, FB_Editor, FB_Errors)
            "Editor-Warning: revalence can only source a single object at a time."
            ENDFB(G);
        } else {
          ObjectMoleculeOpRec op;

          ObjectMoleculeOpRecInit(&op);
          op.code = OMOP_RevalenceFromSource;
          op.i1 = sele1;
          op.i2 = sele2;
          op.i3 = target_state;
          op.obj3 = obj3;
          op.i4 = sele3;
          op.i5 = source_state;
          op.i6 = quiet;

          ExecutiveObjMolSeleOp(G, sele1, &op);

          /*
             if(ObjectMoleculeXferValences(obj1,sele1,sele2,target_state,obj3,sele3,source_state,quiet)) {
             ObjectMoleculeVerifyChemistry(obj1,target_state);
             ObjectMoleculeInvalidate(obj1,cRepAll,cRepInvBonds,target_state);
             }
           */

        }
      }
    } else {                    /* guess valences */
      ObjectMoleculeOpRec op;

      ObjectMoleculeOpRecInit(&op);
      op.code = OMOP_RevalenceByGuessing;
      op.i1 = sele1;
      op.i2 = sele2;
      op.i3 = target_state;
      op.i4 = reset;
      op.i6 = quiet;

      ExecutiveObjMolSeleOp(G, sele1, &op);

    }
  }
  return ok;
}


/*========================================================================*/
int ExecutiveBond(PyMOLGlobals * G, const char *s1, const char *s2, int order, int mode, int quiet)
{
  int ok = false;
  int sele1, sele2;
  int cnt;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  int flag = false;
  OrthoLineType sname1 = "", sname2 = "";

  ok_assert(1, SelectorGetTmp(G, s1, sname1) >= 0);
  ok_assert(1, SelectorGetTmp(G, s2, sname2) >= 0);

  sele1 = SelectorIndexByName(G, sname1);
  sele2 = SelectorIndexByName(G, sname2);

  if((sele1 >= 0) && (sele2 >= 0)) {
    ObjectMolecule *obj1 = SelectorGetSingleObjectMolecule(G, sele1);
    ObjectMolecule *obj2 = SelectorGetSingleObjectMolecule(G, sele2);
    if((!obj1) || (!obj2) || (obj1 != obj2)) {
      if((!quiet) && (mode == 1)) {
        PRINTFB(G, FB_Editor, FB_Warnings)
          "Editor-Warning: bonds cannot be created between objects, only within.\n"
          ENDFB(G);
      }
    }
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
          switch (mode) {
          case 1:              /* add */
            cnt = ObjectMoleculeAddBond((ObjectMolecule *) rec->obj, sele1, sele2, order);
            if(cnt) {
              if(!quiet) {
                PRINTFB(G, FB_Editor, FB_Actions)
                  " Bond: %d bonds added to model \"%s\".\n", cnt, rec->obj->Name
                  ENDFB(G);
                flag = true;
              }
            }
            break;
          case 2:              /* adjust */
            cnt =
              ObjectMoleculeAdjustBonds((ObjectMolecule *) rec->obj, sele1, sele2, 1,
                                        order);
            if(cnt) {
              if(!quiet) {
                PRINTFB(G, FB_Editor, FB_Actions)
                  " Valence: %d bond valences adjusted in model \"%s\".\n", cnt,
                  rec->obj->Name ENDFB(G);
                flag = true;
              }
            }
            break;
          case 0:              /* remove */
          default:
            cnt = ObjectMoleculeRemoveBonds((ObjectMolecule *) rec->obj, sele1, sele2);
            if(cnt) {
              if(!quiet) {
                PRINTFB(G, FB_Editor, FB_Actions)
                  " Unbond: %d bonds removed from model \"%s\".\n",
                  cnt, rec->obj->Name ENDFB(G);
              }
              flag = true;
            }
          }
        }
      }
    }
    if(!flag) {
      if(!quiet) {
        switch (mode) {
        case 1:
          PRINTFB(G, FB_Editor, FB_Warnings)
            "Bond-Warning: no bonds added." ENDFB(G);
          break;
        case 2:
          PRINTFB(G, FB_Editor, FB_Warnings)
            "Valence-Warning: no bond valences changed." ENDFB(G);
          break;
        case 0:
        default:
          PRINTFB(G, FB_Editor, FB_Warnings)
            "Unbond-Warning: no bonds removed." ENDFB(G);
          break;
        }
      }
    }

    ok = true;
  } else if(sele1 < 0) {
    ok = ErrMessage(G, "ExecutiveBond", "The first selection contains no atoms.");
  } else if(sele2 < 0) {
    ok = ErrMessage(G, "ExecutiveBond", "The second selection contains no atoms.");
  }

ok_except1:
  SelectorFreeTmp(G, sname1);
  SelectorFreeTmp(G, sname2);

  return ok;
}


/*========================================================================*/
int ExecutiveAngle(PyMOLGlobals * G, float *result, const char *nam,
                   const char *s1, const char *s2, const char *s3, int mode,
                   int labels, int reset, int zoom, int quiet, int state,
                   int state1, int state2, int state3)
{
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  SelectorTmp tmpsele3(G, s3);
  int sele1 = tmpsele1.getIndex();
  int sele2 = (WordMatchExact(G, s2, cKeywordSame, true)) ? sele1 : tmpsele2.getIndex();
  int sele3 = (WordMatchExact(G, s3, cKeywordSame, true)) ? sele2 : tmpsele3.getIndex();

  ObjectDist *obj;
  CObject *anyObj = NULL;
  *result = -1.0F;

  if((sele1 >= 0) && (sele2 >= 0) && (sele3 >= 0)) {
    anyObj = ExecutiveFindObjectByName(G, nam);
    if(anyObj) {
      if(anyObj->type != cObjectMeasurement) {
        ExecutiveDelete(G, nam);
        anyObj = NULL;
      }
    }

    obj = ObjectDistNewFromAngleSele(G, (ObjectDist *) anyObj,
                                     sele1, sele2, sele3,
                                     mode, labels, result, reset, state,
                                     state1, state2, state3);
    if(!obj) {
      if(!quiet)
        ErrMessage(G, "ExecutiveAngle", "No angles found.");
    } else {
      *result = rad_to_deg(*result);
      if(!anyObj) {
        ObjectSetName((CObject *) obj, nam);
        ExecutiveManageObject(G, (CObject *) obj, zoom, quiet);
        ExecutiveSetRepVisib(G, nam, cRepLine, 1);
        if(!labels)
          ExecutiveSetRepVisib(G, nam, cRepLabel, 0);
      }
    }
  } else if(sele1 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveAngle", "The first selection contains no atoms.");
  } else if(sele2 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveAngle", "The second selection contains no atoms.");
  } else if(sele3 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveAngle", "The third selection contains no atoms.");
  }
  return (1);
}


/*========================================================================*/
int ExecutiveDihedral(PyMOLGlobals * G, float *result, const char *nam, const char *s1,
                      const char *s2, const char *s3, const char *s4, int mode,
                      int labels, int reset, int zoom, int quiet, int state)
{
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  SelectorTmp tmpsele3(G, s3);
  SelectorTmp tmpsele4(G, s4);
  int sele1 = tmpsele1.getIndex();
  int sele2 = (WordMatchExact(G, s2, cKeywordSame, true)) ? sele1 : tmpsele2.getIndex();
  int sele3 = (WordMatchExact(G, s3, cKeywordSame, true)) ? sele2 : tmpsele3.getIndex();
  int sele4 = (WordMatchExact(G, s4, cKeywordSame, true)) ? sele3 : tmpsele4.getIndex();

  ObjectDist *obj;
  CObject *anyObj = NULL;
  *result = -1.0F;

  if((sele1 >= 0) && (sele2 >= 0) && (sele3 >= 0) && (sele4 >= 0)) {
    anyObj = ExecutiveFindObjectByName(G, nam);
    if(anyObj) {
      if(anyObj->type != cObjectMeasurement) {
        ExecutiveDelete(G, nam);
        anyObj = NULL;
      }
    }

    obj = ObjectDistNewFromDihedralSele(G, (ObjectDist *) anyObj,
                                        sele1, sele2, sele3, sele4,
                                        mode, labels, result, reset, state);
    if(!obj) {
      if(!quiet)
        ErrMessage(G, "ExecutiveDihedral", "No angles found.");
    } else {
      *result = rad_to_deg(*result);
      if(!anyObj) {
        ObjectSetName((CObject *) obj, nam);
        ExecutiveManageObject(G, (CObject *) obj, zoom, quiet);
        ExecutiveSetRepVisib(G, nam, cRepLine, 1);
        if(!labels)
          ExecutiveSetRepVisib(G, nam, cRepLabel, 0);
      }
    }
  } else if(sele1 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveDihedral", "The first selection contains no atoms.");
  } else if(sele2 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveDihedral", "The second selection contains no atoms.");
  } else if(sele3 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveDihedral", "The third selection contains no atoms.");
  } else if(sele4 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveDihedral", "The fourth selection contains no atoms.");
  }

  return 1;
}

/*
 * Create a distance measurement object
 *
 * result: output pointer for measured distance in Angstrom
 * nam: name of measurement object to create or add to
 * s1: selection expression
 * s2: selection expression or "same" keyword (shortcut for s1 = s2)
 * mode: 0 (any), 1 (bonds), 2 (hbonds), 3 (distance_exclusion), 4 (centroids)
 */
int ExecutiveDist(PyMOLGlobals * G, float *result, const char *nam,
                  const char *s1, const char *s2, int mode, float cutoff,
                  int labels, int quiet, int reset, int state, int zoom,
                  int state1, int state2)
{
  SelectorTmp tmpsele1(G, s1);
  SelectorTmp tmpsele2(G, s2);
  int sele1 = tmpsele1.getIndex();
  int sele2 = (WordMatchExact(G, s2, cKeywordSame, true)) ? sele1 : tmpsele2.getIndex();

  ObjectDist *obj;
  CObject *anyObj = NULL;
  *result = -1.0F;
  /* if the distance 'name' we provided exists, overwrite it, by deleting it by its base class */
  if((sele1 >= 0) && (sele2 >= 0)) {
    anyObj = ExecutiveFindObjectByName(G, nam);
    if(anyObj)
      if(reset || anyObj->type != cObjectMeasurement) {
        ExecutiveDelete(G, nam);
        anyObj = NULL;
      }
    /* create a new distance from the two selections */
    obj = ObjectDistNewFromSele(G, (ObjectDist *) anyObj,
                                sele1, sele2, mode, cutoff, labels, reset, result, state,
                                state1, state2);
    /* could insert obj into sele1's mol's object's DistList and sele2's mol's object's DistList */
    /* if the distance was created, add it to the object list and manage it
     * otherwise, complain and do nothing */
    if(!obj) {
      if(!quiet)
        ErrMessage(G, "ExecutiveDistance", "No such distances found.");
    } else {
      ObjectSetName((CObject *) obj, nam);
      ExecutiveManageObject(G, (CObject *) obj, zoom, quiet);
      ExecutiveSetRepVisib(G, nam, cRepLine, 1);
      if(!labels)
        ExecutiveSetRepVisib(G, nam, cRepLabel, 0);
    }
  } else if(sele1 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveDistance", "The first selection contains no atoms.");
    if(reset)
      ExecutiveDelete(G, nam);
  } else if(sele2 < 0) {
    if(!quiet)
      ErrMessage(G, "ExecutiveDistance", "The second selection contains no atoms.");
    if(reset)
      ExecutiveDelete(G, nam);
  }
  return 1;
}


#if 0
/*========================================================================*/
float ExecutiveDistance(PyMOLGlobals * G, const char *s1, const char *s2)
{
  int sele1, sele2;
  float dist = -1.0;

  ObjectMoleculeOpRec op1;
  ObjectMoleculeOpRec op2;

  ObjectMoleculeOpRecInit(&op1);
  ObjectMoleculeOpRecInit(&op2);
  sele1 = SelectorIndexByName(G, s1);
  op1.i1 = 0;
  op2.i2 = 0;
  if(sele1 >= 0) {
    op1.code = OMOP_SUMC;
    op1.v1[0] = 0.0;
    op1.v1[1] = 0.0;
    op1.v1[2] = 0.0;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
  } else {
    ErrMessage(G, "ExecutiveDistance", "The first selection contains no atoms.");
  }

  sele2 = SelectorIndexByName(G, s2);
  op2.i1 = 0;
  op2.i2 = 0;
  if(sele2 >= 0) {
    op2.code = OMOP_SUMC;
    op2.v1[0] = 0.0;
    op2.v1[1] = 0.0;
    op2.v1[2] = 0.0;
    op2.i1 = 0;
    ExecutiveObjMolSeleOp(G, sele2, &op2);
  } else {
    ErrMessage(G, "ExecutiveDistance", "The second selection contains no atoms.");
  }

  if(op1.i1 && op2.i1) {
    scale3f(op1.v1, 1.0F / op1.i1, op1.v1);
    scale3f(op2.v1, 1.0F / op2.i1, op2.v1);
    dist = (float) diff3f(op1.v1, op2.v1);
    PRINTFB(G, FB_Executive, FB_Results)
      " Distance: %8.3f [%i atom(s) to %i atom(s)]\n", dist, op1.i1, op2.i1 ENDFB(G);
  } else {
    ErrMessage(G, "ExecutiveRMS", "No atoms selected.");
  }
  return (dist);
}
#endif


/*========================================================================*/
char *ExecutiveNameToSeqAlignStrVLA(PyMOLGlobals * G, const char *name, int state, int format,
                                    int quiet)
{
  char *result = NULL;
  if((!name) || (!name[0]) || (strcmp(name, "(all)") == 0)) {
    /* use current alignment as the default */
    name = SettingGetGlobal_s(G, cSetting_seq_view_alignment);
    if(name[0] == 0) {
      SpecRec *rec = NULL;
      CExecutive *I = G->Executive;
      while(ListIterate(I->Spec, rec, next)) {
        if(rec->visible) {
          if(rec->type == cExecObject)
            if(rec->obj->type == cObjectAlignment) {
              name = rec->obj->Name;
              break;
            }
        }
      }
    }
  }
  if(!name) {
    ErrMessage(G, " Executive", "invalid alignment object name.");
  } else {
    CObject *obj = ExecutiveFindObjectByName(G, name);

    if(!obj) {
      ErrMessage(G, " Executive", "alignment object not found.");
    } else if(obj->type != cObjectAlignment) {
      ErrMessage(G, " Executive", "invalid object type.");
    } else {
      ObjectAlignmentAsStrVLA(G, (ObjectAlignment *) obj, state, format, &result);
    }
  }
  return (result);
}


/*========================================================================*/
int ExecutiveSeleToObject(PyMOLGlobals * G, const char *name, const char *s1,
                          int source, int target,
                          int discrete, int zoom, int quiet, int singletons, int copy_properties)
{
  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  int ok = false;
  ObjectNameType valid_name;

  UtilNCopy(valid_name, name, sizeof(valid_name));
  if(SettingGetGlobal_b(G, cSetting_validate_object_names)) {
    ObjectMakeValidName(G, valid_name);
    name = valid_name;
  }
  {
    int exists = (ExecutiveFindObjectMoleculeByName(G, name) != NULL);

    if(sele1 >= 0) {
      ok = SelectorCreateObjectMolecule(G, sele1, name, target,
                                        source, discrete, false, quiet, singletons, copy_properties);
      if(ok) {
        int sele2 = SelectorIndexByName(G, name);
        ObjectMolecule *old_obj, *new_obj;
        old_obj = SelectorGetFirstObjectMolecule(G, sele1);     /* get at least one object */
        new_obj = SelectorGetSingleObjectMolecule(G, sele2);

        /* first we need to make sure that the object being moved
           matches the target with respect to both the TTT and the
           object's state matrix (if any) */

        if(old_obj && new_obj) {
          ExecutiveMatrixCopy(G, old_obj->Obj.Name, new_obj->Obj.Name, 1, 1,    /* TTT mode */
                              source, target, false, 0, quiet);

          ExecutiveMatrixCopy(G, old_obj->Obj.Name, new_obj->Obj.Name, 2, 2,    /* Object state mode */
                              source, target, false, 0, quiet);

          ExecutiveDoZoom(G, (CObject *) new_obj, !exists, zoom, true);
        }
      }
    }
  }
  return ok;
}


/*========================================================================*/
void ExecutiveCopy(PyMOLGlobals * G, const char *src, const char *dst, int zoom)
{
  CObject *os;
  ObjectMolecule *oSrc, *oDst;

  os = ExecutiveFindObjectByName(G, src);
  if(!os)
    ErrMessage(G, " Executive", "object not found.");
  else if(os->type != cObjectMolecule)
    ErrMessage(G, " Executive", "bad object type.");
  else {
    oSrc = (ObjectMolecule *) os;
    oDst = ObjectMoleculeCopy(oSrc);
    if(oDst) {
      strcpy(oDst->Obj.Name, dst);
      ExecutiveManageObject(G, (CObject *) oDst, zoom, false);

      PRINTFB(G, FB_Executive, FB_Actions)
        " Executive: object %s created.\n", oDst->Obj.Name ENDFB(G);
    }
  }
  SceneChanged(G);
}


/*========================================================================*/
void ExecutiveOrient(PyMOLGlobals * G, const char *sele, double *mi,
                     int state, float animate, int complete, float buffer, int quiet)
{
  double egval[3], egvali[3];
  double evect[3][3];
  float m[4][4], mt[4][4];
  float t[3];
  const float _0 = 0.0F;
  int a, b;

  if(!MatrixEigensolveC33d(G, mi, egval, egvali, (double *) (void *) evect)) {

    normalize3d(evect[0]);
    normalize3d(evect[1]);
    normalize3d(evect[2]);

    for(a = 0; a < 3; a++) {
      for(b = 0; b < 3; b++) {
        m[a][b] = (float) evect[b][a];  /* fill columns */
      }
    }

    for(a = 0; a < 3; a++) {    /* expand to 4x4 */
      m[3][a] = 0;
      m[a][3] = 0;
    }
    m[3][3] = 1.0;

    normalize3f(m[0]);          /* cross normalization (probably unnec.)  */
    normalize3f(m[1]);
    normalize3f(m[2]);

    for(a = 0; a < 3; a++)      /* convert to row-major */
      for(b = 0; b < 3; b++)
        mt[a][b] = m[b][a];

    cross_product3f(mt[0], mt[1], t);   /* insure right-handed matrix */
    if(dot_product3f(t, mt[2]) < 0.0) {
      mt[2][0] = -mt[2][0];
      mt[2][1] = -mt[2][1];
      mt[2][2] = -mt[2][2];
    }

    for(a = 0; a < 3; a++)      /* convert back to column major */
      for(b = 0; b < 3; b++)
        m[a][b] = mt[b][a];

    if(animate < 0.0F) {
      if(SettingGetGlobal_b(G, cSetting_animation))
        animate = SettingGetGlobal_f(G, cSetting_animation_duration);
      else
        animate = 0.0F;
    }
    if(animate != 0.0F)
      ScenePrimeAnimation(G);

    {
      float old_mat[16];
      float new_mat[16];
      float x, y, z;
      copy44f(SceneGetMatrix(G), old_mat);

      SceneSetMatrix(G, m[0]);  /* load matrix */

      /* there must  be a more elegant to get the PC on X and the SC
       * on Y then what is shown below, but I couldn't get it to work.
       * I tried swapping the eigen-columns around but either that is 
       * a bogus approach (?) or my code was buggy.  Hence the following...*/

      if((egval[0] < egval[2]) && (egval[2] < egval[1])) {      /* X < Z < Y */
        SceneRotate(G, 90, 1, 0, 0);    /*1<-->2 */
      } else if((egval[1] < egval[0]) && (egval[0] < egval[2])) {       /* Y < X < Z */
        SceneRotate(G, 90, 0, 0, 1);    /*0<-->1 */
      } else if((egval[1] < egval[2]) && (egval[2] < egval[0])) {       /* Y < Z < X */
        SceneRotate(G, 90, 0, 1, 0);    /*1<-->2 */
        SceneRotate(G, 90, 0, 0, 1);    /*0<-->1 */
      } else if((egval[2] < egval[1]) && (egval[1] < egval[0])) {       /* Z < Y < X */
        SceneRotate(G, 90, 0, 1, 0);    /*0<-->2 */
      } else if((egval[2] < egval[0]) && (egval[0] < egval[1])) {       /* Z < X < Y */
        SceneRotate(G, 90, 0, 1, 0);    /*0<-->2 */
        SceneRotate(G, 90, 1, 0, 0);    /*0<-->1 */
      }

      /* now choose orientation that has the least perturbation from the starting matrix */

      copy44f(SceneGetMatrix(G), new_mat);

      x = old_mat[0] * new_mat[0] + old_mat[4] * new_mat[4] + old_mat[8] * new_mat[8];
      y = old_mat[1] * new_mat[1] + old_mat[5] * new_mat[5] + old_mat[9] * new_mat[9];
      z = old_mat[2] * new_mat[2] + old_mat[6] * new_mat[6] + old_mat[10] * new_mat[10];

      if((x > _0) && (y < _0) && (z < _0)) {
        SceneRotate(G, 180, 1, 0, 0);
      } else if((x < _0) && (y > _0) && (z < _0)) {
        SceneRotate(G, 180, 0, 1, 0);
      } else if((x < _0) && (y < _0) && (z > _0)) {
        SceneRotate(G, 180, 0, 0, 1);
      }
    }

    /* X < Y < Z  - do nothing - that's what we want */

    ExecutiveWindowZoom(G, sele, buffer, state, complete, false, quiet);
    if(animate != 0.0F)
      SceneLoadAnimation(G, animate, 0);

  }
}


/*========================================================================*/
int ExecutiveLabel(PyMOLGlobals * G, const char *s1, const char *expr, int quiet, int eval_mode)
{
  int sele1;
  ObjectMoleculeOpRec op1;
  int cnt;

  sele1 = SelectorIndexByName(G, s1);
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op1);
    op1.code = OMOP_LABL;
    op1.s1 = expr;
    op1.i1 = 0;
    op1.i2 = eval_mode;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    cnt = op1.i1;
    op1.code = OMOP_VISI;
    op1.i1 = cRepLabelBit;
    op1.i2 = cVis_SHOW;
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    op1.code = OMOP_INVA;
    op1.i2 = cRepInvVisib;
    ExecutiveObjMolSeleOp(G, sele1, &op1);

    if(!quiet) {
      {
	const char *unlabelledstr = "";
	if (cnt<0){ /* if negative, say unlabelled */
	  cnt = -cnt;
	  unlabelledstr = "un";
	}
      PRINTFB(G, FB_Executive, FB_Actions)
        " Label: %slabelled %i atoms.\n", unlabelledstr, cnt ENDFB(G);
      }
    }
  } else {
    PRINTFB(G, FB_Executive, FB_Warnings)
      " Label: no atoms selected.\n" ENDFB(G);
  }
  return 1;
}


/*========================================================================*/
#ifdef _WEBGL
#else
int ExecutiveIterate(PyMOLGlobals * G, const char *str1, const char *expr, int read_only, int quiet,
                     PyObject * space)
#endif
{
  ObjectMoleculeOpRec op1;
  ObjectMoleculeOpRecInit(&op1);
#ifdef _WEBGL
#endif
  SelectorTmp tmpsele1(G, str1);
  int sele1 = tmpsele1.getIndex();
  op1.i1 = 0;
  if(sele1 >= 0) {
    op1.code = OMOP_ALTR;
    op1.i1 = 0;
    op1.i2 = read_only;
#ifdef _WEBGL
#else
    op1.s1 = expr;
    op1.py_ob1 = space;
#endif
    ExecutiveObjMolSeleOp(G, sele1, &op1);
    if(!quiet) {
      if(!read_only) {
        PRINTFB(G, FB_Executive, FB_Actions)
          " Alter: modified %i atoms.\n", op1.i1 ENDFB(G);
      } else {
        PRINTFB(G, FB_Executive, FB_Actions)
          " Iterate: iterated over %i atoms.\n", op1.i1 ENDFB(G);
      }
    }
  } else {
    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        "ExecutiveIterate: No atoms selected.\n" ENDFB(G);
    }
  }
  return (op1.i1);
}


/*========================================================================*/
int ExecutiveSelectList(PyMOLGlobals * G, const char *sele_name, const char *s1,
                        int *list, int list_len, int state, int mode, int quiet)
{                               /* assumes a blocked Python interpreter */
  int ok = true;
  int n_eval = 0;
  int sele0 = SelectorIndexByName(G, s1);
  int n_sele = 0;
  ObjectMolecule *obj = NULL;
  if(sele0 >= 0)
    obj = SelectorGetSingleObjectMolecule(G, sele0);
  if(obj) {
    int a;
    int index = 0;
    int check_state = true;
    CoordSet *cs = NULL;
    if(state == -2)
      state = SceneGetState(G);
    if(state == -3)
      state = ObjectGetCurrentState(&obj->Obj, true);
    if(state >= 0) {
      cs = ObjectMoleculeGetCoordSet(obj, state);
    } else
      check_state = false;

    if(ok && list) {
      if(list_len) {
        switch (mode) {
        case 0:                /* object indices */
          for(a = 0; a < list_len; a++) {
            list[a]--;          /* convert 1-based indices to 0-based array offsets */
          }
          if(ok)
            n_sele =
              SelectorCreateOrderedFromObjectIndices(G, sele_name, obj, list, list_len);
          break;
        case 1:                /* atom identifier */
        case 2:                /* rank */

          {
            OVOneToAny *o2a = OVOneToAny_New(G->Context->heap);
            AtomInfoType *ai;
            OVstatus res;
            OVreturn_word ret;
            int n_idx = 0;
            int *idx_list = VLAlloc(int, list_len);
            ai = obj->AtomInfo;

            for(a = 0; a < obj->NAtom; a++) {
              ai->temp1 = -1;
              ai++;
            }

            /* create linked list using temp1 as "next" field */

            ai = obj->AtomInfo;
            for(a = 0; a < obj->NAtom; a++) {
              if(mode == 1) {   /* id */
                index = ai[a].id;
              } else            /* rank */
                index = ai[a].rank;
              if((OVreturn_IS_ERROR((res = OVOneToAny_SetKey(o2a, index, a))))) {
                if((OVreturn_IS_ERROR((ret = OVOneToAny_GetKey(o2a, index))))) {
                  ok = false;
                } else {
                  int cur = ret.word;
                  while(1) {
                    if(ai[cur].temp1 < 0) {
                      ai[cur].temp1 = a;
                      break;
                    } else {
                      cur = ai[cur].temp1;
                    }
                  }
                }
              }
            }

            {
              int cur;
              for(a = 0; a < list_len; a++) {
                index = list[a];
                if((OVreturn_IS_OK((ret = OVOneToAny_GetKey(o2a, index))))) {
                  cur = ret.word;
                  while(cur >= 0) {
                    if(check_state) {
                      if(cs) {
                        int ix;
                        if(obj->DiscreteFlag) {
                          if(cs == obj->DiscreteCSet[cur])
                            ix = obj->DiscreteAtmToIdx[a];
                          else
                            ix = -1;
                        } else
                          ix = cs->AtmToIdx[a];
                        if(ix >= 0) {
                          VLACheck(idx_list, int, n_idx);
                          idx_list[n_idx] = cur;
                          n_idx++;
                        }
                      }
                    } else {
                      VLACheck(idx_list, int, n_idx);
                      idx_list[n_idx] = cur;
                      n_idx++;
                    }
                    cur = ai[cur].temp1;
                  }
                }
              }
            }
            if(ok)
              n_sele =
                SelectorCreateOrderedFromObjectIndices(G, sele_name, obj, idx_list,
                                                       n_idx);
            OVOneToAny_DEL_AUTO_NULL(o2a);
            VLAFreeP(idx_list);
          }
          break;

        }
      } else
        SelectorCreateEmpty(G, sele_name, true);
    }
  } else {
    PRINTFB(G, FB_Executive, FB_Errors)
      " SelectList-Error: selection cannot span more than one object.\n" ENDFB(G);
  }
  if(ok) {
    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Actions)
        " SelectList: modified %i atoms.\n", n_eval ENDFB(G);
    }
  } else {
    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        "ExecutiveIterateList: An error occurred.\n" ENDFB(G);
    }
  }
  if(!ok)
    return -1;
  else
    return n_sele;
}


/*========================================================================*/
int ExecutiveIterateList(PyMOLGlobals * G, const char *name,
                         PyObject * list, int read_only, int quiet, PyObject * space)
{
#ifdef _PYMOL_NOPY
  return -1;
#else
  int ok = true;
  int n_eval = 0;
  int sele0 = SelectorIndexByName(G, name);
  PyObject *entry = NULL;
  ObjectMolecule *obj = NULL;
  if(sele0 >= 0)
    obj = SelectorGetSingleObjectMolecule(G, sele0);
  if(obj) {
    int n_atom = obj->NAtom;
    int list_len = 0;
    int a;
    int index = 0;
    const char *expr = NULL;
    if(ok)
      ok = PyList_Check(list);
    if(ok) {
      list_len = PyList_Size(list);
      for(a = 0; a < list_len; a++) {
        if(ok)
          entry = PyList_GetItem(list, a);
        if(ok)
          ok = PyList_Check(entry);
        if(ok)
          ok = (PyList_Size(entry) == 2);
        if(ok)
          ok = PConvPyIntToInt(PyList_GetItem(entry, 0), &index);
        if(ok)
          ok = PConvPyStrToStrPtr(PyList_GetItem(entry, 1), &expr);
        if(ok)
          ok = ((index <= n_atom) && (index > 0));
        if(ok)
        {
          PyCodeObject *expr_co = (PyCodeObject *)Py_CompileString(expr, "", Py_single_input);
	  CoordSet *cs = NULL;
	  if(obj->DiscreteFlag && obj->DiscreteCSet) {
	    cs = obj->DiscreteCSet[index - 1];
	  } else if (obj->NCSet == 1){
	    cs = obj->CSet[0];
	  }
          ok =
            (expr_co != NULL) &&
            PAlterAtom(G, obj, cs, expr_co, read_only, index - 1,
                       space);
          Py_XDECREF(expr_co);
        }
        if(ok)
          n_eval++;
      }
    }
  } else {
    PRINTFB(G, FB_Executive, FB_Errors)
      " AlterList-Error: selection cannot span more than one object.\n" ENDFB(G);
  }
  if(ok) {
    if(!quiet) {
      if(!read_only) {
        PRINTFB(G, FB_Executive, FB_Actions)
          " AlterList: modified %i atoms.\n", n_eval ENDFB(G);
      } else {
        PRINTFB(G, FB_Executive, FB_Actions)
          " IterateList: iterated over %i atoms.\n", n_eval ENDFB(G);
      }
    }
  } else {
    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        "ExecutiveIterateList: An error occurred.\n" ENDFB(G);
    }
  }
  if(!ok)
    return -1;
  else
    return n_eval;
#endif
}


/*========================================================================*/
#ifdef _WEBGL
#else
int ExecutiveIterateState(PyMOLGlobals * G, int state, const char *str1, const char *expr,
                           int read_only, int atomic_props, int quiet, PyObject * space)
#endif
{
#ifdef _WEBGL
#endif
  SelectorTmp tmpsele1(G, str1);
  int sele1 = tmpsele1.getIndex();
  if(sele1 >= 0) {
    int start_state = 0, stop_state = 0;
    ObjectMoleculeOpRec op1;

    if(state >= 0) {
      start_state = state;
      stop_state = state + 1;
    } else {
      if((state == -2) || (state == -3)) {      /* current state, TO DO: effective object state */
        state = SceneGetState(G);
        start_state = state;
        stop_state = state + 1;
      } else if(state == -1) {  /* all states (for the selection) */
        start_state = 0;
        stop_state = SelectorCountStates(G, sele1);
      }
    }
    ObjectMoleculeOpRecInit(&op1);
    op1.i1 = 0;

    for(state = start_state; state < stop_state; state++) {
      op1.code = OMOP_AlterState;
#ifdef _WEBGL
#else
      op1.s1 = expr;
      op1.py_ob1 = space;
#endif
      op1.i2 = state;
      op1.i3 = read_only;
      op1.i4 = atomic_props;
      ExecutiveObjMolSeleOp(G, sele1, &op1);
    }
    if(!read_only) {
#ifndef _PYMOL_NO_UNDO
#endif
      // for dynamic_measures
      ExecutiveUpdateCoordDepends(G, NULL);
    }
    if(!quiet) {
      if(!read_only) {
        PRINTFB(G, FB_Executive, FB_Actions)
          " AlterState: modified %i atom coordinate states.\n", op1.i1 ENDFB(G);
      } else {
        PRINTFB(G, FB_Executive, FB_Actions)
          " IterateState: iterated over %i atom coordinate states.\n", op1.i1 ENDFB(G);
      }
    }
    return op1.i1;
  } else {
    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        "ExecutiveIterateState: No atoms selected.\n" ENDFB(G);
    }
    return 0;
  }
}

typedef struct {
  int priority;
  float vertex[3];
  AtomInfoType *ai;
} FitVertexRec;

static int fVertexOrdered(FitVertexRec * array, int l, int r)
{
  return (array[l].priority <= array[r].priority);
}

static int fAtomOrdered(PyMOLGlobals * G, AtomInfoType ** array, int l, int r)
{
  return (AtomInfoCompare(G, array[l], array[r]));
}

static int fAtomIDOrdered(AtomInfoType ** array, int l, int r)
{
  return (array[l]->id <= array[r]->id);
}

static int fAtomRankOrdered(AtomInfoType ** array, int l, int r)
{
  return (array[l]->rank <= array[r]->rank);
}

static int fAtomTemp1Ordered(AtomInfoType ** array, int l, int r)
{
  return (array[l]->temp1 <= array[r]->temp1);
}

static void PackSortedIndices(int n, int *x, int rec_size, void *data)
{
  int a;
  for(a = 0; a < n; a++) {
    if(a != x[a]) {
      memcpy(((char *) data) + (a * rec_size),
             ((char *) data) + (x[a] * rec_size), rec_size);
    }
  }
}


/*========================================================================*/
int ExecutiveRMS(PyMOLGlobals * G, const char *s1, const char *s2, int mode, float refine,
                 int max_cyc, int quiet, const char *oname, int state1, int state2,
                 int ordered_selections, int matchmaker, ExecutiveRMSInfo * rms_info)
{
  /* mode 0: measure rms without superposition
     mode 1: measure rms with trial superposition
     mode 2: measure rms with actual superposition */

  int sele1, sele2;
  float rms = -1.0;
  int a, b;
  float inv, *f, *f1, *f2;
  ObjectMoleculeOpRec op1;
  ObjectMoleculeOpRec op2;
  OrthoLineType buffer;
  int *flag;
  int ok = true;
  int repeat;
  float v1[3], *v2;
  ObjectAlignment *align_to_update = NULL;

  bool ignore_case = SettingGetGlobal_b(G, cSetting_ignore_case);
  bool ignore_case_chain = SettingGetGlobal_b(G, cSetting_ignore_case_chain);

  int matrix_mode = SettingGetGlobal_i(G, cSetting_matrix_mode);
  if(matrix_mode < 0)
    matrix_mode = 0; /* for now */

  if(matchmaker == -1) {
    /* matchmaker -1 is the same as matchmaker 0 except that the
       selections are not pre-matched prior to calling of this routine */
    matchmaker = 0;
  }

  sele1 = SelectorIndexByName(G, s1);
  sele2 = SelectorIndexByName(G, s2);

  /* this function operates on stored coordinates -- thus transformation 
     matrices will need to be applied to the resulting atoms */

  // get coordinates
  {
    auto sele = sele1;
    auto state = state1;
    auto op = &op1;

    // for both selections
    do {
      ObjectMoleculeOpRecInit(op);

      if(sele >= 0) {
        if(state < 0) {
          op->code = OMOP_AVRT;
        } else {
          op->code = OMOP_StateVRT;
          op->i1 = state;
        }

        op->nvv1 = 0;                       // length of vc1 (number of atoms with coordinates)
        op->vc1 = VLACalloc(int, 1000);     // number of states per atom
        op->vv1 = VLACalloc(float, 1000);   // coordinates (sum over states)

        if(mode == 0)
          op->i2 = true;            /* if measuring current coordinates, then get global txfd values */

        if(matchmaker || (oname && oname[0]))
          op->ai1VLA = VLACalloc(AtomInfoType*, 1000);

        if(ordered_selections)
          op->vp1 = VLAlloc(int, 1000);     // selection member "priority"? (MemberType::tag)

        ExecutiveObjMolSeleOp(G, sele, op);

        for(a = 0; a < op->nvv1; a++) {
          inv = (float) op->vc1[a]; /* average over coordinate sets */
          if(inv) {
            f = op->vv1 + (a * 3);
            scale3f(f, 1.F / inv, f);
          }
        }
      }

      // second iteration done
      if (sele == sele2)
        break;

      sele = sele2;
      state = state2;
      op = &op2;

    } while (true);
  }

  if(op1.vv1 && op2.vv1) {
    if(op1.nvv1 && op2.nvv1) {
      ObjectMolecule *mobile_obj = NULL;

      int n_pair = 0;

      if(!(mobile_obj = SelectorGetSingleObjectMolecule(G, sele1))) {
        if(mode != 2) {
          PRINTFB(G, FB_Executive, FB_Warnings)
            "Executive-Warning: Mobile selection spans more than one object.\n" ENDFB(G);
        } else {
          PRINTFB(G, FB_Executive, FB_Errors)
            "Executive-Error: Mobile selection spans more than one object. Aborting.\n"
            ENDFB(G);
          ok = false;
        }
      }

      if(ok && op1.nvv1 && op2.nvv1 && (matchmaker > 0)) {
        /* matchmaker 0 is the default... by internal atom ordering only */
        int *idx1 = Alloc(int, op1.nvv1);
        int *idx2 = Alloc(int, op2.nvv1);
        int sort_flag = false;
        if(!(idx1 && idx2))
          ok = false;
        else {
          switch (matchmaker) {
          case 1:              /* by atom info-based ordering */
            UtilSortIndexGlobals(G, op1.nvv1, op1.ai1VLA, idx1,
                                 (UtilOrderFnGlobals *) fAtomOrdered);
            UtilSortIndexGlobals(G, op2.nvv1, op2.ai1VLA, idx2,
                                 (UtilOrderFnGlobals *) fAtomOrdered);
            sort_flag = true;
            break;
          case 2:              /* by matching atom identifiers */
            UtilSortIndex(op1.nvv1, op1.ai1VLA, idx1, (UtilOrderFn *) fAtomIDOrdered);
            UtilSortIndex(op2.nvv1, op2.ai1VLA, idx2, (UtilOrderFn *) fAtomIDOrdered);
            sort_flag = true;
            break;
          case 3:              /* by matching atom ranks */
            UtilSortIndex(op1.nvv1, op1.ai1VLA, idx1, (UtilOrderFn *) fAtomRankOrdered);
            UtilSortIndex(op2.nvv1, op2.ai1VLA, idx2, (UtilOrderFn *) fAtomRankOrdered);
            sort_flag = true;
            break;
          case 4:              /* by internal atom indexes (stored in temp1 kludge field) */
            UtilSortIndex(op1.nvv1, op1.ai1VLA, idx1, (UtilOrderFn *) fAtomTemp1Ordered);
            UtilSortIndex(op2.nvv1, op2.ai1VLA, idx2, (UtilOrderFn *) fAtomTemp1Ordered);
            sort_flag = true;
            break;
          }
          if(sort_flag) {
            /* GOD this is SO ugly! */

            if(op1.vv1) {
              float *tmp = VLAlloc(float, op1.nvv1 * 3);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op1.nvv1, idx1, 3 * sizeof(float), op1.vv1, tmp);
                VLAFreeP(op1.vv1);
                op1.vv1 = tmp;
              }
            }
            if(op1.vc1) {
              int *tmp = VLAlloc(int, op1.nvv1);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op1.nvv1, idx1, sizeof(int), op1.vc1, tmp);
                VLAFreeP(op1.vc1);
                op1.vc1 = tmp;
              }
            }
            if(op1.vp1) {
              int *tmp = VLAlloc(int, op1.nvv1);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op1.nvv1, idx1, sizeof(int), op1.vp1, tmp);
                VLAFreeP(op1.vp1);
                op1.vp1 = tmp;
              }
            }
            if(op1.ai1VLA) {
              AtomInfoType **tmp = VLACalloc(AtomInfoType *, op1.nvv1);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op1.nvv1, idx1, sizeof(AtomInfoType *), op1.ai1VLA,
                                       tmp);
                VLAFreeP(op1.ai1VLA);
                op1.ai1VLA = tmp;
              }
            }

            if(op2.vv1) {
              float *tmp = VLAlloc(float, op2.nvv1 * 3);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op2.nvv1, idx2, 3 * sizeof(float), op2.vv1, tmp);
                VLAFreeP(op2.vv1);
                op2.vv1 = tmp;
              }
            }
            if(op2.vc1) {
              int *tmp = VLAlloc(int, op2.nvv1);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op2.nvv1, idx2, sizeof(int), op2.vc1, tmp);
                VLAFreeP(op2.vc1);
                op2.vc1 = tmp;
              }
            }
            if(op2.vp1) {
              int *tmp = VLAlloc(int, op2.nvv1);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op2.nvv1, idx2, sizeof(int), op2.vp1, tmp);
                VLAFreeP(op2.vp1);
                op2.vp1 = tmp;
              }
            }
            if(op2.ai1VLA) {
              AtomInfoType **tmp = VLACalloc(AtomInfoType *, op2.nvv1);
              if(!tmp)
                ok = false;
              else {
                UtilApplySortedIndices(op2.nvv1, idx2, sizeof(AtomInfoType *), op2.ai1VLA,
                                       tmp);
                VLAFreeP(op2.ai1VLA);
                op2.ai1VLA = tmp;
              }
            }

          }
        }

        if(matchmaker != 0) {
          int n1 = 0, n2 = 0, c1 = 0, c2 = 0;
          int cmp;

          while((n1 < op1.nvv1) && (n2 < op2.nvv1)) {
            cmp = 0;
            switch (matchmaker) {
            case 1:            /* insure that AtomInfoType matches */
              if(AtomInfoMatch(G, op1.ai1VLA[n1], op2.ai1VLA[n2], ignore_case, ignore_case_chain))
                cmp = 0;
              else
                cmp = AtomInfoCompare(G, op1.ai1VLA[n1], op2.ai1VLA[n2]);
              printf("%d-%d %d-%d: %d\n", c1, n1, c2, n2, cmp);
              break;
            case 2:            /* ID */
            case 3:            /* rank */
              {
                int val1;
                int val2;

                switch (matchmaker) {
                case 2:        /* ID */
                  val1 = op1.ai1VLA[n1]->id;
                  val2 = op2.ai1VLA[n2]->id;
                  break;
                case 3:        /* rank */
                  val1 = op1.ai1VLA[n1]->rank;
                  val2 = op2.ai1VLA[n2]->rank;
                  break;
                case 4:        /* index (via temp1) */
                  val1 = op1.ai1VLA[n1]->temp1;
                  val2 = op2.ai1VLA[n2]->temp1;
                  break;
                default:
                  val1 = 0;
                  val2 = 0;
                  break;
                }
                if(val1 == val2)
                  cmp = 0;
                else if(val1 < val2)
                  cmp = -1;
                else
                  cmp = 1;
              }
              break;
            }
            if(!cmp) {          /* match found */
              idx1[c1++] = n1++;
              idx2[c2++] = n2++;
              n_pair++;
            } else if(cmp < 0) {        /* op1 below op2 */
              n1++;
            } else {            /* op2 below op1 */
              n2++;
            }
          }

          if(n_pair) {
            if(op1.vv1)
              PackSortedIndices(n_pair, idx1, 3 * sizeof(float), op1.vv1);
            if(op1.vc1)
              PackSortedIndices(n_pair, idx1, sizeof(int), op1.vc1);
            if(op1.vp1)
              PackSortedIndices(n_pair, idx1, sizeof(int), op1.vp1);
            if(op1.ai1VLA)
              PackSortedIndices(n_pair, idx1, sizeof(AtomInfoType *), op1.ai1VLA);

            if(op2.vv1)
              PackSortedIndices(n_pair, idx2, 3 * sizeof(float), op2.vv1);
            if(op2.vc1)
              PackSortedIndices(n_pair, idx2, sizeof(int), op2.vc1);
            if(op2.vp1)
              PackSortedIndices(n_pair, idx2, sizeof(int), op2.vp1);
            if(op2.ai1VLA)
              PackSortedIndices(n_pair, idx2, sizeof(AtomInfoType *), op2.ai1VLA);
          }
        }
        FreeP(idx1);
        FreeP(idx2);
      } else if(op1.nvv1 != op2.nvv1) {
        sprintf(buffer, "Atom counts between selections don't match (%d vs %d)",
                op1.nvv1, op2.nvv1);
        ErrMessage(G, "ExecutiveRMS", buffer);
        n_pair = 0;
        ok = false;
      } else {
        n_pair = 0;
        for(a = 0; a < op1.nvv1; ++a) { // for atoms in selection
          if (op1.vc1[a] && op2.vc1[a]) { // check state counts
            if (n_pair < a) { // copy over if necessary
              copy3(op1.vv1 + 3 * a, op1.vv1 + 3 * n_pair);
              copy3(op2.vv1 + 3 * a, op2.vv1 + 3 * n_pair);
              if(op1.ai1VLA) op1.ai1VLA[n_pair] = op1.ai1VLA[a];
              if(op2.ai1VLA) op2.ai1VLA[n_pair] = op2.ai1VLA[a];
              if(op1.vp1) op1.vp1[n_pair] = op1.vp1[a];
              if(op2.vp1) op2.vp1[n_pair] = op2.vp1[a];
              op1.vc1[n_pair] = op1.vc1[a];
              op2.vc1[n_pair] = op2.vc1[a];
            }
            ++n_pair;
          }
        }
      }

      if(n_pair) {
        /* okay -- we're on track to do an alignment */

        if(ordered_selections && op1.vp1 && op2.vp1) {
          /* if we expected ordered selections and have priorities, 
             then we may need to sort vertices */

          int sort_flag1 = false, sort_flag2 = false;
          int well_defined1 = true, well_defined2 = true;

          for(a = 0; a < (n_pair - 1); a++) {
            /*          printf("op1 vertex %d priority %d\n",a,op1.vp1[a]);
               printf("op2 vertex %d priority %d\n",a,op2.vp1[a]); */

            if(op1.vp1[a] > op1.vp1[a + 1])
              sort_flag1 = true;
            else if(op1.vp1[a] == op1.vp1[a + 1])
              well_defined1 = false;
            if(op2.vp1[a] > op2.vp1[a + 1])
              sort_flag2 = true;
            else if(op2.vp1[a] == op2.vp1[a + 1])
              well_defined2 = false;
          }

          if(sort_flag1 || sort_flag2) {
            if(!(well_defined1 || well_defined2)) {
              PRINTFB(G, FB_Executive, FB_Warnings)
                "Executive-Warning: Ordering requested but not well defined.\n" ENDFB(G);
            } else {
              FitVertexRec *vert = Alloc(FitVertexRec, n_pair);

              if(sort_flag1) {
                float *src, *dst;
                src = op1.vv1;
                for(a = 0; a < n_pair; a++) {
                  vert[a].priority = op1.vp1[a];
                  dst = vert[a].vertex;
                  copy3f(src, dst);
                  src += 3;
                }
                UtilSortInPlace(G, vert, n_pair, sizeof(FitVertexRec),
                                (UtilOrderFn *) fVertexOrdered);
                dst = op1.vv1;
                for(a = 0; a < n_pair; a++) {
                  src = vert[a].vertex;
                  copy3f(src, dst);
                  dst += 3;
                }
              }

              if(sort_flag2) {
                float *src, *dst;
                src = op2.vv1;
                for(a = 0; a < n_pair; a++) {
                  vert[a].priority = op2.vp1[a];
                  dst = vert[a].vertex;
                  copy3f(src, dst);
                  src += 3;
                }
                UtilSortInPlace(G, vert, n_pair, sizeof(FitVertexRec),
                                (UtilOrderFn *) fVertexOrdered);
                dst = op2.vv1;
                for(a = 0; a < n_pair; a++) {
                  src = vert[a].vertex;
                  copy3f(src, dst);
                  dst += 3;
                }
              }

              FreeP(vert);
            }
          }
        }

        if(rms_info) {
          rms_info->initial_n_atom = n_pair;
          rms_info->n_cycles_run = 0;
          rms_info->final_n_atom = n_pair;      /* in case there is no refinement */
        }

        if(mode != 0) {
          rms = MatrixFitRMSTTTf(G, n_pair, op1.vv1, op2.vv1, NULL, op2.ttt);
          if(rms_info) {
            rms_info->initial_rms = rms;
            rms_info->final_rms = rms;
          }
          repeat = true;
          b = 0;
          while(repeat) {
            repeat = false;
            b++;
            if(b > max_cyc)
              break;
            if((refine > R_SMALL4) && (rms > R_SMALL4)) {
              int n_next = n_pair;
              AtomInfoType **ai1, **ai2;

              flag = Alloc(int, n_pair);

              if(flag) {
                for(a = 0; a < n_pair; a++) {
                  MatrixTransformTTTfN3f(1, v1, op2.ttt, op1.vv1 + (a * 3));
                  v2 = op2.vv1 + (a * 3);
                  if((diff3f(v1, v2) / rms) > refine) {
                    flag[a] = false;
                    repeat = true;
                  } else
                    flag[a] = true;
                }
                f1 = op1.vv1;
                f2 = op2.vv1;
                ai1 = op1.ai1VLA;
                ai2 = op2.ai1VLA;
                for(a = 0; a < n_pair; a++) {
                  if(!flag[a]) {
                    n_next--;
                  } else {
                    copy3f(op1.vv1 + (3 * a), f1);
                    copy3f(op2.vv1 + (3 * a), f2);
                    f1 += 3;
                    f2 += 3;
                    if(ai1 && ai2) {    /* make sure we keep track of which atoms are aligned */
                      *(ai1++) = op1.ai1VLA[a];
                      *(ai2++) = op2.ai1VLA[a];
                    }
                  }
                }
                if(!quiet && (n_next != n_pair)) {
                  PRINTFB(G, FB_Executive, FB_Actions)
                    " ExecutiveRMS: %d atoms rejected during cycle %d (RMSD=%0.2f).\n",
                    n_pair - n_next, b, rms ENDFB(G);
                }
                n_pair = n_next;
                FreeP(flag);
                if(n_pair) {
                  rms = MatrixFitRMSTTTf(G, n_pair, op1.vv1, op2.vv1, NULL, op2.ttt);
                  if(rms_info) {
                    rms_info->n_cycles_run = b;
                    rms_info->final_n_atom = n_pair;
                    rms_info->final_rms = rms;
                  }
                } else
                  break;
              }
            }
          }
        } else {                /* mode == 0 -- simple RMS, with no coordinate movement */
          rms = MatrixGetRMS(G, n_pair, op1.vv1, op2.vv1, NULL);
          if(rms_info) {
            rms_info->initial_rms = rms;
            rms_info->final_rms = rms;
          }
        }
      }
      if(!n_pair) {
        PRINTFB(G, FB_Executive, FB_Results)
          " Executive: Error -- no atoms left after refinement!\n" ENDFB(G);
        ok = false;
      }

      if(ok) {
        if(!quiet) {
          PRINTFB(G, FB_Executive, FB_Results)
            " Executive: RMSD = %8.3f (%d to %d atoms)\n", rms, n_pair, n_pair ENDFB(G);
        }
        if(oname && oname[0]) {
            int align_state = state2;
            ObjectMolecule *trg_obj = SelectorGetSingleObjectMolecule(G, sele2);

            if(align_state < 0) {
              align_state = SceneGetState(G);
            }

            /* we're going to create/update an alignment object */

            {
              /* Get unique ids and construct the alignment vla */
              int *align_vla = VLAlloc(int, n_pair * 3);

              {
                int *id_p = align_vla;
                int i;
                for(i = 0; i < n_pair; i++) {
                  id_p[0] = AtomInfoCheckUniqueID(G, op2.ai1VLA[i]);    /* target */
                  id_p[1] = AtomInfoCheckUniqueID(G, op1.ai1VLA[i]);
                  id_p[2] = 0;
                  id_p += 3;
                }
                VLASize(align_vla, int, n_pair * 3);
              }
              {
                ObjectAlignment *obj = NULL;

                /* does object already exist? */
                {
                  CObject *execObj = ExecutiveFindObjectByName(G, oname);
                  if(execObj && (execObj->type != cObjectAlignment))
                    ExecutiveDelete(G, oname);
                  else
                    obj = (ObjectAlignment *) execObj;
                }
                obj =
                  ObjectAlignmentDefine(G, obj, align_vla, align_state, true, trg_obj,
                                        mobile_obj);
                obj->Obj.Color = ColorGetIndex(G, "yellow");
                ObjectSetName((CObject *) obj, oname);
                ExecutiveManageObject(G, (CObject *) obj, 0, quiet);
                align_to_update = obj;
                SceneInvalidate(G);
              }
              VLAFreeP(align_vla);
            }
        }
        if(ok && mode == 2) {
          if(matrix_mode>0) {

            ObjectMolecule *src_obj, *trg_obj;
            src_obj = SelectorGetFirstObjectMolecule(G, sele1); /* get at least one object */
            trg_obj = SelectorGetSingleObjectMolecule(G, sele2);

            /* first we need to make sure that the object being moved
               matches the target with respect to both the TTT and the
               object's state matrix (if any) */

            if(src_obj && trg_obj) {
              ExecutiveMatrixCopy(G, trg_obj->Obj.Name, src_obj->Obj.Name, 1, 1,        /* TTT mode */
                                  state2, state1, false, 0, quiet);

              ExecutiveMatrixCopy(G, trg_obj->Obj.Name, src_obj->Obj.Name, 2, 2,        /* Object state mode */
                                  state2, state1, false, 0, quiet);

              switch (matrix_mode) {
              case 1:          /* TTTs */
                ExecutiveCombineObjectTTT(G, src_obj->Obj.Name, op2.ttt, true, -1);
                break;
              case 2:
                {
                  double homo[16], *src_homo;
                  convertTTTfR44d(op2.ttt, homo);
                  if(ExecutiveGetObjectMatrix
                     (G, src_obj->Obj.Name, state1, &src_homo, false)) {
                    left_multiply44d44d(src_homo, homo);
                    ExecutiveSetObjectMatrix(G, src_obj->Obj.Name, state1, homo);
                  }
                }
                break;
              }
              /* next we need to update the object's TTT matrix to reflect
                 the transformation */
            }
          } else {              /* matrix_mode is zero -- legacy behavior */
            /* this will transform the actual coordinates */
            op2.code = OMOP_TTTF;
            ExecutiveObjMolSeleOp(G, sele1, &op2);
          }
        }
      }
    } else {
      ErrMessage(G, "ExecutiveRMS", "No atoms selected.");
    }
  }

  if(align_to_update) {
    ObjectAlignmentUpdate(align_to_update);
  }

  VLAFreeP(op1.vv1);
  VLAFreeP(op2.vv1);
  VLAFreeP(op1.vc1);
  VLAFreeP(op2.vc1);
  VLAFreeP(op1.vp1);
  VLAFreeP(op2.vp1);
  VLAFreeP(op1.ai1VLA);
  VLAFreeP(op2.ai1VLA);
  return (ok);
}


/*========================================================================*/
int *ExecutiveIdentify(PyMOLGlobals * G, const char *s1, int mode)
{
  int sele1;
  ObjectMoleculeOpRec op2;
  int *result = NULL;
  sele1 = SelectorIndexByName(G, s1);
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op2);
    op2.code = OMOP_Identify;
    op2.i1 = 0;
    op2.i1VLA = VLAlloc(int, 1000);
    ExecutiveObjMolSeleOp(G, sele1, &op2);
    result = op2.i1VLA;
    VLASize(result, int, op2.i1);
  }
  return (result);
}


/*========================================================================*/
int ExecutiveIdentifyObjects(PyMOLGlobals * G, const char *s1, int mode, int **indexVLA,
                             ObjectMolecule *** objVLA)
{
  int sele1;
  ObjectMoleculeOpRec op2;
  sele1 = SelectorIndexByName(G, s1);
  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op2);
    op2.code = OMOP_IdentifyObjects;
    op2.obj1VLA = VLAlloc(ObjectMolecule *, 1000);
    op2.i1VLA = VLAlloc(int, 1000);
    op2.i1 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op2);
    VLASize(op2.i1VLA, int, op2.i1);
    VLASize(op2.obj1VLA, ObjectMolecule *, op2.i1);
    (*indexVLA) = op2.i1VLA;
    (*objVLA) = op2.obj1VLA;
  }
  return (op2.i1);
}


/*========================================================================*/
int ExecutiveIndex(PyMOLGlobals * G, const char *s1, int mode, int **indexVLA,
                   ObjectMolecule *** objVLA)
{
  ObjectMoleculeOpRec op2;

  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  if(sele1 >= 0) {
    ObjectMoleculeOpRecInit(&op2);
    op2.code = OMOP_Index;
    op2.obj1VLA = VLAlloc(ObjectMolecule *, 1000);
    op2.i1VLA = VLAlloc(int, 1000);
    op2.i1 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op2);
    VLASize(op2.i1VLA, int, op2.i1);
    VLASize(op2.obj1VLA, ObjectMolecule *, op2.i1);
    (*indexVLA) = op2.i1VLA;
    (*objVLA) = op2.obj1VLA;
  }
  return (op2.i1);
}


/*========================================================================*/
float *ExecutiveRMSStates(PyMOLGlobals * G, const char *s1, int target, int mode, int quiet,
                          int mix)
{
  SelectorTmp tmpsele1(G, s1);
  int sele1 = tmpsele1.getIndex();

  ObjectMoleculeOpRec op1;
  ObjectMoleculeOpRec op2;
  float *result = NULL;
  int ok = true;

  ObjectMoleculeOpRecInit(&op1);
  ObjectMoleculeOpRecInit(&op2);
  op1.vv1 = NULL;
  op2.vv1 = NULL;

  if(!SelectorGetSingleObjectMolecule(G, sele1)) {
    if(mode != 2) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        "Executive-Warning: Mobile selection spans more than one object.\n" ENDFB(G);
    } else {
      PRINTFB(G, FB_Executive, FB_Errors)
        "Executive-Error: Mobile selection spans more than one object. Aborting.\n\n"
        ENDFB(G);
      ok = false;
    }
  }

  if(ok && sele1 >= 0) {
    op1.code = OMOP_SVRT;
    op1.nvv1 = 0;
    op1.i1 = target;
    op1.vv1 = (float *) VLAMalloc(1000, sizeof(float), 5, 0);
    op1.i1VLA = VLAlloc(int, 1000);
    ExecutiveObjMolSeleOp(G, sele1, &op1);

    op2.vv2 = op1.vv1;
    op2.nvv2 = op1.nvv1;
    op2.i1VLA = op1.i1VLA;
    op2.i2 = target;
    op2.i1 = mode;
    op2.i3 = mix;
    op2.f1VLA = VLAlloc(float, 10);
    VLASize(op2.f1VLA, float, 0);       /* failsafe */
    op2.vv1 = (float *) VLAMalloc(1000, sizeof(float), 5, 0);
    op2.code = OMOP_SFIT;
    op2.nvv1 = 0;
    ExecutiveObjMolSeleOp(G, sele1, &op2);
    result = op2.f1VLA;
    VLAFreeP(op1.vv1);
    VLAFreeP(op1.i1VLA);
    VLAFreeP(op2.vv1);
  }
  return (result);
}


/*========================================================================*/
float ExecutiveRMSPairs(PyMOLGlobals * G, WordType * sele, int pairs, int mode)
{
  int sele1, sele2;
  int a, c;
  float rms = 0.0, inv, *f;
  OrthoLineType buffer;

  ObjectMoleculeOpRec op1;
  ObjectMoleculeOpRec op2;
  OrthoLineType combi, s1;

  ObjectMoleculeOpRecInit(&op1);
  ObjectMoleculeOpRecInit(&op2);
  op1.nvv1 = 0;
  op1.vc1 = (int *) VLAMalloc(1000, sizeof(int), 5, 1);
  op1.vv1 = (float *) VLAMalloc(1000, sizeof(float), 5, 1);     /* auto-zero */
  op1.code = OMOP_AVRT;

  op2.nvv1 = 0;
  op2.vc1 = (int *) VLAMalloc(1000, sizeof(int), 5, 1);
  op2.vv1 = (float *) VLAMalloc(1000, sizeof(float), 5, 1);     /* auto-zero */
  op2.code = OMOP_AVRT;

  strcpy(combi, "(");
  c = 0;
  for(a = 0; a < pairs; a++) {
    sele1 = SelectorIndexByName(G, sele[c]);
    if(sele1 >= 0)
      ExecutiveObjMolSeleOp(G, sele1, &op1);
    strcat(combi, sele[c]);
    if(a < (pairs - 1))
      strcat(combi, " or ");
    c++;
    sele2 = SelectorIndexByName(G, sele[c]);
    if(sele2 >= 0)
      ExecutiveObjMolSeleOp(G, sele2, &op2);
    c++;
  }
  strcat(combi, ")");
  for(a = 0; a < op1.nvv1; a++) {
    inv = (float) op1.vc1[a];
    if(inv) {
      f = op1.vv1 + (a * 3);
      inv = 1.0F / inv;
      *(f++) *= inv;
      *(f++) *= inv;
      *(f++) *= inv;
    }
  }
  for(a = 0; a < op2.nvv1; a++) {
    inv = (float) op2.vc1[a];
    if(inv) {
      f = op2.vv1 + (a * 3);
      inv = 1.0F / inv;
      *(f++) *= inv;
      *(f++) *= inv;
      *(f++) *= inv;
    }
  }
  if(op1.vv1 && op2.vv1) {
    if(op1.nvv1 != op2.nvv1) {
      sprintf(buffer, "Atom counts between selection sets don't match (%d != %d).",
              op1.nvv1, op2.nvv1);
      ErrMessage(G, "ExecutiveRMS", buffer);
    } else if(op1.nvv1) {
      if(mode != 0)
        rms = MatrixFitRMSTTTf(G, op1.nvv1, op1.vv1, op2.vv1, NULL, op2.ttt);
      else
        rms = MatrixGetRMS(G, op1.nvv1, op1.vv1, op2.vv1, NULL);
      PRINTFB(G, FB_Executive, FB_Results)
        " ExecutiveRMS: RMSD = %8.3f (%d to %d atoms)\n", rms, op1.nvv1, op2.nvv1 ENDFB(G);

      op2.code = OMOP_TTTF;
      SelectorGetTmp(G, combi, s1);
      sele1 = SelectorIndexByName(G, s1);
      ExecutiveObjMolSeleOp(G, sele1, &op2);
      SelectorFreeTmp(G, s1);
    } else {
      ErrMessage(G, "ExecutiveRMS", "No atoms selected.");
    }
  }
  VLAFreeP(op1.vv1);
  VLAFreeP(op2.vv1);
  VLAFreeP(op1.vc1);
  VLAFreeP(op2.vc1);
  return (rms);
}


/*========================================================================*/
void ExecutiveUpdateObjectSelection(PyMOLGlobals * G, CObject * obj)
{
  if(obj->type == cObjectMolecule) {
    SelectorUpdateObjectSele(G, (ObjectMolecule *) obj);
  }
}


/*========================================================================*/
int ExecutiveReset(PyMOLGlobals * G, int cmd, const char *name)
{
  int ok = true;
  int store = SettingGetGlobal_i(G, cSetting_movie_auto_store);

  if(!name[0]) {
    SceneResetMatrix(G);
    ExecutiveWindowZoom(G, cKeywordAll, 0.0, -1, 0, 0, true);   /* reset does all states */
  } else {
    CExecutive *I = G->Executive;
    if((!name)||(!name[0])||(!strcmp(name,cKeywordAll))||(!strcmp(name,cKeywordSame))) { 
      SpecRec *rec = NULL;
      while(ListIterate(I->Spec, rec, next)) {
        switch(rec->type) {
        case cExecObject:
          {
            CObject *obj = rec->obj;
            if((ObjectGetSpecLevel(rec->obj,0)>=0)||(!strcmp(name,cKeywordAll))) {
              ObjectResetTTT(obj, SettingGetGlobal_b(G,cSetting_movie_auto_store));
              if(obj->fInvalidate)
                obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
            }
          }
          break;
        }
      }
      if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
        ExecutiveMotionReinterpolate(G);
      }
    } else { /* pattern */
      CTracker *I_Tracker = I->Tracker;
      SpecRec *rec = NULL;
      int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          
          switch (rec->type) {
          case cExecObject: 
            {
              CObject *obj = rec->obj;
              ObjectResetTTT(obj, SettingGetGlobal_b(G,cSetting_movie_auto_store));
              if(obj->fInvalidate)
                obj->fInvalidate(obj, cRepNone, cRepInvExtents, -1);
            }
            break;
          }
        }
      }
      TrackerDelList(I_Tracker, list_id);
      TrackerDelIter(I_Tracker, iter_id);
      if(store && SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) {
        ExecutiveMotionReinterpolate(G);
      }
    }
    SceneInvalidate(G);
  return ok;
  }
  return (ok);
}


/*========================================================================*/
void ExecutiveDrawNow(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;

  if(PyMOL_GetIdleAndReady(G->PyMOL) && !SettingGetGlobal_b(G, cSetting_suspend_deferred))
    OrthoExecDeferred(G);
  if(!SettingGetGlobal_b(G, cSetting_suspend_updates)){
    int stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
    int stereo = SettingGetGlobal_i(G, cSetting_stereo);
    if(G->HaveGUI && G->ValidContext) {
      glMatrixMode(GL_MODELVIEW);       /* why is this necessary?  is it? */
    }

    ExecutiveUpdateSceneMembers(G);
    SceneUpdate(G, false);
    if(WizardUpdate(G))
      SceneUpdate(G, false);
    if (stereo){
      switch (stereo_mode) {
      case cStereo_geowall:
	{
	  int width = G->Option->winX;
	  int height = G->Option->winY;
	  glViewport(0, 0, width / 2, height);
	  OrthoDoDraw(G, 1);
	  OrthoDoDraw(G, 2);
	  glViewport(0, 0, width, height);
	}
	break;
      default:
	OrthoDoDraw(G, 0);
	break;
      }
    } else {
      OrthoDoDraw(G, 0);
    }

    if(G->HaveGUI && G->ValidContext) {
      if(I->CaptureFlag) {
        I->CaptureFlag = false;
        SceneCaptureWindow(G);
      }
    }
    PyMOL_NeedSwap(G->PyMOL);
  }

  //  PRINTFD(G, FB_Executive)
  //    " ExecutiveDrawNow: leaving.\n" ENDFD;
}


/*========================================================================*/
int ExecutiveCountStates(PyMOLGlobals * G, const char *s1)
{
  CExecutive *I = G->Executive;
  int sele1;
  int result = 0;
  int n_state;
  SpecRec *rec = NULL;
  if((!s1) || (!s1[0]))
    s1 = cKeywordAll;
  {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, s1, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecAll:
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if(rec->type == cExecObject) {
              if(rec->obj->fGetNFrame) {
                n_state = rec->obj->fGetNFrame(rec->obj);
                if(result < n_state)
                  result = n_state;
              }
            }
          }
          break;
        case cExecSelection:
          sele1 = SelectorIndexByName(G, rec->name);
          if(sele1 >= 0) {
            SelectorUpdateTable(G, cSelectorUpdateTableAllStates, -1);
            n_state = SelectorGetSeleNCSet(G, sele1);
            if(result < n_state)
              result = n_state;
          }
          break;
        case cExecObject:
          if(rec->obj->fGetNFrame) {
            n_state = rec->obj->fGetNFrame(rec->obj);
            if(result < n_state)
              result = n_state;
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  return (result);
}


/*========================================================================*/
int ExecutiveRay(PyMOLGlobals * G, int width, int height, int mode,
                 float angle, float shift, int quiet, int defer, int antialias)
{
  if((mode == 0) && G->HaveGUI && SettingGetGlobal_b(G, cSetting_auto_copy_images)) {
    /* force deferred behavior if copying image to clipboard */
    defer = 1;
  }

  ExecutiveUpdateSceneMembers(G);

  if(defer && (mode == 0)) {
    SceneDeferRay(G, width, height, mode, angle, shift, quiet, true, antialias);
  } else {
    SceneRay(G, width, height, mode, NULL, NULL, angle, shift, quiet, NULL, true,
               antialias);
  }
  return 1;
}


/*========================================================================*/
int *ExecutiveGetG3d(PyMOLGlobals * G)
{
  int *result = NULL;
  SceneRay(G, 0, 0, 3, NULL, NULL, 0.0F, 0.0F, true, (G3dPrimitive **) (void *) &result,
           false, -1);
  return result;
}

int ExecutiveSetBondSettingFromString(PyMOLGlobals * G,
                                      int index, const char *value,
                                      const char *s1, const char *s2, int state,
                                      int quiet, int updates)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int sele1, sele2;
  SettingName name;
  int ok = true;
  int side_effects = false;
  int value_storage[3], *value_ptr;
  float float_storage[3];
  int value_type = 0;
  PRINTFD(G, FB_Executive)
    " ExecutiveSetBondSettingFromString: entered. '%s' '%s'\n", s1, s2 ENDFD;
  sele1 = SelectorIndexByName(G, s1);
  sele2 = SelectorIndexByName(G, s2);
  value_ptr = &value_storage[0];
  if((sele1 >= 0) && (sele2 >= 0)) {
    int have_value = false;
    int type = SettingGetType(G, index);
    switch (type) {
    case cSetting_boolean:
      {
        if((!*value) || (*value == '0') || (*value == 'F') || WordMatchExact(G, value, "on", true)
           || WordMatchExact(G, value, "false", true))
          *(value_ptr) = 0;
        else
          *(value_ptr) = 1;
        value_type = cSetting_boolean;
        have_value = true;
      }
      break;
    case cSetting_int:
      {
        if(sscanf(value, "%d", value_ptr) == 1) {
          value_type = cSetting_int;
          have_value = true;
        } else {
          ok = false;
        }
      }
      break;
    case cSetting_float:
      {
        if(sscanf(value, "%f", &float_storage[0]) == 1) {
          value_ptr = (int*) (void*) &float_storage[0];
          value_type = cSetting_float;
          have_value = true;
        } else {
          ok = false;
        }
      }
      break;
    case cSetting_float3:
      if(sscanf(value, "%f%f%f", &float_storage[0],
                &float_storage[1], &float_storage[2]) == 3) {
        value_ptr = (int*) (void*) &float_storage[0];
        value_type = cSetting_float3;
        have_value = true;
      } else {
        ok = false;
      }
      break;
    case cSetting_color:
      {
        int color_index = ColorGetIndex(G, value);
        if((color_index < 0) && (color_index > cColorExtCutoff))
          color_index = 0;
        *(value_ptr) = color_index;
        value_type = cSetting_color;
        have_value = true;
      }
      break;
      /* cSetting_string? */
    default:
      ok = false;
      break;
    }
    
    if(ok && have_value) {
      rec = NULL;
      while((ListIterate(I->Spec, rec, next))) {
        if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
          obj = (ObjectMolecule *) rec->obj;
          {
            int a, nBond = obj->NBond;
            int nSet = 0;
            BondType *bi = obj->Bond;
            AtomInfoType *ai1, *ai2, *ai = obj->AtomInfo;
            for(a = 0; a < nBond; a++) {
              ai1 = ai + bi->index[0];
              ai2 = ai + bi->index[1];
              if((SelectorIsMember(G, ai1->selEntry, sele1) &&
                  SelectorIsMember(G, ai2->selEntry, sele2)) ||
                 (SelectorIsMember(G, ai2->selEntry, sele1) &&
                  SelectorIsMember(G, ai1->selEntry, sele2))) {
                
                int uid = AtomInfoCheckUniqueBondID(G, bi);
		int isset;
                bi->has_setting = true;
                isset = SettingUniqueSetTypedValue(G, uid, index, value_type, value_ptr);
                if(updates && isset)
                  side_effects = true;
                nSet++;
              }
              bi++;
            }
            if(nSet && !quiet) {
              SettingGetName(G, index, name);
              PRINTF
                " Setting: %s set for %d bonds in object \"%s\".\n",
                name, nSet, obj->Obj.Name ENDF(G);
            }
          }
        }
      }
    }
  }
  if(side_effects) {
    SettingGenerateSideEffects(G, index, s1, state, quiet); /* not strickly correct */
    /*    SettingGenerateSideEffects(G,index,s2,state); */
  }
  return (ok);
}
/*========================================================================*/
PyObject *ExecutiveGetBondSetting(PyMOLGlobals * G, int index, 
				  char *s1, const char *s2, int state, int quiet, int updates)
{
#ifdef _PYMOL_NOPY
  return 0;
#else
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int sele1, sele2;
  SettingName name;
  int unblock;
  //  int *value_ptr;
  //  int value_type = 0;
  PyObject *result = PyList_New(0);

  PRINTFD(G, FB_Executive)
    " ExecutiveGetBondSetting: entered. '%s' '%s'\n", s1, s2 ENDFD;
  unblock = PAutoBlock(G);
  sele1 = SelectorIndexByName(G, s1);
  sele2 = SelectorIndexByName(G, s2);

  if((sele1 >= 0) && (sele2 >= 0)) {
    while((ListIterate(I->Spec, rec, next))) {
      if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
	obj = (ObjectMolecule *) rec->obj;
	{
	  int a, nBond = obj->NBond ;
	  int nSet = 0;
	  BondType *bi = obj->Bond;
	  AtomInfoType *ai1, *ai2, *ai = obj->AtomInfo;

	  PyObject *pyObjList = NULL;
	  PyObject *pyBondList = NULL;

	  for(a = 0; a < nBond; a++) {
	    ai1 = ai + bi->index[0];
	    ai2 = ai + bi->index[1];
	    if((SelectorIsMember(G, ai1->selEntry, sele1) &&
		SelectorIsMember(G, ai2->selEntry, sele2)) ||
	       (SelectorIsMember(G, ai2->selEntry, sele1) &&
		SelectorIsMember(G, ai1->selEntry, sele2))) {
	      PyObject *pyBondInfo = PyList_New(3);
	      PyObject *bond_setting_value = NULL;
	      if (!pyObjList){
		pyObjList = PyList_New(2);
		pyBondList = PyList_New(0);
		PyList_SetItem(pyObjList, 0, PyString_FromString(obj->Obj.Name));
		PyList_SetItem(pyObjList, 1, pyBondList);
		PyList_Append(result, pyObjList);
		Py_DECREF(pyObjList);
	      }
	      PyList_SetItem(pyBondInfo, 0, PyInt_FromLong((long)bi->index[0]+1));
	      PyList_SetItem(pyBondInfo, 1, PyInt_FromLong((long)bi->index[1]+1));
	      if (bi->has_setting){
		int uid = AtomInfoCheckUniqueBondID(G, bi);
		bond_setting_value = SettingUniqueGetPyObject(G, uid, index);
	      }
	      PyList_SetItem(pyBondInfo, 2, PConvAutoNone(bond_setting_value));
	      PyList_Append(pyBondList, pyBondInfo);
	      Py_DECREF(pyBondInfo);
	      nSet++;
	    }
	    bi++;
	  }
	  if(nSet && !quiet) {
	    SettingGetName(G, index, name);
	    PRINTF
	      " Getting: %s for %d bonds in object \"%s\".\n",
	      name, nSet, obj->Obj.Name ENDF(G);
	  }
	}
      }
    }
  }
  PRINTFD(G, FB_Executive)
    " ExecutiveGetBondSetting: end. '%s' '%s'\n", s1, s2 ENDFD;
  PAutoUnblock(G, unblock);
  return result;
#endif
}
/*========================================================================*/
int ExecutiveSetBondSetting(PyMOLGlobals * G, int index, PyObject * tuple,
                            const char *s1, const char *s2, int state, int quiet, int updates)
{
#ifdef _PYMOL_NOPY
  return 0;
#else

  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int sele1, sele2;
  SettingName name = "";
  int unblock;
  int ok = true;
  int side_effects = false;
  int value_storage, *value_ptr;
  int value_type = 0;

  PRINTFD(G, FB_Executive)
    " ExecutiveSetBondSetting: entered. '%s' '%s'\n", s1, s2 ENDFD;
  unblock = PAutoBlock(G);
  sele1 = SelectorIndexByName(G, s1);
  sele2 = SelectorIndexByName(G, s2);
  value_ptr = &value_storage;
  if((sele1 >= 0) && (sele2 >= 0)) {
    int have_value = false;
    int type = PyInt_AsLong(PyTuple_GetItem(tuple, 0));
    PyObject *value = PyTuple_GetItem(tuple, 1);
    if(value) {
      switch (type) {
      case cSetting_boolean:
        *(value_ptr) = PyInt_AsLong(value);
        value_type = cSetting_boolean;
        have_value = true;
        break;
      case cSetting_int:
        *(value_ptr) = PyInt_AsLong(value);
        value_type = cSetting_int;
        have_value = true;
        break;
      case cSetting_float:
        *(aliased_float *) value_ptr =
          (float) PyFloat_AsDouble(value);
        value_type = cSetting_float;
        have_value = true;
        break;
      case cSetting_color:
        {
          int color_index =
            ColorGetIndex(G, PyString_AsString(value));
          if((color_index < 0) && (color_index > cColorExtCutoff))
            color_index = 0;
          *(value_ptr) = color_index;
          value_type = cSetting_color;
          have_value = true;
        }
        break;
      }
      if(have_value) {
        rec = NULL;
        while((ListIterate(I->Spec, rec, next))) {
          if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
            obj = (ObjectMolecule *) rec->obj;
            {
              int a, nBond = obj->NBond;
              int nSet = 0;
              BondType *bi = obj->Bond;
              AtomInfoType *ai1, *ai2, *ai = obj->AtomInfo;
              for(a = 0; a < nBond; a++) {
                ai1 = ai + bi->index[0];
                ai2 = ai + bi->index[1];
                if((SelectorIsMember(G, ai1->selEntry, sele1) &&
                    SelectorIsMember(G, ai2->selEntry, sele2)) ||
                   (SelectorIsMember(G, ai2->selEntry, sele1) &&
                    SelectorIsMember(G, ai1->selEntry, sele2))) {

                  int uid = AtomInfoCheckUniqueBondID(G, bi);
                  bi->has_setting = true;
                  SettingUniqueSetTypedValue(G, uid, index, value_type, value_ptr);
                  if(updates)
                    side_effects = true;
                  nSet++;
                }
                bi++;
              }
              if(nSet && !quiet) {
                SettingGetName(G, index, name);
                PRINTF
                  " Setting: %s set for %d bonds in object \"%s\".\n",
                  name, nSet, obj->Obj.Name ENDF(G);
              }
            }
          }
        }
      }
    }
  }
  if(side_effects) {
    SettingGenerateSideEffects(G, index, s1, state, quiet);  /* not strictly correct */
    /*    SettingGenerateSideEffects(G,index,s2,state); */
  }

  if(!SettingLevelCheck(G, index, cSettingLevel_bond)) {
    if (!name[0])
      SettingGetName(G, index, name);

    PRINTFB(G, FB_Setting, FB_Warnings)
      " Setting-Warning: '%s' is not a bond-level setting\n", name
      ENDFB(G);
  }

  PAutoUnblock(G, unblock);
  return (ok);
#endif
}


/*========================================================================*/
int ExecutiveUnsetBondSetting(PyMOLGlobals * G, int index, const char *s1, const char *s2,
                              int state, int quiet, int updates)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  SettingName name;
  /*  int unblock; */
  int ok = true;
  int side_effects = false;
  int sele1, sele2;
  PRINTFD(G, FB_Executive)
    " ExecutiveUnsetBondSetting: entered. sele '%s' '%s'\n", s1, s2 ENDFD;
  /* unblock = PAutoBlock(G); */
  sele1 = SelectorIndexByName(G, s1);
  sele2 = SelectorIndexByName(G, s2);
  if((sele1 >= 0) && (sele2 >= 0)) {
    rec = NULL;
    while((ListIterate(I->Spec, rec, next))) {
      if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
        obj = (ObjectMolecule *) rec->obj;
        {
          int nSet = 0;
          BondType *bi = obj->Bond;
          BondType *bi_end = bi + obj->NBond;
          AtomInfoType *ai1, *ai2, *ai = obj->AtomInfo;
          for(; bi != bi_end; ++bi) {
            if(!bi->has_setting)
              continue;
            ai1 = ai + bi->index[0];
            ai2 = ai + bi->index[1];
            if((SelectorIsMember(G, ai1->selEntry, sele1) &&
                SelectorIsMember(G, ai2->selEntry, sele2)) ||
               (SelectorIsMember(G, ai2->selEntry, sele1) &&
                SelectorIsMember(G, ai1->selEntry, sele2))) {
              int uid = AtomInfoCheckUniqueBondID(G, bi);
              if(!SettingUniqueUnset(G, uid, index))
                continue;
              if(updates)
                side_effects = true;
              nSet++;
            }
          }
          if(nSet && !quiet) {
            SettingGetName(G, index, name);
            PRINTF
              " Setting: %s unset for %d bonds in object \"%s\".\n",
              name, nSet, rec->obj->Name ENDF(G);
          }
        }
      }
    }
  }
  if(side_effects) {
    SettingGenerateSideEffects(G, index, s1, state, quiet);
    /*    SettingGenerateSideEffects(G,index,s2,state); */
  }
  /* PAutoUnblock(G, unblock); */
  return (ok);
}


/*========================================================================*/
int ExecutiveSetSetting(PyMOLGlobals * G, int index, PyObject * tuple, const char *sele,
                        int state, int quiet, int updates)
{
#ifdef _PYMOL_NOPY
  return 0;
#else

  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int sele1;
  ObjectMoleculeOpRec op;
  OrthoLineType value;
  CSetting **handle = NULL;
  SettingName name = "";
  int nObj = 0;
  int unblock;
  int ok = true;

  PRINTFD(G, FB_Executive)
    " ExecutiveSetSetting: entered. sele \"%s\" updates=%d index=%d\n", sele, updates, index ENDFD;

  if(!quiet) {
    SettingGetName(G, index, name);
  }

  unblock = PAutoBlock(G);
  if((!sele) || (sele[0] == 0)) {       /* global setting */
    ok = SettingSetFromTuple(G, NULL, index, tuple);
    if(ok) {
      if(!quiet) {
        if(Feedback(G, FB_Setting, FB_Actions)) {
          SettingGetTextValue(G, NULL, NULL, index, value);
          PRINTF " Setting: %s set to %s.\n", name, value ENDF(G);
        }
      }
      if(updates) {
        SettingGenerateSideEffects(G, index, NULL, state, quiet);
      }
    }
  }
  else {
    unsigned char levelmask = 0;
    int side_effects = false;

    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, sele, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecAll:
          levelmask |= SettingLevelInfo[state < 0 ? cSettingLevel_object : cSettingLevel_ostate].mask;
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if(rec->type == cExecObject) {
              if(rec->obj->fGetSettingHandle) {
                handle = rec->obj->fGetSettingHandle(rec->obj, state);
                if(handle) {
                  SettingCheckHandle(G, handle);
                  ok = SettingSetFromTuple(G, *handle, index, tuple);
                  if(updates)
                    side_effects = true;
                  nObj++;
                }
              }
            }
          }
          if(Feedback(G, FB_Setting, FB_Actions)) {
            if(nObj && handle) {
              SettingGetTextValue(G, *handle, NULL, index, value);
              if(!quiet) {
                if(state < 0) {
                  PRINTF
                    " Setting: %s set to %s in %d objects.\n", name, value, nObj ENDF(G);
                } else {
                  PRINTF
                    " Setting: %s set to %s in %d objects, state %d.\n",
                    name, value, nObj, state + 1 ENDF(G);
                }
              }
            }
          }
          break;
        case cExecSelection:
          if (SettingLevelCheckMask(G, index, SettingLevelInfo[cSettingLevel_bond].mask)) {
            // handle bond-level settings (PYMOL-2726)
            ok = ExecutiveSetBondSetting(G, index, tuple, sele, sele, state, quiet, false);
            if (updates)
              side_effects = true;
            sele1 = -1;
          } else {
            levelmask |= SettingLevelInfo[cSettingLevel_atom].mask;
            sele1 = SelectorIndexByName(G, rec->name);
          }

          if(sele1 >= 0) {
            int have_atomic_value = false;
            int type = PyInt_AsLong(PyTuple_GetItem(tuple, 0));
            PyObject *value = PyTuple_GetItem(tuple, 1);
            if(value) {
              ObjectMoleculeOpRecInit(&op);
              op.code = OMOP_SetAtomicSetting;
              op.i1 = index;
              op.ii1 = &op.i3;
              switch (type) {
              case cSetting_boolean:
                *(op.ii1) = PyInt_AsLong(value);
                op.i2 = cSetting_boolean;
                have_atomic_value = true;
                break;
              case cSetting_int:
                *(op.ii1) = PyInt_AsLong(value);
                op.i2 = cSetting_int;
                have_atomic_value = true;
                break;
              case cSetting_float:
                *(float *) op.ii1 = (float) PyFloat_AsDouble(value);
                op.i2 = cSetting_float;
                have_atomic_value = true;
                break;
              case cSetting_float3:
		{
		  PConvPyListOrTupleToFloatArrayInPlace(value, op.ttt, 3);
		  op.mat1 = op.ttt; // for passing (float**)
		  op.ii1 = (int*) &op.mat1;
		  op.i2 = cSetting_float3;
		  have_atomic_value = true;
		}
                break;
              case cSetting_color:
                {
                  int color_index =
                    ColorGetIndex(G, PyString_AsString(value));
                  if((color_index < 0) && (color_index > cColorExtCutoff)) {
                    switch (color_index) {
                    case cColorAtomic:
                      color_index = -1;
                      break;
                    case cColorFront:
                    case cColorBack:
                    case cColorDefault:
                      break;
                    default:
                      color_index = 0;
                      break;
                    }
                  }
                  *(op.ii1) = color_index;
                  op.i2 = cSetting_color;
                  have_atomic_value = true;
                }
                break;
              }
              if(have_atomic_value) {
                rec = NULL;
                while((ListIterate(I->Spec, rec, next))) {
                  if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
                    obj = (ObjectMolecule *) rec->obj;
                    op.i4 = 0;
                    ObjectMoleculeSeleOp(obj, sele1, &op);
                    if(op.i4) {
                      if(updates)
                        side_effects = true;
                      if(!quiet) {
                        PRINTF
                          " Setting: %s set for %d atoms in object \"%s\".\n",
                          name, op.i4, rec->obj->Name ENDF(G);
                      }
                    }
                  }
                }
              }
            }
          }
          break;
        case cExecObject:
          levelmask |= SettingLevelInfo[state < 0 ? cSettingLevel_object : cSettingLevel_ostate].mask;
          if(rec->obj->fGetSettingHandle) {
            handle = rec->obj->fGetSettingHandle(rec->obj, state);
            if(handle) {
              SettingCheckHandle(G, handle);
              ok = SettingSetFromTuple(G, *handle, index, tuple);
              if(ok) {
                if(updates)
                  side_effects = true;
                if(!quiet) {
                  if(state < 0) {       /* object-specific */
                    if(Feedback(G, FB_Setting, FB_Actions)) {
                      SettingGetTextValue(G, *handle, NULL, index, value);
                      PRINTF
                        " Setting: %s set to %s in object \"%s\".\n",
                        name, value, rec->obj->Name ENDF(G);
                    }
                  } else {      /* state-specific */
                    if(Feedback(G, FB_Setting, FB_Actions)) {
                      SettingGetTextValue(G, *handle, NULL, index, value);
                      PRINTF
                        " Setting: %s set to %s in object \"%s\", state %d.\n",
                        name, value, rec->obj->Name, state + 1 ENDF(G);
                    }
                  }
                }
              }
            }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);

    if(side_effects)
      SettingGenerateSideEffects(G, index, sele, state, quiet);

    if(!SettingLevelCheckMask(G, index, levelmask)) {
      if(!name[0])
        SettingGetName(G, index, name);

      PRINTFB(G, FB_Setting, FB_Warnings)
        " Setting-Warning: '%s' is a %s-level setting\n", name, SettingLevelGetName(G, index)
        ENDFB(G);
    }
  }

  PAutoUnblock(G, unblock);
  return (ok);
#endif
}

int ExecutiveGetSettingFromString(PyMOLGlobals * G, PyMOLreturn_value *result, 
                                  int index, const char *sele,
                                  int state, int quiet)
{
  CObject *obj = NULL;
  CSetting **handle = NULL, *set_ptr1 = NULL, *set_ptr2 = NULL;
  int ok = true;
  int type;
  type = SettingGetType(G, index);
  if(sele)
    if(sele[0]) {
      obj = ExecutiveFindObjectByName(G, sele);
      if(!obj)
        ok = false;
    }
  if(!ok) {
    PRINTFB(G, FB_Executive, FB_Errors)
      " ExecutiveGetSettingFromString-Error: sele \"%s\" not found.\n", sele ENDFB(G);
    ok = false;
  } else if(obj) {
    handle = obj->fGetSettingHandle(obj, -1);
    if(handle)
      set_ptr1 = *handle;
    if(state >= 0) {
      handle = obj->fGetSettingHandle(obj, state);
      if(handle)
        set_ptr2 = *handle;
      else {
        PRINTFB(G, FB_Executive, FB_Errors)
          " ExecutiveGetSettingFromString-Error: sele \"%s\" lacks state %d.\n", sele, state + 1
          ENDFB(G);
        ok = false;
      }
    }
  }
  if(ok) {
    switch (type) {
    case cSetting_boolean:
      {
        int value = SettingGet_b(G, set_ptr2, set_ptr1, index);
	result->type = PYMOL_RETURN_VALUE_IS_INT;
	result->int_value = value;
      }
      break;
    case cSetting_int:
      {
        int value = SettingGet_i(G, set_ptr2, set_ptr1, index);
	result->type = PYMOL_RETURN_VALUE_IS_INT;
	result->int_value = value;
      }
      break;
    case cSetting_float:
      {
        float value = SettingGet_f(G, set_ptr2, set_ptr1, index);
	result->type = PYMOL_RETURN_VALUE_IS_FLOAT;
	result->float_value = value;
      }
      break;
    case cSetting_float3:
      {
	result->type = PYMOL_RETURN_VALUE_IS_FLOAT_ARRAY;
	result->float_array = VLAlloc(float, 3);
	result->array_length = 3;
	copy3f(SettingGet<const float *>(G, set_ptr2, set_ptr1, index),
	    result->float_array);
      }
      break;
    case cSetting_color:
      {
        int value = SettingGet_color(G, set_ptr2, set_ptr1, index);
	result->type = PYMOL_RETURN_VALUE_IS_INT;
	result->int_value = value;
      }
      break;
    case cSetting_string:
      {
        OrthoLineType buffer = "";
	result->type = PYMOL_RETURN_VALUE_IS_STRING;
	result->string = mstrdup(SettingGetTextPtr(G, set_ptr2, set_ptr1, index, buffer));
      }
      break;
    default:
      break;
    }
  }
  return (ok);
}

int ExecutiveSetSettingFromString(PyMOLGlobals * G,
                                  int index, const char *value, const char *sele,
                                  int state, int quiet, int updates)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int sele1;
  ObjectMoleculeOpRec op;
  OrthoLineType value2;
  CSetting **handle = NULL;
  SettingName name;
  int nObj = 0;
  int ok = true;

  PRINTFD(G, FB_Executive)
    " ExecutiveSetSettingFromString: entered. sele \"%s\"\n", sele ENDFD;
  if(sele[0] == 0) {            /* global setting */
    ok = SettingSetFromString(G, NULL, index, value);
    if(ok) {
      if(!quiet) {
        if(Feedback(G, FB_Setting, FB_Actions)) {
          SettingGetTextValue(G, NULL, NULL, index, value2);
          SettingGetName(G, index, name);
          PRINTF " Setting: %s set to %s.\n", name, value2 ENDF(G);
        }
      }
      if(updates)
        SettingGenerateSideEffects(G, index, sele, state, quiet);
    }
  }
  else {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, sele, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecAll:
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if(rec->type == cExecObject) {
              if(rec->obj->fGetSettingHandle) {
                handle = rec->obj->fGetSettingHandle(rec->obj, state);
                if(handle) {
                  SettingCheckHandle(G, handle);
                  ok = SettingSetFromString(G, *handle, index, value);
                  if(updates)
                    SettingGenerateSideEffects(G, index, rec->name, state, quiet);
                  nObj++;
                }
              }
            }
          }
          if(Feedback(G, FB_Setting, FB_Actions)) {
            if(nObj && handle) {
              SettingGetTextValue(G, *handle, NULL, index, value2);
              SettingGetName(G, index, name);
              if(!quiet) {
                if(state < 0) {
                  PRINTF
                    " Setting: %s set to %s in %d objects.\n", name, value2, nObj ENDF(G);
                } else {
                  PRINTF
                    " Setting: %s set to %s in %d objects, state %d.\n",
                    name, value2, nObj, state + 1 ENDF(G);
                }
              }
            }
          }
          break;
        case cExecSelection:
          /* this code has not yet been tested... */

          sele1 = SelectorIndexByName(G, rec->name);
          if(sele1 >= 0) {
            int type;
            int value_store;
            if(SettingStringToTypedValue(G, index, value, &type, &value_store)) {
              ObjectMoleculeOpRecInit(&op);
              op.code = OMOP_SetAtomicSetting;
              op.i1 = index;
              op.i2 = type;
              op.ii1 = &value_store;
              rec = NULL;
              while((ListIterate(I->Spec, rec, next))) {
                if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
                  obj = (ObjectMolecule *) rec->obj;
                  op.i4 = 0;
                  ObjectMoleculeSeleOp(obj, sele1, &op);
                  if(op.i4) {
                    if(updates)
                      SettingGenerateSideEffects(G, index, rec->name, state, quiet);
                    if(!quiet) {
                      SettingGetName(G, index, name);
                      PRINTF
                        " Setting: %s set for %d atoms in object \"%s\".\n",
                        name, op.i4, rec->obj->Name ENDF(G);
                    }
                  }
                }
              }
            }
          }
          break;
        case cExecObject:
          if(rec->obj->fGetSettingHandle) {
            handle = rec->obj->fGetSettingHandle(rec->obj, state);
            if(handle) {
              SettingCheckHandle(G, handle);
              ok = SettingSetFromString(G, *handle, index, value);
              if(ok) {
                if(updates)
                  SettingGenerateSideEffects(G, index, sele, state, quiet);
                if(!quiet) {
                  if(state < 0) {       /* object-specific */
                    if(Feedback(G, FB_Setting, FB_Actions)) {
                      SettingGetTextValue(G, *handle, NULL, index, value2);
                      SettingGetName(G, index, name);
                      PRINTF
                        " Setting: %s set to %s in object \"%s\".\n",
                        name, value2, rec->obj->Name ENDF(G);
                    }
                  } else {      /* state-specific */
                    if(Feedback(G, FB_Setting, FB_Actions)) {
                      SettingGetTextValue(G, *handle, NULL, index, value2);
                      SettingGetName(G, index, name);
                      PRINTF
                        " Setting: %s set to %s in object \"%s\", state %d.\n",
                        name, value2, rec->obj->Name, state + 1 ENDF(G);
                    }
                  }
                }
              }
            }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  return (ok);
}

int ExecutiveSetObjSettingFromString(PyMOLGlobals * G,
                                     int index, const char *value, CObject * obj,
                                     int state, int quiet, int updates)
{
  OrthoLineType value2;
  CSetting **handle = NULL;
  SettingName name;
  int ok = true;

  PRINTFD(G, FB_Executive)
    " ExecutiveSetObjSettingFromString: entered \n" ENDFD;
  if(!obj) {                    /* global */
    ok = SettingSetFromString(G, NULL, index, value);
    if(ok) {
      if(!quiet) {
        if(Feedback(G, FB_Setting, FB_Actions)) {
          SettingGetTextValue(G, NULL, NULL, index, value2);
          SettingGetName(G, index, name);
          PRINTF " Setting: %s set to %s.\n", name, value2 ENDF(G);
        }
      }
      if(updates)
        SettingGenerateSideEffects(G, index, obj->Name, state, quiet);
    }
  } else {                      /* based on a single object */
    if(obj->fGetSettingHandle) {
      handle = obj->fGetSettingHandle(obj, state);
      if(handle) {
        SettingCheckHandle(G, handle);
        ok = SettingSetFromString(G, *handle, index, value);
        if(ok) {
          if(updates)
            SettingGenerateSideEffects(G, index, obj->Name, state, quiet);
          if(!quiet) {
            if(state < 0) {     /* object-specific */
              if(Feedback(G, FB_Setting, FB_Actions)) {
                SettingGetTextValue(G, *handle, NULL, index, value2);
                SettingGetName(G, index, name);
                PRINTF
                  " Setting: %s set to %s in object \"%s\".\n",
                  name, value2, obj->Name ENDF(G);
              }
            } else {            /* state-specific */
              if(Feedback(G, FB_Setting, FB_Actions)) {
                SettingGetTextValue(G, *handle, NULL, index, value2);
                SettingGetName(G, index, name);
                PRINTF
                  " Setting: %s set to %s in object \"%s\", state %d.\n",
                  name, value2, obj->Name, state + 1 ENDF(G);
              }
            }
          }
        }
      }
    }
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveUnsetSetting(PyMOLGlobals * G, int index, const char *sele,
                          int state, int quiet, int updates)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int sele1;
  ObjectMoleculeOpRec op;
  CSetting **handle = NULL;
  const char * name = SettingGetName(index);
  int nObj = 0;
  int unblock;
  int ok = true;

  PRINTFD(G, FB_Executive)
    " ExecutiveUnsetSetting: entered. sele \"%s\"\n", sele ENDFD;
  unblock = PAutoBlock(G);
  if(sele[0] == 0) {
    // Set global setting to an "off" value.
    // NOTE: It would be nice if this would restore the default setting, but
    //       that's not how Warren implemented it and we don't want to break
    //       legacy PyMOL behavior.
    if (!SettingIsDefaultZero(index)) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        " Warning: The behavior of \"unset\" for global numeric settings will change.\n"
        " Use \"set %s, 0\" to ensure consistent behavior in future PyMOL versions.",
        name ENDFB(G);
      SettingSetGlobal_i(G, index, 0);
    } else {
      SettingRestoreDefault(G->Setting, index, G->Default);
      if (!quiet)
      PRINTFB(G, FB_Executive, FB_Actions)
        " Setting: %s restored to default\n", name ENDFB(G);
    }
  }
  else {
    // Undefine per-object, per-state, or per-atom settings.
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, sele, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecAll:
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if(rec->type == cExecObject) {
              if(rec->obj->fGetSettingHandle) {
                handle = rec->obj->fGetSettingHandle(rec->obj, state);
                if(handle) {
                  SettingCheckHandle(G, handle);
                  ok = SettingUnset(*handle, index);
                  nObj++;
                }
              }
            }
          }
          if(Feedback(G, FB_Setting, FB_Actions)) {
            if(nObj && handle) {
              if(!quiet) {
                if(state < 0) {
                  PRINTF " Setting: %s unset in %d objects.\n", name, nObj ENDF(G);
                } else {
                  PRINTF
                    " Setting: %s unset in %d objects, state %d.\n",
                    name, nObj, state + 1 ENDF(G);
                }
              }
            }
          }
          break;
        case cExecSelection:
          if (SettingLevelCheckMask(G, index, SettingLevelInfo[cSettingLevel_bond].mask)) {
            // handle bond-level settings (PYMOL-2726)
            ok = ExecutiveUnsetBondSetting(G, index, sele, sele, state, quiet, false);
            sele1 = -1;
          } else {
            sele1 = SelectorIndexByName(G, rec->name);
          }

          if(sele1 >= 0) {
            ObjectMoleculeOpRecInit(&op);
            op.code = OMOP_SetAtomicSetting;
            op.i1 = index;
            op.i2 = cSetting_blank;
            op.ii1 = NULL;

            rec = NULL;
            while((ListIterate(I->Spec, rec, next))) {
              if((rec->type == cExecObject) && (rec->obj->type == cObjectMolecule)) {
                obj = (ObjectMolecule *) rec->obj;
                op.i4 = 0;
                ObjectMoleculeSeleOp(obj, sele1, &op);
                if(op.i4) {
                  if(!quiet) {
                    PRINTF
                      " Setting: %s unset for %d atoms in object \"%s\".\n",
                      name, op.i4, rec->obj->Name ENDF(G);
                  }
                }
              }
            }
          }
          break;
        case cExecObject:
          if(rec->obj->fGetSettingHandle) {
            handle = rec->obj->fGetSettingHandle(rec->obj, state);
            if(handle) {
              SettingCheckHandle(G, handle);
              ok = SettingUnset(*handle, index);
              if(ok) {
                if(!quiet) {
                  if(state < 0) {       /* object-specific */
                    if(Feedback(G, FB_Setting, FB_Actions)) {
                      PRINTF
                        " Setting: %s unset in object \"%s\".\n",
                        name, rec->obj->Name ENDF(G);
                    }
                  } else {      /* state-specific */
                    if(Feedback(G, FB_Setting, FB_Actions)) {
                      PRINTF
                        " Setting: %s unset in object \"%s\", state %d.\n",
                        name, rec->obj->Name, state + 1 ENDF(G);
                    }
                  }
                }
              }
            }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  if(updates)
    SettingGenerateSideEffects(G, index, sele, state, quiet);
  PAutoUnblock(G, unblock);
  return (ok);
}


/*========================================================================*/
int ExecutiveColor(PyMOLGlobals * G, const char *name, const char *color, int flags, int quiet)
{
  /* flags: 
     0x1 -- ignore or suppress selection name matches
   */

  CExecutive *I = G->Executive;
  int col_ind;
  int ok = false;
  col_ind = ColorGetIndex(G, color);
  if((!name) || (!name[0]))
    name = cKeywordAll;
  if(col_ind == -1) {
    ErrMessage(G, "Color", "Unknown color.");
  } else {
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int n_atm = 0;
    int n_obj = 0;

    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecSelection:
        case cExecObject:
        case cExecAll:
          if((rec->type == cExecSelection) ||   /* coloring a selection */
             (rec->type == cExecAll) || /* coloring all */
             ((rec->type == cExecObject) &&     /* coloring object and its backing selection */
              (rec->obj->type == cObjectMolecule))) {
            if(!(flags & 0x1)) {
              int sele = SelectorIndexByName(G, rec->name);
              ObjectMoleculeOpRec op;
              if(sele >= 0) {
                ok = true;
                ObjectMoleculeOpRecInit(&op);
                op.code = OMOP_COLR;
                op.i1 = col_ind;
                op.i2 = n_atm;
                ExecutiveObjMolSeleOp(G, sele, &op);
                n_atm = op.i2;
                op.code = OMOP_INVA;
                op.i1 = cRepBitmask;
                op.i2 = cRepInvColor;
                ExecutiveObjMolSeleOp(G, sele, &op);
              }
            }
          }
          break;
        }

        switch (rec->type) {    /* sets object color */
        case cExecObject:
          rec->obj->Color = col_ind;
          if(rec->obj->fInvalidate)
            rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvColor, -1);
          n_obj++;
          ok = true;
          SceneInvalidate(G);
          break;
        case cExecAll:
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if(rec->type == cExecObject) {
              rec->obj->Color = col_ind;
              if(rec->obj->fInvalidate)
                rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvColor, -1);
              n_obj++;
              ok = true;
              SceneInvalidate(G);
            }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);

    if(n_obj || n_atm) {
      char atms[] = "s";
      char objs[] = "s";
      if(n_obj < 2)
        objs[0] = 0;
      if(n_atm < 2)
        atms[0] = 0;
      if(!quiet) {

        if(n_obj && n_atm) {
          PRINTFB(G, FB_Executive, FB_Actions)
            " Executive: Colored %d atom%s and %d object%s.\n", n_atm, atms, n_obj, objs
            ENDFB(G);
        } else if(n_obj) {
          PRINTFB(G, FB_Executive, FB_Actions)
            " Executive: Colored %d object%s.\n", n_obj, objs ENDFB(G);
        } else {
          PRINTFB(G, FB_Executive, FB_Actions)
            " Executive: Colored %d atom%s.\n", n_atm, atms ENDFB(G);
        }
      }
    }
  }
  return (ok);
}


/*========================================================================*/
const char *ExecutiveFindBestNameMatch(PyMOLGlobals * G, const char *name)
{
  const char *result;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL, *best_rec = NULL;
  int best;
  int wm;

  best = 0;
  result = name;

  while(ListIterate(I->Spec, rec, next)) {
    wm = WordMatch(G, name, rec->name, true);
    if(wm < 0) {
      best_rec = rec;
      best = wm;
      break;
    } else if((best > 0) && (best < wm)) {
      best_rec = rec;
      best = wm;
    }
  }
  if(best_rec)
    result = best_rec->name;
  return (result);
}


/*========================================================================*/
static int count_objects(PyMOLGlobals * G, int public_only)
{
  int count = 0;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      if(!public_only)
        count++;
      else if(rec->obj->Name[0] != '_')
        count++;
    }
  }
  return count;
}

static SpecRec *ExecutiveFindSpec(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  // ignore % prefix
  if(name[0] && name[0] == '%')
    name++;
  {                             /* first, try for perfect, case-specific match */
    OVreturn_word result;
    if(OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, name)))) {
      if(OVreturn_IS_OK((result = OVOneToOne_GetForward(I->Key, result.word)))) {
        if(!TrackerGetCandRef(I->Tracker, result.word, (TrackerRef **) (void *) &rec)) {
          rec = NULL;
        }
      }
    }
    if(!rec) {                  /* otherwise try partial/case-nonspecific match */
      rec = ExecutiveAnyCaseNameMatch(G, name);
    }
  }
  return (rec);
}


/*========================================================================*/
void ExecutiveObjMolSeleOp(PyMOLGlobals * G, int sele, ObjectMoleculeOpRec * op)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  ObjectMolecule *obj = NULL;
  int update_table = true;

	/* if we're given a valid selection */
  if(sele >= 0) {
		/* iterate over all the objects in the global list */
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(rec->obj->type == cObjectMolecule) {
					/* if the objects are valid molecules, then perform the operation in op_code */
          obj = (ObjectMolecule *) rec->obj;

          switch (op->code) {
          case OMOP_RenameAtoms:
            {
              int result = SelectorRenameObjectAtoms(G, obj, sele, op->i2, update_table);
              if(result > 0)
                op->i1 += result;
              update_table = false;
            }
            break;
          default:
						/* all other cases, perform the operation on obj */
            ObjectMoleculeSeleOp(obj, sele, op);
            break;
          }
        }
      }
    }
  }
}


/*========================================================================*/
int ExecutiveGetCameraExtent(PyMOLGlobals * G, const char *name, float *mn, float *mx,
                             int transformed, int state)
{
  int sele;
  ObjectMoleculeOpRec op;
  int flag = false;

  if((state == -2) || (state == -3))    /* TO DO: support per-object states */
    state = SceneGetState(G);

  PRINTFD(G, FB_Executive)
    " ExecutiveGetCameraExtent: name %s state %d\n", name, state ENDFD;

  sele = SelectorIndexByName(G, name);

  if(sele >= 0) {
    ObjectMoleculeOpRecInit(&op);
    if(state < 0) {
      op.code = OMOP_CameraMinMax;
    } else {
      op.code = OMOP_CSetCameraMinMax;
      op.cs1 = state;
    }
    op.v1[0] = FLT_MAX;
    op.v1[1] = FLT_MAX;
    op.v1[2] = FLT_MAX;
    op.v2[0] = -FLT_MAX;
    op.v2[1] = -FLT_MAX;
    op.v2[2] = -FLT_MAX;
    op.i1 = 0;
    op.i2 = transformed;
    op.mat1 = SceneGetMatrix(G);

    ExecutiveObjMolSeleOp(G, sele, &op);

    PRINTFD(G, FB_Executive)
      " ExecutiveGetCameraExtent: minmax over %d vertices\n", op.i1 ENDFD;
    if(op.i1)
      flag = true;
  }
  copy3f(op.v1, mn);
  copy3f(op.v2, mx);

  PRINTFD(G, FB_Executive)
    " ExecutiveGetCameraExtent: returning %d\n", flag ENDFD;

  return (flag);
}


/*========================================================================*/
int ExecutiveGetExtent(PyMOLGlobals * G, const char *name, float *mn, float *mx,
                       int transformed, int state, int weighted)
{
  int sele;
  ObjectMoleculeOpRec op, op2;
  CExecutive *I = G->Executive;
  CObject *obj;
  int result = false;
  SpecRec *rec = NULL;
  float f1, f2, fmx;
  int a;

  if(WordMatchExact(G, cKeywordCenter, name, true)) {
    SceneGetCenter(G, mn);
    copy3f(mn, mx);
    return 1;
  }
  if(WordMatchExact(G, cKeywordOrigin, name, true)) {
    SceneOriginGet(G, mn);
    copy3f(mn, mx);
    return 1;
  }

  PRINTFD(G, FB_Executive)
    " ExecutiveGetExtent: name %s state %d\n", name, state ENDFD;

  ObjectMoleculeOpRecInit(&op);
  ObjectMoleculeOpRecInit(&op2);

  if((state == -2) || (state == -3)) {  /* we want the currently displayed state */
    state = SceneGetState(G);
    op.include_static_singletons = true;        /* make sure we get the static singletons too */
    op2.include_static_singletons = true;
  }

  op2.i1 = 0;
  op2.v1[0] = -1.0;
  op2.v1[1] = -1.0;
  op2.v1[2] = -1.0;
  op2.v2[0] = 1.0;
  op2.v2[1] = 1.0;
  op2.v2[2] = 1.0;

  {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int have_atoms_flag = false;
    int have_extent_flag = false;

    /* first, compute atomic extents */

    if(weighted) {
      op2.i1 = 0;

      op2.v1[0] = 0.0F;
      op2.v1[1] = 0.0F;
      op2.v1[2] = 0.0F;

      op.i1 = 0;

      op.v1[0] = FLT_MAX;
      op.v1[1] = FLT_MAX;
      op.v1[2] = FLT_MAX;

      op.v2[0] = -FLT_MAX;
      op.v2[1] = -FLT_MAX;
      op.v2[2] = -FLT_MAX;
    }

    /* first, handle molecular objects */

    {
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);

      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          switch (rec->type) {
          case cExecObject:
          case cExecSelection:
          case cExecAll:
            if(rec->type == cExecAll)
              sele = SelectorIndexByName(G, cKeywordAll);
            else
              sele = SelectorIndexByName(G, rec->name);
            if(sele >= 0) {
              if(state < 0) {
                op.code = OMOP_MNMX;
              } else {
                op.code = OMOP_CSetMinMax;
                op.cs1 = state;
              }
              op.i2 = transformed;
              ExecutiveObjMolSeleOp(G, sele, &op);
              if(op.i1) {
                have_atoms_flag = true;
              }
              PRINTFD(G, FB_Executive)
                " ExecutiveGetExtent: minmax over %d vertices\n", op.i1 ENDFD;
            }

            if(weighted) {
              if(state < 0)
                op2.code = OMOP_SUMC;
              else {
                op2.code = OMOP_CSetSumVertices;
                op2.cs1 = state;
              }
              op2.i2 = transformed;
              ExecutiveObjMolSeleOp(G, sele, &op2);
            }
            break;
          }
        }
      }
      TrackerDelIter(I_Tracker, iter_id);
    }
    if(have_atoms_flag)
      have_extent_flag = true;

    /* now handle nonmolecular objects */

    {
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);

      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          switch (rec->type) {
          case cExecAll:
            rec = NULL;
            while(ListIterate(I->Spec, rec, next)) {
              if(rec->type == cExecObject) {
                obj = rec->obj;
                if(!obj->ExtentFlag) {
                  switch (obj->type) {
                  case cObjectMap:
                  case cObjectMesh:
                  case cObjectSurface:
                    if(!rec->obj->ExtentFlag) {
                      if(rec->obj->fUpdate)     /* allow object to update extents, if necessary */
                        rec->obj->fUpdate(rec->obj);
                    }
                  }
                }
                if(obj->ExtentFlag)
                  switch (obj->type) {
                  case cObjectMolecule:
                    break;
                    /* intentional fall-through */
                  default:
                    if(!have_extent_flag) {
                      copy3f(obj->ExtentMin, op.v1);
                      copy3f(obj->ExtentMax, op.v2);
                      have_extent_flag = true;
                    } else {
                      min3f(obj->ExtentMin, op.v1, op.v1);
                      max3f(obj->ExtentMax, op.v2, op.v2);
                    }
                    break;
                  }
              }
            }
            break;
          case cExecObject:
            obj = rec->obj;
            if(!obj->ExtentFlag) {
              switch (obj->type) {
              case cObjectMap:
              case cObjectMesh:
              case cObjectSurface:
                if(!rec->obj->ExtentFlag) {
                  if(rec->obj->fUpdate) /* allow object to update extents, if necessary */
                    rec->obj->fUpdate(rec->obj);
                }
              }
            }
            if(obj->ExtentFlag)
              switch (obj->type) {
              case cObjectMolecule:    /* will have been handled above... */
                break;
              default:
                if(!have_extent_flag) {
                  copy3f(obj->ExtentMin, op.v1);
                  copy3f(obj->ExtentMax, op.v2);
                  have_extent_flag = true;
                } else {
                  min3f(obj->ExtentMin, op.v1, op.v1);
                  max3f(obj->ExtentMax, op.v2, op.v2);
                }
                break;
              }
            break;
          }
        }
      }
      TrackerDelIter(I_Tracker, iter_id);
    }

    if(have_atoms_flag && weighted) {
      if(op2.i1) {
        op2.v1[0] /= op2.i1;    /* compute average */
        op2.v1[1] /= op2.i1;
        op2.v1[2] /= op2.i1;

        for(a = 0; a < 3; a++) {        /* this puts origin at the weighted center */
          f1 = op2.v1[a] - op.v1[a];
          f2 = op.v2[a] - op2.v1[a];
          if(f1 > f2)
            fmx = f1;
          else
            fmx = f2;
          op.v1[a] = op2.v1[a] - fmx;
          op.v2[a] = op2.v1[a] + fmx;
        }
      }
    }

    if(have_extent_flag) {
      copy3f(op.v1, mn);
      copy3f(op.v2, mx);
    } else {
      zero3f(mn);
      zero3f(mx);
    }
    TrackerDelList(I_Tracker, list_id);

    result = have_extent_flag;

  }

  PRINTFD(G, FB_Executive)
    " ExecutiveGetExtent: returning %d\n", result ENDFD;

  return result;
}


/*========================================================================*/
static int ExecutiveGetMaxDistance(PyMOLGlobals * G, const char *name, float *pos, float *dev,
                                   int transformed, int state)
{
  int sele;
  ObjectMoleculeOpRec op, op2;
  CExecutive *I = G->Executive;
  CObject *obj;
  int flag = false;
  SpecRec *rec = NULL;
  float f1, fmx = 0.0F;

  if((state == -2) || (state == -3))    /* TO DO: support per-object states */
    state = SceneGetState(G);

  PRINTFD(G, FB_Executive)
    " ExecutiveGetExtent: name %s state %d\n", name, state ENDFD;

  ObjectMoleculeOpRecInit(&op);
  ObjectMoleculeOpRecInit(&op2);

  {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);

    op2.i1 = 0;
    op2.v1[0] = -1.0;
    op2.v1[1] = -1.0;
    op2.v1[2] = -1.0;
    op2.v2[0] = 1.0;
    op2.v2[1] = 1.0;
    op2.v2[2] = 1.0;

    {
      /* first handle molecular objects */

      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);

      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          switch (rec->type) {
          case cExecObject:
          case cExecSelection:
          case cExecAll:
            if(rec->type == cExecAll)
              sele = SelectorIndexByName(G, cKeywordAll);
            else
              sele = SelectorIndexByName(G, rec->name);
            if(sele >= 0) {
              if(state < 0) {
                op.code = OMOP_MaxDistToPt;
              } else {
                op.code = OMOP_CSetMaxDistToPt;
                op.cs1 = state;
              }
              op.v1[0] = pos[0];
              op.v1[1] = pos[1];
              op.v1[2] = pos[2];
              op.i1 = 0;
              op.f1 = 0.0F;
              op.i2 = transformed;
              ExecutiveObjMolSeleOp(G, sele, &op);
              fmx = op.f1;

              if(op.i1)
                flag = true;
            }
            break;
          }
        }
      }
      TrackerDelIter(I_Tracker, iter_id);
    }

    {
      /* now handle nonmolecular objects */
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);

      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          switch (rec->type) {
          case cExecAll:
            rec = NULL;
            while(ListIterate(I->Spec, rec, next)) {
              if(rec->type == cExecObject) {
                obj = rec->obj;
                if(obj->ExtentFlag) {
                  switch (obj->type) {
                  case cObjectMolecule:
                    break;
                  default:
                    if(obj->ExtentFlag) {
                      f1 = (float) diff3f(obj->ExtentMin, pos);
                      if(fmx < f1)
                        fmx = f1;
                      f1 = (float) diff3f(obj->ExtentMax, pos);
                      if(fmx < f1)
                        fmx = f1;
                      flag = true;
                      break;
                    }
                  }
                }
              }
            }
            break;
          case cExecObject:
            obj = rec->obj;
            switch (rec->obj->type) {
            case cObjectMolecule:
              break;
            default:
              if(obj->ExtentFlag) {
                f1 = (float) diff3f(obj->ExtentMin, pos);
                if(fmx < f1)
                  fmx = f1;
                f1 = (float) diff3f(obj->ExtentMax, pos);
                if(fmx < f1)
                  fmx = f1;
                flag = true;
              }
              break;
            }
          }
        }
      }
      TrackerDelIter(I_Tracker, iter_id);
    }

    TrackerDelList(I_Tracker, list_id);
  }
  *dev = fmx;
  return (flag);
}


/*========================================================================*/
int ExecutiveWindowZoom(PyMOLGlobals * G, const char *name, float buffer,
                        int state, int inclusive, float animate, int quiet)
{
  float center[3], radius;
  float mn[3], mx[3], df[3];
  int sele0;
  int ok = true;

  PRINTFD(G, FB_Executive)
    " ExecutiveWindowZoom-DEBUG: entered\n" ENDFD;
  if(ExecutiveGetExtent(G, name, mn, mx, true, state, true)) {
    if(buffer != 0.0F) {
      mx[0] += buffer;
      mx[1] += buffer;
      mx[2] += buffer;
      mn[0] -= buffer;
      mn[1] -= buffer;
      mn[2] -= buffer;
    }
    subtract3f(mx, mn, df);
    average3f(mn, mx, center);
    if(inclusive) {
      if(!ExecutiveGetMaxDistance(G, name, center, &radius, true, state))
        radius = 0.0;
      radius += buffer;
    } else {
      radius = df[0];
      if(radius < df[1])
        radius = df[1];
      if(radius < df[2])
        radius = df[2];
      radius = radius / 2.0F;
    }
    if(radius < MAX_VDW)
      radius = MAX_VDW;
    PRINTFD(G, FB_Executive)
      " ExecutiveWindowZoom: zooming with radius %8.3f...state %d\n", radius, state ENDFD;
    PRINTFD(G, FB_Executive)
      " ExecutiveWindowZoom: on center %8.3f %8.3f %8.3f...\n", center[0],
      center[1], center[2]
      ENDFD;
    if(animate < 0.0F) {
      if(SettingGetGlobal_b(G, cSetting_animation))
        animate = SettingGetGlobal_f(G, cSetting_animation_duration);
      else
        animate = 0.0F;
    }
    if(animate != 0.0F)
      ScenePrimeAnimation(G);
    SceneOriginSet(G, center, false);
    SceneWindowSphere(G, center, radius);
    if(animate != 0.0F)
      SceneLoadAnimation(G, animate, 0);
    else
      SceneAbortAnimation(G);
    SceneInvalidate(G);
  } else {

    sele0 = SelectorIndexByName(G, name);
    if(sele0 > 0) {             /* any valid selection except "all" */
      /* no longer an error to zoom on an empty selection -- just has no effect */
      if(!quiet) {
        PRINTFB(G, FB_Executive, FB_Warnings)
          "ExecutiveWindowZoom-Warning: selection doesn't specify any coordinates.\n"
          ENDFB(G);
      }
    } else if(ExecutiveValidName(G, name)) {
      PRINTFD(G, FB_Executive)
        " ExecutiveWindowZoom-DEBUG: name valid, but no extents -- using default view\n"
        ENDFD;
      SceneSetDefaultView(G);
      SceneInvalidate(G);
    } else {
      ErrMessage(G, "ExecutiveWindowZoom", "selection or object unknown.");
      ok = false;
    }
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveCenter(PyMOLGlobals * G, const char *name, int state,
                    int origin, float animate, float *pos, int quiet)
{
  float center[3];
  float mn[3], mx[3];
  int sele0;
  int ok = true;
  int have_center = false;

  if(name && ExecutiveGetExtent(G, name, mn, mx, true, state, true)) {
    average3f(mn, mx, center);
    have_center = true;
    PRINTFD(G, FB_Executive)
      " ExecutiveCenter: centering state %d\n", state ENDFD;
    PRINTFD(G, FB_Executive)
      " ExecutiveCenter: on center %8.3f %8.3f %8.3f...\n", center[0],
      center[1], center[2]
      ENDFD;
  } else if(pos) {
    have_center = true;
    copy3f(pos, center);
  }
  if(have_center) {
    if(animate < 0.0F) {
      if(SettingGetGlobal_b(G, cSetting_animation))
        animate = SettingGetGlobal_f(G, cSetting_animation_duration);
      else
        animate = 0.0F;
    }

    if(animate != 0.0F)
      ScenePrimeAnimation(G);
    if(origin)
      SceneOriginSet(G, center, false);
    SceneRelocate(G, center);
    SceneInvalidate(G);
    if(animate != 0.0F)
      SceneLoadAnimation(G, animate, 0);
  } else {
    sele0 = SelectorIndexByName(G, name);
    if(sele0 >= 0) {            /* any valid selection except "all" */
      if(!quiet) {
        /* no longer an error to center on an empty selection -- just have no effect */
        PRINTFB(G, FB_Executive, FB_Warnings)
          "ExecutiveCenter-Warning: selection doesn't specify any coordinates.\n"
          ENDFB(G);
      }
    } else if(ExecutiveValidName(G, name)) {
      SceneSetDefaultView(G);
      SceneInvalidate(G);
    } else {
      ErrMessage(G, "ExecutiveCenter", "selection or object unknown.");
      ok = false;
    }
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveOrigin(PyMOLGlobals * G, const char *name, int preserve, const char *oname, float *pos,
                    int state)
{
  float center[3];
  float mn[3], mx[3];
  int ok = true;
  CObject *obj = NULL;
  int have_center = false;
  if(oname && oname[0]) {
    obj = ExecutiveFindObjectByName(G, oname);
    if(!obj)
      ok = false;
  }
  if(ok) {
    if(name && name[0]) {
      ok = ExecutiveGetExtent(G, name, mn, mx, true, state, true);
      if(ok) {
        average3f(mn, mx, center);
        have_center = true;
      }
    } else if(pos) {
      copy3f(pos, center);
      have_center = true;
    }
  }
  if(ok && have_center) {
    if(obj) {
      ObjectSetTTTOrigin(obj, center);
      PRINTFB(G, FB_Executive, FB_Blather)
        " ExecutiveCenter: origin for %s set to %8.3f %8.3f %8.3f\n",
        oname, center[0], center[1], center[2]
        ENDFB(G);
    } else {
      PRINTFB(G, FB_Executive, FB_Blather)
        " ExecutiveCenter: scene origin set to %8.3f %8.3f %8.3f\n",
        center[0], center[1], center[2]
        ENDFB(G);
      SceneOriginSet(G, center, preserve);
    }
    SceneInvalidate(G);
  } else
    ok = false;
  return (ok);
}


/*========================================================================*/
int ExecutiveGetMoment(PyMOLGlobals * G, const char *name, double *mi, int state)
{
  int sele;
  ObjectMoleculeOpRec op;
  int a, b;
  int c = 0;

  if((state == -2) || (state == -3))    /* TO DO: support per-object states */
    state = SceneGetState(G);

  sele = SelectorIndexByName(G, name);
  if(sele >= 0) {
    ObjectMoleculeOpRecInit(&op);
    if(state < 0) {
      op.code = OMOP_SUMC;
    } else {
      op.code = OMOP_CSetSumVertices;
      op.cs1 = state;
    }

    op.v1[0] = 0.0;
    op.v1[1] = 0.0;
    op.v1[2] = 0.0;
    op.i1 = 0;
    op.i2 = 0;                  /* untransformed...is this right? */

    ExecutiveObjMolSeleOp(G, sele, &op);

    if(op.i1) {                 /* any vertices? */
      c += op.i1;
      scale3f(op.v1, 1.0F / op.i1, op.v1);      /* compute raw average */
      if(state < 0) {
        op.code = OMOP_MOME;
      } else {
        op.code = OMOP_CSetMoment;
        op.cs1 = state;
      }
      for(a = 0; a < 3; a++)
        for(b = 0; b < 3; b++)
          op.d[a][b] = 0.0;
      ExecutiveObjMolSeleOp(G, sele, &op);
      {
        double *p = mi;
        for(a = 0; a < 3; a++)
          for(b = 0; b < 3; b++)
            *(p++) = op.d[a][b];
      }
    }
  } else {
    identity33d(mi);
  }

  return (c);
}


/*========================================================================*/
int ExecutiveSetObjVisib(PyMOLGlobals * G, const char *name, int onoff, int parents)
{
  CExecutive *I = G->Executive;
  PRINTFD(G, FB_Executive)
    " ExecutiveSetObjVisib: entered.\n" ENDFD;
  {
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, false);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    int suppress_hidden = SettingGetGlobal_b(G, cSetting_suppress_hidden);
    int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
    if(suppress_hidden && hide_underscore)
      ExecutiveUpdateGroups(G, false);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {

      if(rec) {
        switch (rec->type) {
        case cExecAll:
          {
            SpecRec *tRec = NULL;
            while(ListIterate(I->Spec, tRec, next)) {
              if(onoff != tRec->visible) {
                if(tRec->type == cExecObject) {
                  if(tRec->visible) {
                    tRec->in_scene = SceneObjectDel(G, tRec->obj, true);
                    ExecutiveInvalidateSceneMembers(G);
                    tRec->visible = !tRec->visible;
		    ReportEnabledChange(G, rec);
                  } else {
                    if((!suppress_hidden) || (!hide_underscore) || (!tRec->is_hidden)) {
                      tRec->in_scene = SceneObjectAdd(G, tRec->obj);
                      ExecutiveInvalidateSceneMembers(G);
                      tRec->visible = !tRec->visible;
		      ReportEnabledChange(G, rec);
                    }
                  }
                } else if((tRec->type != cExecSelection) || (!onoff)) {  /* hide all selections, but show all */
                  tRec->visible = !tRec->visible;
                  ReportEnabledChange(G, rec);
                }
              }
            }
          }
          break;
        case cExecObject:
          /*
             if(rec->visible!=onoff) {
             if(rec->visible) {
             rec->in_scene = SceneObjectDel(G,rec->obj);                           
             ExecutiveInvalidateSceneMembers(G);
             } else {
             rec->in_scene = SceneObjectAdd(G,rec->obj);
             ExecutiveInvalidateSceneMembers(G);
             }
             rec->visible=!rec->visible;
             }
           */
          if(onoff) {           /* enable */
            ExecutiveSpecEnable(G, rec, parents, false);
          } else {              /* disable */
            if(rec->visible) {
              if(rec->in_scene)
                rec->in_scene = SceneObjectDel(G, rec->obj, true);
              rec->visible = false;
              ExecutiveInvalidateSceneMembers(G);
	      ReportEnabledChange(G, rec);
            }
          }
          break;
        case cExecSelection:
          if(rec->visible != onoff) {
	    int previousVisible = rec->visible;
            rec->visible = !rec->visible;
            if(rec->visible)
              if(SettingGetGlobal_b(G, cSetting_active_selections)) {
                ExecutiveHideSelections(G);
                rec->visible = true;
              }
            SceneInvalidate(G);
            SeqDirty(G);
	    if (previousVisible!=rec->visible){
	      ReportEnabledChange(G, rec);
	    }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  PRINTFD(G, FB_Executive)
    " ExecutiveSetObjVisib: leaving...\n" ENDFD;
  return 1;
}


/*========================================================================*/
/*
 * Full screen state fallback in case we can't get get the state from
 * the window manager.
 */
static bool _is_full_screen = false;

/*========================================================================*/
/*
 * Get the fullscreen state from the window manager or return -1 if
 * not available.
 */
bool ExecutiveIsFullScreen(PyMOLGlobals * G) {
  if(!G->HaveGUI || !G->ValidContext)
    return false;

  int flag = -1;

#ifdef _MACPYMOL_XCODE
  flag = MacPyMOL_fullScreenActive();
#elif defined(GLUT_FULL_SCREEN)
  flag = glutGet(GLUT_FULL_SCREEN);
#endif

  PRINTFD(G, FB_Executive)
    " ExecutiveIsFullScreen: flag=%d fallback=%d.\n",
    flag, _is_full_screen ENDFD;

  if (flag > -1)
    return flag;
  return _is_full_screen;
}

/*========================================================================*/
void ExecutiveFullScreen(PyMOLGlobals * G, int flag)
{
  if(!G->HaveGUI)
    return;

  int wm_flag = ExecutiveIsFullScreen(G);

  if(flag < 0) {
    flag = !wm_flag;
  }

  _is_full_screen = (flag != 0);

#ifndef _PYMOL_NO_GLUT
  if(G->HaveGUI && G->ValidContext) {
    if (flag) {
#ifndef GLUT_FULL_SCREEN
      if(wm_flag < 1) {
        CExecutive *I = G->Executive;
        I->oldPX = p_glutGet(P_GLUT_WINDOW_X);
        I->oldPY = p_glutGet(P_GLUT_WINDOW_Y);
        I->oldWidth = p_glutGet(P_GLUT_WINDOW_WIDTH);
        I->oldHeight = p_glutGet(P_GLUT_WINDOW_HEIGHT);
      }
#endif

      p_glutFullScreen();
    } else {
#ifndef GLUT_FULL_SCREEN
      // freeglut < 2.6
      CExecutive *I = G->Executive;
      p_glutReshapeWindow(I->oldWidth, I->oldHeight);
      p_glutPositionWindow(I->oldPX, I->oldPY);
#elif !defined(GLUT_HAS_MULTI)
      // freeglut < 2.8
      if(wm_flag)
        glutFullScreenToggle();
#else
      glutLeaveFullScreen();
#endif
    }
  }
#endif

  PyMOL_NeedReshape(G->PyMOL, flag, 0, 0, 0, 0);
  SceneChanged(G);
}


/*========================================================================*/
static
void fInvalidateRepMask(CObject * obj, int repmask, int state=-1) {
  if(obj->fInvalidate) {
    for(int a = 0; a < cRepCnt; a++) {
      if ((1 << a) & repmask)
        obj->fInvalidate(obj, a, cRepInvVisib, state);
    }
  }
}


/*========================================================================*/
int ExecutiveToggleRepVisib(PyMOLGlobals * G, const char *name, int rep)
{
  int ok = true;
  int sele = -1;
  SpecRec *tRec;
  ObjectMoleculeOpRec op;
  OrthoLineType tmpname;

  PRINTFD(G, FB_Executive)
    " ExecutiveToggleRepVisib: entered.\n" ENDFD;

  tRec = ExecutiveFindSpec(G, name);

  if(rep == -2) {
    // special case: toggle object visibility (should that be in this function?)
    if(tRec) {
      ExecutiveSetObjVisib(G, name, !tRec->visible, 0);
    } else {
      PRINTFB(G, FB_Executive, FB_Errors)
        " ExecutiveToggleRepVisib-Error: '%s' not found\n", name ENDFB(G);
    }
  } else if(tRec && tRec->type == cExecObject &&
      tRec->obj->type != cObjectMolecule) {
    // non-atom object
    tRec->obj->visRep ^= rep;
    fInvalidateRepMask(tRec->obj, rep, 0);
    SceneChanged(G);
  } else if(SelectorGetTmp(G, name, tmpname) >= 0) {
    // atom selection
    sele = SelectorIndexByName(G, tmpname);
    if(sele >= 0) {
          ObjectMoleculeOpRecInit(&op);

          op.code = OMOP_CheckVis;
          op.i1 = rep;
          op.i2 = false;
          ExecutiveObjMolSeleOp(G, sele, &op);
          op.i2 = !op.i2;

          op.code = OMOP_VISI;
          op.i1 = rep;
          ExecutiveObjMolSeleOp(G, sele, &op);
          op.code = OMOP_INVA;
          op.i2 = cRepInvVisib;
          ExecutiveObjMolSeleOp(G, sele, &op);

    }
    SelectorFreeTmp(G, tmpname);
  }
  PRINTFD(G, FB_Executive)
    " ExecutiveToggleRepVisib: leaving...\n" ENDFD;
  return (ok);
}


/*========================================================================*/
void ExecutiveSetRepVisib(PyMOLGlobals * G, const char *name, int rep, int state)
{
  int repmask = (rep == cRepAll) ? cRepBitmask : (1 << rep);
  ExecutiveSetRepVisMask(G, name, repmask, state);
}

void ExecutiveSetRepVisMask(PyMOLGlobals * G, const char *name, int repmask, int state)
{
  PRINTFD(G, FB_Executive)
    " ExecutiveSetRepVisib: entered.\n" ENDFD;

  {
    CExecutive *I = G->Executive;
    CTracker *I_Tracker = I->Tracker;
    SpecRec *rec = NULL;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        /* per-atom */

        switch (rec->type) {
        case cExecSelection:
        case cExecObject:
          {
            int sele = SelectorIndexByName(G, rec->name);
            if(sele >= 0) {
              ObjectMoleculeOpRec op;
              ObjectMoleculeOpRecInit(&op);
              op.code = OMOP_VISI;
              op.i1 = repmask;
              op.i2 = state;
              ExecutiveObjMolSeleOp(G, sele, &op);
              op.code = OMOP_INVA;
              if (state == cVis_AS)
                op.i1 = cRepBitmask;
              op.i2 = cRepInvVisib;
              ExecutiveObjMolSeleOp(G, sele, &op);
            }
          }
          break;
        }

        /* per-object/name */

        switch (rec->type) {
        case cExecObject:
          ObjectSetRepVisMask(rec->obj, repmask, state);
          fInvalidateRepMask(rec->obj, repmask, 0);
          SceneChanged(G);
          break;
        case cExecAll:
          ExecutiveSetAllRepVisMask(G, repmask, state);
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
  PRINTFD(G, FB_Executive)
    " ExecutiveSetRepVisib: leaving...\n" ENDFD;

}


/*========================================================================*/
int ExecutiveSetOnOffBySele(PyMOLGlobals * G, const char *name, int onoff)
{
  int sele;
  SpecRec *tRec;
  ObjectMoleculeOpRec op;

  tRec = ExecutiveFindSpec(G, name);
  if((!tRec) && (!strcmp(name, cKeywordAll))) {
    ExecutiveSetObjVisib(G, name, onoff, false);
  }
  if(tRec) {
    sele = SelectorIndexByName(G, name);
    if(sele >= 0) {
      ObjectMoleculeOpRecInit(&op);

      op.code = OMOP_OnOff;
      op.i1 = onoff;
      ExecutiveObjMolSeleOp(G, sele, &op);
    }
  }
  return 1;
}


/*========================================================================*/
/*
 * repmask: rep bit mask
 * state: 0 (hide), 1 (show), 2 (as)
 */
static void ExecutiveSetAllRepVisMask(PyMOLGlobals * G, int repmask, int state)
{
  ObjectMoleculeOpRec op;
  ObjectMolecule *obj;
  int sele;

  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  PRINTFD(G, FB_Executive)
    " ExecutiveSetAllRepVisib: entered.\n" ENDFD;
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      if(rec->type == cExecObject) {
        switch (rec->obj->type) {
        case cObjectMolecule:
          obj = (ObjectMolecule *) rec->obj;
          sele = SelectorIndexByName(G, obj->Obj.Name);
          ObjectMoleculeOpRecInit(&op);

          op.code = OMOP_VISI;
          op.i1 = repmask;
          op.i2 = state;
          ObjectMoleculeSeleOp(obj, sele, &op);
          op.code = OMOP_INVA;
          if (state == cVis_AS)
            op.i1 = cRepBitmask;
          op.i2 = cRepInvVisib;
          ObjectMoleculeSeleOp(obj, sele, &op);
          break;
        default:
          ObjectSetRepVisMask(rec->obj, repmask, state);
          fInvalidateRepMask(rec->obj, repmask, -1);
          SceneInvalidate(G);
          break;
        }
      }
    }
  }
  PRINTFD(G, FB_Executive)
    " ExecutiveSetAllRepVisib: leaving...\n" ENDFD;

}


/*========================================================================*/
void ExecutiveInvalidateRep(PyMOLGlobals * G, const char *name, int rep, int level)
{
  CExecutive *I = G->Executive;
  ObjectMoleculeOpRec op;
  SpecRec *rec = NULL;
  if((!name) || (!name[0]))
    name = cKeywordAll;
  {
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);

    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec) {
        switch (rec->type) {
        case cExecSelection:
        case cExecObject:
          {
            int sele = SelectorIndexByName(G, rec->name);
            if(sele >= 0) {
              ObjectMoleculeOpRecInit(&op);
              op.code = OMOP_INVA;
              op.i1 = (rep == cRepAll) ? cRepBitmask : (1 << rep);
              op.i2 = level;
              ExecutiveObjMolSeleOp(G, sele, &op);
            } else if(rec->obj->fInvalidate) {
              rec->obj->fInvalidate(rec->obj, rep, level, -1);
            }
          }
          break;
        case cExecAll:
          rec = NULL;
          while(ListIterate(I->Spec, rec, next)) {
            if(rec->type == cExecObject) {
              if(rec->obj->fInvalidate) {
                rec->obj->fInvalidate(rec->obj, rep, level, -1);
                SceneInvalidate(G);
              }
            }
          }
          break;
        }
      }
    }
    TrackerDelList(I_Tracker, list_id);
    TrackerDelIter(I_Tracker, iter_id);
  }
}

int ExecutiveCheckGroupMembership(PyMOLGlobals * G, int list_id, CObject * obj)
{
  CExecutive *I = G->Executive;
  int result = false;
  CTracker *I_Tracker = I->Tracker;
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  if(iter_id) {
    SpecRec *rec = NULL;
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if(rec && (rec->type == cExecObject) && (rec->obj == obj)) {
        result = true;
        break;
      }
    }
    TrackerDelIter(I_Tracker, iter_id);
  }
  return result;
}

int ExecutiveGetExpandedGroupListFromPattern(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  int result = 0;
  CWordMatcher *matcher;
  CWordMatchOptions options;
  CTracker *I_Tracker = I->Tracker;
  const char *wildcard = SettingGetGlobal_s(G, cSetting_wildcard);
  int iter_id = TrackerNewIter(I_Tracker, 0, I->all_names_list_id);
  int cand_id;
  SpecRec *rec;

  WordMatchOptionsConfigNameList(&options,
                                 *wildcard, SettingGetGlobal_b(G, cSetting_ignore_case));
  matcher = WordMatcherNew(G, name, &options, false);
  if(matcher) {
    if(iter_id) {
      while((cand_id = TrackerIterNextCandInList(I_Tracker, iter_id,
                                                 (TrackerRef **) (void *) &rec))) {
        if(rec && !(rec->type == cExecAll)) {
          if(WordMatcherMatchAlpha(matcher, rec->name)) {
            if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
              if(!result)
                result = TrackerNewList(I_Tracker, NULL);
              if(result) {
                TrackerLink(I_Tracker, cand_id, result, 1);
              }
            }
          }
        }
      }
    }
  } else if((rec = ExecutiveFindSpec(G, name))) {       /* only one name in list */
    if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
      result = TrackerNewList(I_Tracker, NULL);
      TrackerLink(I_Tracker, rec->cand_id, result, 1);
    }
  } else if((rec = ExecutiveUnambiguousNameMatch(G, name))) {
    if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
      result = TrackerNewList(I_Tracker, NULL);
      TrackerLink(I_Tracker, rec->cand_id, result, 1);
    }
  }
  if(matcher)
    WordMatcherFree(matcher);
  if(iter_id)
    TrackerDelIter(I->Tracker, iter_id);
  if(result)
    ExecutiveExpandGroupsInList(G, result, cExecExpandGroups);
  return result;
}

int ExecutiveGetExpandedGroupList(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  int result = 0;
  int list_id = 0;

  SpecRec *rec = ExecutiveFindSpec(G, name);
  ExecutiveUpdateGroups(G, false);
  if(rec && (rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
    list_id = rec->group_member_list_id;
  }
  if(list_id) {
    result = TrackerNewListCopy(I->Tracker, list_id, NULL);
    ExecutiveExpandGroupsInList(G, result, cExecExpandGroups);
  }
  return result;
}

void ExecutiveFreeGroupList(PyMOLGlobals * G, int list_id)
{
  CExecutive *I = G->Executive;
  TrackerDelList(I->Tracker, list_id);
}


/*========================================================================*/
CObject *ExecutiveFindObjectByName(PyMOLGlobals * G, const char *name)
{
  CObject *obj = NULL;
  SpecRec *rec = ExecutiveFindSpec(G, name);
  if(rec && (rec->type == cExecObject)) {
    obj = rec->obj;
  }
  return (obj);
}

/*========================================================================*/
/* returns NULL if none found */
CObject ** ExecutiveFindObjectsByType(PyMOLGlobals * G, int objType) {
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  int n = 0;
  CObject** rVal = VLAlloc(CObject*, 1);

  /* loop over all known objects */
  while(ListIterate(I->Spec,rec,next)) {
    /* make sure it exists and is the right type */
    if (rec->obj && rec->type==cExecObject) {
      if(rec->obj->type==objType) {
	/* this could be optimized */
	VLACheck(rVal, CObject*, n);
	*(rVal+n) = rec->obj;
	n++;
      }
    }
  }
  VLASize(rVal, CObject*, n);
  if (n==0) {
	VLAFree(rVal);
    return NULL;
  }
  else
    return rVal;
}

/*========================================================================*/
ObjectMap *ExecutiveFindObjectMapByName(PyMOLGlobals * G, const char *name)
{
  CObject *obj;

  obj = ExecutiveFindObjectByName(G, name);
  if(obj)
    if(obj->type != cObjectMap)
      obj = NULL;
  return ((ObjectMap *) obj);
}


/*========================================================================*/
ObjectMolecule *ExecutiveFindObjectMoleculeByName(PyMOLGlobals * G, const char *name)
{
  CObject *obj;

  obj = ExecutiveFindObjectByName(G, name);
  if(obj)
    if(obj->type != cObjectMolecule)
      obj = NULL;
  return ((ObjectMolecule *) obj);
}


/*========================================================================*/
Block *ExecutiveGetBlock(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  return (I->Block);
}


/*========================================================================*/
void ExecutiveSymExp(PyMOLGlobals * G, const char *name,
                     const char *oname, const char *s1, float cutoff, int segi, int quiet)
{                               /* TODO state */
  CObject *ob;
  ObjectMolecule *obj = NULL;
  ObjectMolecule *new_obj = NULL;
  ObjectMoleculeOpRec op;
  MapType *map;
  int x, y, z, b, c, i, j, h, k, l, n;
  ov_size a;
  CoordSet *cs, *os;
  int keepFlag, sele, tt[3];
  float *v1, *v2, m[16], tc[3], ts[3];
  OrthoLineType new_name;
  float auto_save;

  PRINTFD(G, FB_Executive)
    " ExecutiveSymExp: entered.\n" ENDFD;

  /* controls whether we zoom in on newly created objects or not */
	auto_save = SettingGetGlobal_i(G, cSetting_auto_zoom);
  SettingSetGlobal_i(G, cSetting_auto_zoom, 0);

  SelectorTmp tmpsele1(G, s1);
  sele = tmpsele1.getIndex();

	/* object to expand */
  ob = ExecutiveFindObjectByName(G, oname);
	/* make sure it's a "molecule" type and that it had valid symmetry info */
  if(ob->type == cObjectMolecule)
    obj = (ObjectMolecule *) ob;
  if(!(obj && sele)) {
    ErrMessage(G, "ExecutiveSymExp", "Invalid object");
  } else if(!obj->Symmetry) {
    ErrMessage(G, "ExecutiveSymExp", "No symmetry loaded!");
  } else if(!SymmetryAttemptGeneration(obj->Symmetry)) {
    // unknown space group
  } else if(obj->Symmetry->getNSymMat() < 1) {
    ErrMessage(G, "ExecutiveSymExp", "No symmetry matrices!");
  } else {
    if(!quiet) {
      PRINTFB(G, FB_Executive, FB_Actions)
        " ExecutiveSymExp: Generating symmetry mates...\n" ENDFB(G);
    }

		/* 1.  Get the center of mass for this object/selection */
		/* the object and selection are valid, so initialize the NEW object */
    ObjectMoleculeOpRecInit(&op);
    op.code = OMOP_SUMC;
    op.i1 = 0;
    op.i2 = 0;
    op.v1[0] = 0.0;
    op.v1[1] = 0.0;
    op.v1[2] = 0.0;
    ExecutiveObjMolSeleOp(G, sele, &op);
		/* op.v1 is now the complete sum over all coordinates in this selection */
    tc[0] = op.v1[0];
    tc[1] = op.v1[1];
    tc[2] = op.v1[2];
		/* calculate center of mass.  op.i1 is the number of atoms we counter over in the
		 * previous ExecutiveObjMolSeleOp, so this is the average coordinate or center of mass */
    if(op.i1) {
      tc[0] /= op.i1;
      tc[1] /= op.i1;
      tc[2] /= op.i1;
    }
		/* Transformation: RealToFrac (3x3) * tc (3x1) = (3x1) */
    transform33f3f(obj->Symmetry->Crystal->RealToFrac, tc, tc);

		/* 2.  Copy the coordinates for the atoms in this selection into op */
    op.code = OMOP_VERT;
    op.nvv1 = 0;
    op.vv1 = VLAlloc(float, 10000);
    ExecutiveObjMolSeleOp(G, sele, &op);

		/* op.nvv1 is the number of atom coordinates we copied in the previous step */
    if(!op.nvv1) {
      ErrMessage(G, "ExecutiveSymExp", "No atoms indicated!");
    } else {
      int nsymmat = obj->Symmetry->getNSymMat();
      map = MapNew(G, -cutoff, op.vv1, op.nvv1, NULL);
      if(map) {
        MapSetupExpress(map);
        /* go out no more than one lattice step in each direction: -1, 0, +1 */
        for(x = -1; x < 2; x++)
          for(y = -1; y < 2; y++)
            for(z = -1; z < 2; z++)
              for(a = 0; a < nsymmat; a++) {
								/* make a copy of the original */
                new_obj = ObjectMoleculeCopy(obj);

                keepFlag = false;
                for(b = 0; b < new_obj->NCSet; b++)
                  if(new_obj->CSet[b]) {
										/* get the new and original coordinate sets for this state */
                    cs = new_obj->CSet[b];
                    os = obj->CSet[b];
										/* convert coordinates into fractional, based on unit cell */
                    CoordSetRealToFrac(cs, obj->Symmetry->Crystal);
                    CoordSetTransform44f(cs, obj->Symmetry->getSymMat(a));
                    CoordSetGetAverage(cs, ts);
                    identity44f(m);
                    /* compute the effective translation resulting
                       from application of the symmetry operator so
                       that we can shift it into the cell of the
                       target selection */
                    for(c = 0; c < 3; c++) {    /* manual rounding - rint broken */
											/* here, we subtract the center of mass of the selection from tc */
                      ts[c] = tc[c] - ts[c];
                      if(ts[c] < 0)
                        ts[c] -= 0.5;
                      else
                        ts[c] += 0.5;
                      tt[c] = (int) ts[c];
                    }
										/* translate the coordinate set by adding Tx, Ty, Tz from the symmetry matrix */
										/* Now we're at the center of mass and can make an non-affine rotation */
                    m[3] = (float) tt[0] + x;
                    m[7] = (float) tt[1] + y;
                    m[11] = (float) tt[2] + z;
										/* cs = m x cs, for rotation matrix, m and coordinate set cs */
                    CoordSetTransform44f(cs, m);
										
										/* this steps through the coordinate list until it finds a vertex close enough */
                    CoordSetFracToReal(cs, obj->Symmetry->Crystal);
                    if(!keepFlag) {
											/* for each coordinate in this coordinate set */
                      v2 = cs->Coord;
                      n = cs->NIndex;
                      while(n--) {
                        MapLocus(map, v2, &h, &k, &l);
                        i = *(MapEStart(map, h, k, l));
                        if(i) {
                          j = map->EList[i++];
                          while(j >= 0) {
														/* if op.vv1+3*j (a vertex) is within cutoff angstroms of v2, keep it and break */
                            if(within3f(op.vv1 + 3 * j, v2, cutoff)) {
                              keepFlag = true;
                              break;
                            }
                            j = map->EList[i++];
                          }
                        }
                        v2 += 3;
                        if(keepFlag)
                          break;
                      }
                    }
                    if(keepFlag) {
                      /* make sure that we aren't simply duplicating the template coordinates */
                      keepFlag = false;
                      v1 = os->Coord;
                      v2 = cs->Coord;
                      n = cs->NIndex;
                      while(n--) {
                        if(diffsq3f(v1, v2) > R_SMALL8) {
                          keepFlag = true;
                          break;
                        }
                        v1++;
                        v2++;
                      }
                    }
                  }
                if(keepFlag) {  /* we need to create new object */

                  /* TODO: should also transform the U tensor at this point... */

									/* make and manage the new object; update the scene for the new object */

                  PRINTFB(G, FB_Executive, FB_Blather)
                    "new_name before: %s\n", new_name ENDFB(G);
                  sprintf(new_name, "%s%02d%02d%02d%02d", name, (int)a, x, y, z);
                  PRINTFB(G, FB_Executive, FB_Blather)
                    "Making new object: %s from name=%s, a=%d, x=%d, y=%d, z=%d\n",
                    new_name, name, (int)a, x, y, z ENDFB(G);

                  ObjectSetName((CObject *) new_obj, new_name);
                  ExecutiveDelete(G, new_obj->Obj.Name);
                  ExecutiveManageObject(G, (CObject *) new_obj, -1, quiet);
                  SceneChanged(G);
									
                  if(segi == 1) {
                    SegIdent seg;
										/* a == index of this symmetryMatrix */
                    if(a > 61) {
                      // beyond what can be encoded with a single alphanumeric
                      // character (PYMOL-2475)
                      seg[0] = '_';
                    } else
                    if(a > 35) {
                      seg[0] = 'a' + (a - 36);
                    } else if(a > 25) {
                      seg[0] = '0' + (a - 26);
                    } else {
                      seg[0] = 'A' + a;
                    }
                    if(x > 0) {
                      seg[1] = 'A' + x - 1;
                    } else if(x < 0) {
                      seg[1] = 'Z' + x + 1;
                    } else {
                      seg[1] = '0';
                    }
                    if(y > 0) {
                      seg[2] = 'A' + y - 1;
                    } else if(y < 0) {
                      seg[2] = 'Z' + y + 1;
                    } else {
                      seg[2] = '0';
                    }
                    if(z > 0) {
                      seg[3] = 'A' + z - 1;
                    } else if(z < 0) {
                      seg[3] = 'Z' + z + 1;
                    } else {
                      seg[3] = '0';
                    }
                    seg[4] = 0;
                    {
                      lexidx_t segi = LexIdx(G, seg);
                      int a;
                      AtomInfoType *ai = new_obj->AtomInfo;
                      for(a = 0; a < new_obj->NAtom; a++) {
                        LexAssign(G, ai->segi, segi);
                        ai++;
                      }

                      LexDec(G, segi);
                    }
                  }
                } else {
                  ((CObject *) new_obj)->fFree((CObject *) new_obj);
                }
              }
        MapFree(map);
      }
    }
    VLAFreeP(op.vv1);
  }
  PRINTFD(G, FB_Executive)
    " ExecutiveSymExp: leaving...\n" ENDFD;
  SettingSetGlobal_i(G, cSetting_auto_zoom, auto_save);
}

static void ExecutivePurgeSpec(PyMOLGlobals * G, SpecRec * rec)
{
  CExecutive *I = G->Executive;

    CGOFree(rec->gridSlotSelIndicatorsCGO);

  if(rec->group_name[0]) {
    /* cascade group members up to the surrounding group */
    SpecRec *rec2 = NULL;
    while(ListIterate(I->Spec, rec2, next)) {
      if((rec2->group == rec) || WordMatchExact(G, rec->name, rec2->group_name, true)) {
        strcpy(rec2->group_name, rec->group_name);
      }
    }
  } else if((rec->type == cExecObject) && (rec->obj->type == cObjectGroup)) {
    /* and/or delete their group membership */
    SpecRec *rec2 = NULL;
    while(ListIterate(I->Spec, rec2, next)) {
      if((rec2->group == rec) || WordMatchExact(G, rec->name, rec2->group_name, true)) {
        rec2->group_name[0] = 0;
      }
    }
  }
  ExecutiveInvalidateGroups(G, false);
  ExecutiveInvalidatePanelList(G);
  switch (rec->type) {
  case cExecObject:
    if(I->LastEdited == rec->obj)
      I->LastEdited = NULL;
    if(rec->obj->type == cObjectMolecule)
      if(EditorIsAnActiveObject(G, (ObjectMolecule *) rec->obj))
        EditorInactivate(G);
    SeqChanged(G);
    if(rec->visible) {
      SceneObjectDel(G, rec->obj, false);
      ExecutiveInvalidateSceneMembers(G);
    }
    ExecutiveDelKey(I, rec);
    SelectorDelete(G, rec->name);
    rec->obj->fFree(rec->obj);
    rec->obj = NULL;
    TrackerDelCand(I->Tracker, rec->cand_id);
    break;
  case cExecSelection:
    if(rec->visible) {
      SceneInvalidate(G);
      SeqDirty(G);
    }
    ExecutiveDelKey(I, rec);
    SelectorDelete(G, rec->name);
    TrackerDelCand(I->Tracker, rec->cand_id);
    break;
  }
}


/*========================================================================*/
void ExecutiveDelete(PyMOLGlobals * G, const char *name)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  CTracker *I_Tracker = I->Tracker;
  int list_id = ExecutiveGetNamesListFromPattern(G, name, false, false);
  int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
  while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
    if(rec) {
      switch (rec->type) {
      case cExecSelection:
        ExecutivePurgeSpec(G, rec);
        ListDelete(I->Spec, rec, next, SpecRec);        /* NOTE: order N in list length! TO FIX */
        break;
      case cExecObject:
        if(rec->obj->type == cObjectGroup) {
          /* remove members of the group */
          ExecutiveGroup(G, rec->name, "", cExecutiveGroupPurge, true);
        }
        ExecutivePurgeSpec(G, rec);
        ListDelete(I->Spec, rec, next, SpecRec);        /* NOTE: order N in list length! TO FIX */
        break;
      case cExecAll:
        rec = NULL;
        while(ListIterate(I->Spec, rec, next)) {
          switch (rec->type) {
          case cExecAll:
            break;
          default:
            ExecutivePurgeSpec(G, rec);
            ListDelete(I->Spec, rec, next, SpecRec);
            rec = NULL;
            break;
          }
        }
        SelectorDefragment(G);
        break;
      }
    }
  }
  TrackerDelList(I_Tracker, list_id);
  TrackerDelIter(I_Tracker, iter_id);

  // fix for PYMOL-757 - Note: This should probably go somewhere else, but we
  // couldn't figure out the correct place so far
  ExecutiveUpdateGroups(G, false);
}


/*========================================================================*/
void ExecutiveDump(PyMOLGlobals * G, const char *fname, const char *obj)
{
  SpecRec *rec = NULL;
  CExecutive *I = G->Executive;

  SceneUpdate(G, false);

  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject) {
      if(strcmp(rec->obj->Name, obj) == 0)
        break;
    }
  }
  if(rec) {
    if(rec->obj->type == cObjectMesh) {
      ObjectMeshDump((ObjectMesh *) rec->obj, fname, 0);
    } else if(rec->obj->type == cObjectSurface) {
      ObjectSurfaceDump((ObjectSurface *) rec->obj, fname, 0);
    } else {
      ErrMessage(G, "ExecutiveDump", "Invalid object type for this operation.");
    }
  } else {
    ErrMessage(G, "ExecutiveDump", "Object not found.");
  }

}


/*========================================================================*/
void ExecutiveMemoryDump(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  fprintf(stderr, " Executive: %d candidate(s) %d list(s) %d link(s).\n",
          TrackerGetNCand(I->Tracker),
          TrackerGetNList(I->Tracker), TrackerGetNLink(I->Tracker));
}

void ExecutiveDoZoom(PyMOLGlobals * G, CObject * obj, int is_new, int zoom, int quiet)
{
  if(zoom) {                    /* -1 = use setting, 0 = never, 1 = zoom new, 
                                   2 = zoom always, 3 = zoom current, 4 = zoom all, 5= first object */
    if(zoom < 0) {
      zoom = SettingGetGlobal_i(G, cSetting_auto_zoom);
      if(zoom < 0) {
        zoom = 1;
      }
    }
    switch (zoom) {
    case 1:                    /* zoom when new */
      if(is_new)
        ExecutiveWindowZoom(G, obj->Name, 0.0, -1, 0, 0, quiet);       
      /* (all states) */
      break;
    case 2:                    /* zoom always */
      ExecutiveWindowZoom(G, obj->Name, 0.0, -1, 0, 0, quiet);  
      /* (all states) */
      break;
    case 3:                    /* always zoom current state */
      ExecutiveWindowZoom(G, obj->Name, 0.0, ObjectGetCurrentState(obj, false), 0, 0, quiet);  
      /* (all states) */
      break;
    case 4:                    /* zoom all objects */
      ExecutiveWindowZoom(G, cKeywordAll, 0.0, -1, 0, 0, quiet);
      break;
    case 5:                    /* zoom first object only */
      if(count_objects(G, true) == 1)
        ExecutiveWindowZoom(G, obj->Name, 0.0, -1, 0, 0, quiet);        /* (all states) */
      break;
    }
  }
}

static void ExecutiveDoAutoGroup(PyMOLGlobals * G, SpecRec * rec)
{
  CExecutive *I = G->Executive;
  int auto_mode = SettingGetGlobal_i(G, cSetting_group_auto_mode);
  if(auto_mode && (rec->name[0] != '_')) {
    char *period = rec->name + strlen(rec->name);
    SpecRec *found_group = NULL;
    WordType seek_group_name;
    UtilNCopy(seek_group_name, rec->name, sizeof(WordType));

    while((period > rec->name) && (!found_group)) {
      period--;
      if(*period == '.') {
        seek_group_name[period - rec->name] = 0;
        {
          SpecRec *group_rec = NULL;
          while(ListIterate(I->Spec, group_rec, next)) {
            if((group_rec->type == cExecObject) && (group_rec->obj->type == cObjectGroup)) {
              if(WordMatchExact(G, group_rec->name, seek_group_name, true)) {
                found_group = group_rec;
                strcpy(rec->group_name, seek_group_name);
                break;
              }
            }
          }
        }

        if((!found_group) && (auto_mode == 2)) {
          CObject *obj = (CObject *) ObjectGroupNew(G);
          if(obj) {
            ObjectSetName(obj, seek_group_name);
            strcpy(rec->group_name, obj->Name);
            ExecutiveManageObject(G, obj, false, true);
            ExecutiveInvalidateGroups(G, false);
            break;
          }
        }
      }
    }
    if(found_group)
      ExecutiveInvalidateGroups(G, false);
  }
}


/*========================================================================*/
void ExecutiveManageObject(PyMOLGlobals * G, CObject * obj, int zoom, int quiet)
{
  SpecRec *rec = NULL;
  CExecutive *I = G->Executive;
  int exists = false;
  int previousVisible;

  if(SettingGetGlobal_b(G, cSetting_auto_hide_selections))
    ExecutiveHideSelections(G);
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->obj == obj) {
      exists = true;
    }
  }
  if(!exists) {
    while(ListIterate(I->Spec, rec, next)) {
      if(rec->type == cExecObject) {
        if(strcmp(rec->obj->Name, obj->Name) == 0)
          break;
      }
    }
    if(rec) {                   /* another object of this type already exists */
      /* purge it */
      SceneObjectDel(G, rec->obj, false);
      ExecutiveInvalidateSceneMembers(G);
      rec->obj->fFree(rec->obj);
      rec->obj = NULL;
    } else {
      if(!quiet)
        if(obj->Name[0] != '_') {       /* suppress internal objects */
          PRINTFB(G, FB_Executive, FB_Actions)
            " Executive: object \"%s\" created.\n", obj->Name ENDFB(G);
        }
    }
    if(!rec)
      ListElemCalloc(G, rec, SpecRec);

    if(WordMatchExact(G, cKeywordAll, obj->Name, true)) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        " Executive: object name \"%s\" is illegal -- renamed to 'all_'.\n", obj->Name
        ENDFB(G);
      strcat(obj->Name, "_");   /* don't allow object named "all" */
    }
    if(SelectorNameIsKeyword(G, obj->Name)) {
      PRINTFB(G, FB_Executive, FB_Warnings)
        " Executive-Warning: name \"%s\" collides with a selection language keyword.\n",
        obj->Name ENDFB(G);
    }
    strcpy(rec->name, obj->Name);
    rec->type = cExecObject;
    rec->next = NULL;
    rec->obj = obj;
    previousVisible = rec->visible;
    if(rec->obj->type == cObjectMap) {
      rec->visible = 0;
    } else {
      rec->visible = 1;
      /*      SceneObjectAdd(G,obj); */
    }
    if (previousVisible!=rec->visible){
      ReportEnabledChange(G, rec);
    }

    rec->cand_id = TrackerNewCand(I->Tracker, (TrackerRef *) (void *) rec);

    TrackerLink(I->Tracker, rec->cand_id, I->all_names_list_id, 1);
    TrackerLink(I->Tracker, rec->cand_id, I->all_obj_list_id, 1);
    ListAppend(I->Spec, rec, next, SpecRec);
    ExecutiveAddKey(I, rec);
    ExecutiveInvalidatePanelList(G);

    if(rec->visible) {
      rec->in_scene = SceneObjectAdd(G, obj);
      ExecutiveInvalidateSceneMembers(G);
    }
    ExecutiveDoAutoGroup(G, rec);
  }

  ExecutiveUpdateObjectSelection(G, obj);

  if(SettingGetGlobal_b(G, cSetting_auto_dss)) {
    if(obj->type == cObjectMolecule) {
      ObjectMolecule *objMol = (ObjectMolecule *) obj;
      if(objMol->NCSet == 1) {
        ExecutiveAssignSS(G, obj->Name, 0, NULL, true, objMol, true);
      }
    }
  }

  if(obj->fGetNFrame) {
    int n_state = obj->fGetNFrame(obj);
    int defer_limit = SettingGetGlobal_i(G, cSetting_auto_defer_builds);
    if((defer_limit >= 0) && (n_state >= defer_limit)) {
      int defer_builds = SettingGetGlobal_b(G, cSetting_defer_builds_mode);
      if(!defer_builds)
        SettingSetGlobal_b(G, cSetting_defer_builds_mode, 1);
    }
  }

  ExecutiveDoZoom(G, obj, !exists, zoom, true);

  SeqChanged(G);
  OrthoInvalidateDoDraw(G);
}


/*========================================================================*/
void ExecutiveManageSelection(PyMOLGlobals * G, const char *name)
{

  SpecRec *rec = NULL;
  CExecutive *I = G->Executive;
  int hide_all = SettingGetGlobal_b(G, cSetting_active_selections);
  if(name[0] == '_')
    hide_all = false;           /* hidden selections don't change active selection */
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecSelection) {
      if(strcmp(rec->name, name) == 0)
        break;
      if(hide_all && rec->visible){
        rec->visible = false;
	ReportEnabledChange(G, rec);
      }
    }
  }
  if(rec && hide_all)
    while(ListIterate(I->Spec, rec, next))
      if(rec->type == cExecSelection && rec->visible){
        rec->visible = false;
	ReportEnabledChange(G, rec);
      }

  if(!rec) {
    ListElemCalloc(G, rec, SpecRec);
    strcpy(rec->name, name);
    rec->type = cExecSelection;
    rec->next = NULL;
    rec->sele_color = -1;
    if (rec->visible){
      rec->visible = false;
      ReportEnabledChange(G, rec);
    }
    rec->cand_id = TrackerNewCand(I->Tracker, (TrackerRef *) (void *) rec);
    TrackerLink(I->Tracker, rec->cand_id, I->all_names_list_id, 1);
    TrackerLink(I->Tracker, rec->cand_id, I->all_sel_list_id, 1);
    ListAppend(I->Spec, rec, next, SpecRec);
    ExecutiveAddKey(I, rec);
    ExecutiveInvalidatePanelList(G);
  }
  if(rec) {
    if(name[0] != '_') {
      if(SettingGetGlobal_b(G, cSetting_auto_hide_selections))
        ExecutiveHideSelections(G);
      if(SettingGetGlobal_b(G, cSetting_auto_show_selections) && !rec->visible) {
        rec->visible = true;
	ReportEnabledChange(G, rec);
      }
    }
    if(rec->visible)
      SceneInvalidate(G);
    ExecutiveDoAutoGroup(G, rec);
  }
  SeqDirty(G);
}


/*========================================================================*/
static int ExecutiveClick(Block * block, int button, int x, int y, int mod)
{
  PyMOLGlobals *G = block->G;
  CExecutive *I = G->Executive;
  int n, a;
  SpecRec *rec = NULL;
  PanelRec *panel = NULL;
  int t, xx;
  int pass = false;
  int skip;
  int ExecLineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
  int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
  int op_cnt = get_op_cnt(G);

  if(y < I->HowFarDown) {
    if(SettingGetGlobal_b(G, cSetting_internal_gui_mode) == 1)
      return SceneDeferClick(SceneGetBlock(G), button, x, y, mod);
  }

  switch(button) {
    case P_GLUT_BUTTON_SCROLL_FORWARD:
      ScrollBarMoveBy(I->ScrollBar, -1);
      return 1;
    case P_GLUT_BUTTON_SCROLL_BACKWARD:
      ScrollBarMoveBy(I->ScrollBar, 1);
      return 1;
  }

  n = ((I->Block->rect.top - y) - (ExecTopMargin + ExecClickMargin)) / ExecLineHeight;
  a = n;
  xx = (x - I->Block->rect.left);
  if(I->ScrollBarActive) {
    if((x - I->Block->rect.left) <
       (ExecScrollBarWidth + ExecScrollBarMargin + ExecToggleMargin)) {
      pass = 1;
      ScrollBarDoClick(I->ScrollBar, button, x, y, mod);
    }
    xx -= (ExecScrollBarWidth + ExecScrollBarMargin);
  }
  skip = I->NSkip;
  if(!pass) {
    I->RecoverPressed = NULL;
    /* while(ListIterate(I->Spec,rec,next)) { */
    while(ListIterate(I->Panel, panel, next)) {
      rec = panel->spec;

      if((rec->name[0] != '_') || (!hide_underscore)) {
        if(skip) {
          skip--;
        } else {
          if(!a) {
            t = ((I->Block->rect.right - ExecRightMargin) - x - 1) / ExecToggleWidth;
            if(t < op_cnt) {
              int my = I->Block->rect.top - (ExecTopMargin + n * ExecLineHeight) - 3;
              int mx = I->Block->rect.right - (ExecRightMargin + t * ExecToggleWidth);

#if 0
              // prefix name with % as guarantee to not match a selection keyword
              WordType namesele = "%";
              UtilNCopy(namesele + 1, (rec->type == cExecObject) ?
                  rec->obj->Name : rec->name, WordLength - 1);
#else
              char *namesele = (rec->type == cExecObject) ? rec->obj->Name : rec->name;
#endif

              t = (op_cnt - t) - 1;
              switch (t) {
              case 0:          /* action */
                switch (rec->type) {
                case cExecAll:
                  MenuActivate(G, mx, my, x, y, false, "all_action", namesele);
                  break;
                case cExecSelection:
                  MenuActivate(G, mx, my, x, y, false, "sele_action", namesele);
                  break;
                case cExecObject:
                  switch (rec->obj->type) {
                  case cObjectGroup:
                    MenuActivate(G, mx, my, x, y, false, "group_action", namesele);
                    break;
                  case cObjectMolecule:
                    MenuActivate(G, mx, my, x, y, false, "mol_action", namesele);
                    break;
                  case cObjectMap:
                    MenuActivate(G, mx, my, x, y, false, "map_action", namesele);
                    break;
                  case cObjectSurface:
                    MenuActivate(G, mx, my, x, y, false, "surface_action",
                                 namesele);
                    break;
                  case cObjectMesh:
                    MenuActivate(G, mx, my, x, y, false, "mesh_action", namesele);
                    break;
                  case cObjectMeasurement:
                  case cObjectCGO:
                  case cObjectCallback:
                  case cObjectAlignment:
		  case cObjectVolume:
                    MenuActivate(G, mx, my, x, y, false, "simple_action", namesele);
                    break;
                  case cObjectSlice:
                    MenuActivate(G, mx, my, x, y, false, "slice_action", namesele);
                    break;
                  case cObjectGadget:
                    MenuActivate(G, mx, my, x, y, false, "ramp_action", namesele);
                    break;
                  }
                  break;
                }
                break;
              case 1:
                switch (rec->type) {
                case cExecAll:
                  MenuActivate(G, mx, my, x, y, false, "mol_show", cKeywordAll);
                  break;
                case cExecSelection:
                  MenuActivate(G, mx, my, x, y, false, "mol_show", namesele);
                  break;
                case cExecObject:
                  switch (rec->obj->type) {
                  case cObjectGroup:
                  case cObjectMolecule:
                    MenuActivate(G, mx, my, x, y, false, "mol_show", namesele);
                    break;
                  case cObjectCGO:
                  case cObjectAlignment:
                    MenuActivate(G, mx, my, x, y, false, "cgo_show", namesele);
                    break;
                  case cObjectMeasurement:
                    MenuActivate(G, mx, my, x, y, false, "measurement_show",
                                 namesele);
                    break;
                  case cObjectMap:
                    MenuActivate(G, mx, my, x, y, false, "map_show", namesele);
                    break;
                  case cObjectMesh:
                    MenuActivate(G, mx, my, x, y, false, "mesh_show", namesele);
                    break;
                  case cObjectSurface:
                    MenuActivate(G, mx, my, x, y, false, "surface_show", namesele);
                    break;
                  case cObjectSlice:
                    MenuActivate(G, mx, my, x, y, false, "slice_show", namesele);
                    break;
		  case cObjectVolume:
                    MenuActivate(G, mx, my, x, y, false, "volume_show", namesele);
                    break;

                  }
                  break;
                }
                break;
              case 2:
                switch (rec->type) {
                case cExecAll:
                  MenuActivate(G, mx, my, x, y, false, "mol_hide", cKeywordAll);
                  break;
                case cExecSelection:
                  MenuActivate(G, mx, my, x, y, false, "mol_hide", namesele);
                  break;
                case cExecObject:
                  switch (rec->obj->type) {
                  case cObjectGroup:
                  case cObjectMolecule:
                    MenuActivate(G, mx, my, x, y, false, "mol_hide", namesele);
                    break;
                  case cObjectCGO:
                  case cObjectAlignment:
                    MenuActivate(G, mx, my, x, y, false, "cgo_hide", namesele);
                    break;
                  case cObjectMeasurement:
                    MenuActivate(G, mx, my, x, y, false, "measurement_hide",
                                 namesele);
                    break;
                  case cObjectMap:
                    MenuActivate(G, mx, my, x, y, false, "map_hide", namesele);
                    break;
                  case cObjectMesh:
                    MenuActivate(G, mx, my, x, y, false, "mesh_hide", namesele);
                    break;
                  case cObjectSurface:
                    MenuActivate(G, mx, my, x, y, false, "surface_hide", namesele);
                    break;
                  case cObjectSlice:
                    MenuActivate(G, mx, my, x, y, false, "slice_hide", namesele);
                    break;
		  case cObjectVolume:
                    MenuActivate(G, mx, my, x, y, false, "volume_hide", namesele);
                    break;
		    

                  }
                  break;
                }
                break;
              case 3:
                switch (rec->type) {
                case cExecAll:
                  MenuActivate(G, mx, my, x, y, false, "mol_labels", "(all)");
                  break;
                case cExecSelection:
                  MenuActivate(G, mx, my, x, y, false, "mol_labels", namesele);
                  break;
                case cExecObject:
                  switch (rec->obj->type) {
                  case cObjectGroup:
                  case cObjectMolecule:
                    MenuActivate(G, mx, my, x, y, false, "mol_labels", namesele);
                    break;
                  case cObjectMeasurement:
                    break;
                  case cObjectMap:
                  case cObjectSurface:
                  case cObjectMesh:
                  case cObjectSlice:
                    break;
                  }
                  break;
                }
                break;
              case 4:
                switch (rec->type) {
                case cExecAll:
                case cExecSelection:
                  MenuActivate(G, mx, my, x, y, false, "mol_color", namesele);
                  break;
                case cExecObject:
                  switch (rec->obj->type) {
                  case cObjectGroup:
                  case cObjectMolecule:
                    MenuActivate(G, mx, my, x, y, false, "mol_color", namesele);
                    break;
                  case cObjectMap:
                  case cObjectCGO:
                  case cObjectAlignment:
                    MenuActivate(G, mx, my, x, y, false, "general_color", namesele);
                    break;
                  case cObjectMesh:
                    MenuActivate(G, mx, my, x, y, false, "mesh_color", namesele);
                    break;
                  case cObjectSurface:
                    MenuActivate2Arg(G, mx, my, x, y, false, "mesh_color", namesele, "surface");
                    break;
                  case cObjectMeasurement:
                    MenuActivate(G, mx, my, x, y, false, "measurement_color", namesele);
                    break;
                  case cObjectSlice:
                    MenuActivate(G, mx, my, x, y, false, "slice_color", namesele);
                    break;
                  case cObjectVolume:
                    MenuActivate(G, mx, my, x, y, false, "vol_color", namesele);
                    break;
                  case cObjectGadget:
                    MenuActivate(G, mx, my, x, y, false, "ramp_color", namesele);
                    break;
                  }
                  break;
                }
                break;
              case 5:
                switch (rec->type) {
                case cExecAll:
                  MenuActivate0Arg(G, mx, my, x, y, false, "camera_motion");
                  break;
                case cExecSelection: /* not relevant at present */
		  break;
                case cExecObject: /* this kinds of objects can be animated */
                  switch (rec->obj->type) {
                  case cObjectGroup: /* however, this just groups motions for a set of objects */
                  case cObjectMolecule:
		  case cObjectMeasurement:
		  case cObjectMap:
		  case cObjectSurface:
		  case cObjectCGO:
		  case cObjectMesh:
                    MenuActivate(G, mx, my, x, y, false, "obj_motion", namesele);
                    break;
                  }
                  break;
                }
                break;
              }
            } else {            /* clicked in variable area */

              if(((panel->is_group) && (((xx) - 1) / DIP2PIXEL(8)) > (panel->nest_level + 1)) ||
                 ((!panel->is_group) && (((xx) - 1) / DIP2PIXEL(8)) > panel->nest_level)) {
                /* clicked on name */

                rec->hilight = 1;
                switch (button) {
                case P_GLUT_LEFT_BUTTON:
                  I->Pressed = n;
                  I->OldVisibility = rec->visible;
                  I->Over = n;
                  I->DragMode = 1;
                  I->ToggleMode = 0;
                  I->LastChanged = NULL;
                  I->LastZoomed = NULL;
                  if(mod == (cOrthoSHIFT | cOrthoCTRL)) {
                    I->ToggleMode = 2;
                    if(!rec->visible) {
                      ExecutiveSpecSetVisibility(G, rec, !I->OldVisibility, mod, false);
                    }
                    if(rec != I->LastZoomed)
                      ExecutiveWindowZoom(G, rec->name, 0.0F, -1, false, -1.0F, true);
                    I->LastZoomed = rec;
                    I->LastChanged = rec;
                  } else if(mod & cOrthoSHIFT) {
                    ExecutiveSpecSetVisibility(G, rec, !I->OldVisibility, mod, false);
                    I->ToggleMode = 1;
                  } else if(mod & cOrthoCTRL) {
                    I->ToggleMode = 2;
                    if(!rec->visible) {
                      ExecutiveSpecSetVisibility(G, rec, !I->OldVisibility, mod, false);
                    }
                    I->LastChanged = rec;
                  }
                  I->PressedWhat = 1;
                  I->OverWhat = 1;
                  break;
                case P_GLUT_MIDDLE_BUTTON:
                  I->Pressed = n;
                  I->OldVisibility = rec->visible;
                  I->Over = n;
                  I->LastOver = I->Over;
                  I->DragMode = 3;
                  I->ToggleMode = 0;
                  I->LastChanged = rec;
                  I->LastZoomed = NULL;
                  if(mod & cOrthoCTRL) {
                    I->ToggleMode = 5;
                    ExecutiveWindowZoom(G, rec->name, 0.0F, -1, false, -1.0F, true);
                    I->LastZoomed = rec;
                    if(mod & cOrthoSHIFT) {     /* exclusive */
                      I->ToggleMode = 6;
                      ExecutiveSetObjVisib(G, cKeywordAll, false, false);       
                      /* need to log this */
                      if(!rec->visible)
                        ExecutiveSpecSetVisibility(G, rec, true, 0, true);
                    }
                  } else {
                    I->ToggleMode = 4;
                    ExecutiveCenter(G, rec->name, -1, true, -1.0F, NULL, true);
                  }
                  if(!rec->visible) {
                    ExecutiveSpecSetVisibility(G, rec, !rec->visible, mod, false);
                    I->LastChanged = rec;
                  }
                  I->PressedWhat = 1;
                  I->OverWhat = 1;
                  break;
                case P_GLUT_RIGHT_BUTTON:
                  I->DragMode = 2;      /* reorder */
                  I->Pressed = n;
                  I->Over = n;
                  I->LastOver = I->Over;
                  I->PressedWhat = 1;
                  I->OverWhat = 1;
                  break;
                }
                OrthoGrab(G, I->Block);
                OrthoDirty(G);
              } else if(panel->is_group) {
                /* clicked on group control */
                rec->hilight = 2;
                I->DragMode = 1;
                I->Pressed = n;
                I->Over = n;
                I->LastOver = I->Over;
                I->PressedWhat = 2;
                I->OverWhat = 2;

                OrthoGrab(G, I->Block);
                OrthoDirty(G);
              }
            }
          }
          a--;
        }
      }
    }
  }
  PyMOL_NeedRedisplay(G->PyMOL);
  return (1);
}


/*========================================================================*/
static void ExecutiveSpecEnable(PyMOLGlobals * G, SpecRec * rec, int parents, int log)
{
  if(log && SettingGetGlobal_b(G, cSetting_logging)) {
    OrthoLineType buffer = "";
    sprintf(buffer, "cmd.enable('%s',%d)", rec->obj->Name, parents);
    PLog(G, buffer, cPLog_pym);
  }

  if(!rec->visible) {
    rec->visible = true;
    ReportEnabledChange(G, rec);
  }
  if(!rec->in_scene) {
    rec->in_scene = SceneObjectAdd(G, rec->obj);
  }

  if(parents) {
    CExecutive *I = G->Executive;
    CTracker *I_Tracker = I->Tracker;
    int list_id = ExecutiveGetObjectParentList(G, rec);
    if(list_id) {
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
      SpecRec *parent_rec = NULL;

      while(TrackerIterNextCandInList(I_Tracker, iter_id,
                                      (TrackerRef **) (void *) &parent_rec)) {
        if(rec) {
          switch (parent_rec->type) {
          case cExecObject:
            if(!parent_rec->in_scene) {
              parent_rec->in_scene = SceneObjectAdd(G, parent_rec->obj);
            }
            if(!parent_rec->visible) {
              parent_rec->visible = true;
	      ReportEnabledChange(G, parent_rec);
            }
          }
        }
      }
      TrackerDelIter(I_Tracker, iter_id);
    }
    TrackerDelList(I_Tracker, list_id);
  }
  ExecutiveInvalidateSceneMembers(G);
}

static void ExecutiveSpecSetVisibility(PyMOLGlobals * G, SpecRec * rec,
                                       int new_vis, int mod, int parents)
{
  OrthoLineType buffer = "";
  int logging = SettingGetGlobal_i(G, cSetting_logging);
  if(rec->type == cExecObject) {
    if(rec->visible && !new_vis) {
      if(logging)
        sprintf(buffer, "cmd.disable('%s')", rec->obj->Name);
      SceneObjectDel(G, rec->obj, true);
      ExecutiveInvalidateSceneMembers(G);
      if (rec->visible != new_vis){
	rec->visible = new_vis;
	ReportEnabledChange(G, rec);
      }
    } else if((!rec->visible) && new_vis) {
      ExecutiveSpecEnable(G, rec, parents, logging);
      /*
         if(logging) 
         sprintf(buffer,"cmd.enable('%s')",rec->obj->Name);
         rec->in_scene = SceneObjectAdd(G,rec->obj);
         rec->visible=new_vis;
         ExecutiveInvalidateSceneMembers(G);
       */
    }
    SceneChanged(G);
    if(logging && buffer[0]) {
      PLog(G, buffer, cPLog_pym);
    }
  } else if(rec->type == cExecAll) {
    if(SettingGetGlobal_i(G, cSetting_logging)) {
      if(rec->visible)
        sprintf(buffer, "cmd.disable('all')");
      else
        sprintf(buffer, "cmd.enable('all')");
      PLog(G, buffer, cPLog_pym);
    }
    ExecutiveSetObjVisib(G, cKeywordAll, !rec->visible, false);
  } else if(rec->type == cExecSelection) {
    if(mod & cOrthoCTRL) {
      sprintf(buffer, "cmd.enable('%s')", rec->name);
      PLog(G, buffer, cPLog_pym);
      if (!rec->visible){
	rec->visible = true;
	ReportEnabledChange(G, rec);
      }
    } else {

      if(rec->visible && !new_vis) {
        if(SettingGetGlobal_i(G, cSetting_logging))
          sprintf(buffer, "cmd.disable('%s')", rec->name);
      } else if((!rec->visible) && new_vis) {
        sprintf(buffer, "cmd.enable('%s')", rec->name);
      }
      if(new_vis && SettingGetGlobal_b(G, cSetting_active_selections)) {
        ExecutiveHideSelections(G);
      }
      if(SettingGetGlobal_i(G, cSetting_logging)) {
        PLog(G, buffer, cPLog_pym);
      }
      if (rec->visible != new_vis){
	rec->visible = new_vis;
	ReportEnabledChange(G, rec);
      }
    }
    SceneChanged(G);
  }
}

int ExecutiveAssignAtomTypes(PyMOLGlobals * G, const char *s1, int format, int state, int quiet)
{
  int result = 0;
  int sele1;

  sele1 = SelectorIndexByName(G, s1);
  if(state < 0)
    state = 0;
  {
    int unblock = PAutoBlock(G);        /*   PBlock(G);    PBlockAndUnlockAPI(); */
    if(sele1 >= 0) {
      result = SelectorAssignAtomTypes(G, sele1, state, quiet, format);
    }
    PAutoUnblock(G, unblock);   /*    PUnblock(G);  PLockAPIAndUnblock(); */
  }
  return (result);
}

static int ExecutiveRelease(Block * block, int button, int x, int y, int mod)
{
  PyMOLGlobals *G = block->G;
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
  PanelRec *panel = NULL;
  int pass = false;
  int skip;
  int xx;
  int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
  if(y < I->HowFarDown) {
    if(SettingGetGlobal_b(G, cSetting_internal_gui_mode) == 1)
      return SceneDeferRelease(SceneGetBlock(G), button, x, y, mod);
  }

  xx = (x - I->Block->rect.left);
  if(I->ScrollBarActive) {
    if((x - I->Block->rect.left) <
       (ExecScrollBarWidth + ExecScrollBarMargin + ExecToggleMargin)) {
      pass = 1;
      ScrollBarDoRelease(I->ScrollBar, button, x, y, mod);
      OrthoUngrab(G);
    }
    xx -= (ExecScrollBarWidth + ExecScrollBarMargin);
  }

  skip = I->NSkip;

  if(!pass) {
    ExecutiveDrag(block, x, y, mod);    /* incorporate final changes in cursor position */
    switch (I->DragMode) {
    case 1:

      /*while(ListIterate(I->Spec,rec,next)) { */
      while(ListIterate(I->Panel, panel, next)) {
        rec = panel->spec;

        if((rec->name[0] != '_') || (!hide_underscore)) {
          if(skip) {
            skip--;
          } else {
            if((I->PressedWhat == 1) &&
               (((panel->is_group) && ((xx - 1) / DIP2PIXEL(8)) > (panel->nest_level + 1)) ||
                ((!panel->is_group) && ((xx - 1) / DIP2PIXEL(8)) > panel->nest_level))) {
              /* over name */
              if(rec->hilight == 1) {
                if(rec->type == cExecSelection) {
                  ExecutiveSpecSetVisibility(G, rec, !I->OldVisibility, 0, false);
                } else {
                  ExecutiveSpecSetVisibility(G, rec, !I->OldVisibility, mod, true);
                }
              }
            } else if((I->PressedWhat == 2) && (panel->is_group)) {
              if(rec->hilight == 2) {
                ObjectGroup *obj = (ObjectGroup *) rec->obj;
                OrthoLineType buf2;
                sprintf(buf2, "cmd.group(\"%s\",action='%s')\n", rec->obj->Name,
                        obj->OpenOrClosed ? "close" : "open");
                PLog(G, buf2, cPLog_no_flush);
                ExecutiveGroup(G, rec->obj->Name, "", 5, 1);

              }
              /* over group control */
            }
          }
        }
      }
      break;
    case 2:
      if(I->ReorderFlag) {
        I->ReorderFlag = false;
        PLog(G, I->ReorderLog, cPLog_no_flush);
      }
      break;
    }
  }

  {
    SpecRec *rec = NULL;
    while(ListIterate(I->Spec, rec, next)) {
      rec->hilight = 0;
    }
  }

  I->Over = -1;
  I->Pressed = -1;
  I->DragMode = 0;
  I->PressedWhat = 0;
  OrthoUngrab(G);
  PyMOL_NeedRedisplay(G->PyMOL);
  return (1);
}


/*========================================================================*/
static int ExecutiveDrag(Block * block, int x, int y, int mod)
{
  PyMOLGlobals *G = block->G;
  CExecutive *I = G->Executive;
  int xx, t;
  int ExecLineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
  int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
  int op_cnt = get_op_cnt(G);

  ExecutiveUpdateGroups(G, false);
  ExecutiveUpdatePanelList(G);
  if(y < I->HowFarDown) {
    if(SettingGetGlobal_b(G, cSetting_internal_gui_mode) == 1)
      return SceneDeferDrag(SceneGetBlock(G), x, y, mod);
  }

  if(I->DragMode) {
    xx = (x - I->Block->rect.left);
    t = ((I->Block->rect.right - ExecRightMargin) - x) / ExecToggleWidth;
    if(I->ScrollBarActive) {
      xx -= (ExecScrollBarWidth + ExecScrollBarMargin);
    }

    {
      int row_offset;
      if((xx >= 0) && (t >= op_cnt)) {
        row_offset = ((I->Block->rect.top - y) -
                      (ExecTopMargin + ExecClickMargin)) / ExecLineHeight;
        I->Over = row_offset;
      } else {
        I->Over = -1;
        row_offset = -1;
        {
          SpecRec *rec = NULL;
          while(ListIterate(I->Spec, rec, next))
            rec->hilight = 0;
        }
      }

      if(I->RecoverPressed) {
        SpecRec *rec = NULL;
        PanelRec *panel = NULL;
        int skip = I->NSkip;
        int row = 0;
        while(ListIterate(I->Panel, panel, next)) {
          rec = panel->spec;

          if((rec->name[0] != '_') || (!hide_underscore)) {
            if(skip) {
              skip--;
            } else {
              if(rec == I->RecoverPressed) {
                I->Pressed = row;
                I->RecoverPressed = NULL;
              }
              row++;
            }
          }
        }
      }

      if(I->PressedWhat == 2) {
        I->OverWhat = 0;
      }
      if(I->Over >= 0) {
        SpecRec *rec = NULL;
        PanelRec *panel = NULL;
        int skip = I->NSkip;
        int row = 0;
        switch (I->DragMode) {
        case 1:

          /*          while(ListIterate(I->Spec,rec,next)) { */
          while(ListIterate(I->Panel, panel, next)) {
            rec = panel->spec;

            if((rec->name[0] != '_') || (!hide_underscore)) {
              if(skip) {
                skip--;
              } else {

                rec->hilight = 0;
                if((I->PressedWhat == 1) &&     /* name button */
                   (((row >= I->Over) && (row <= I->Pressed)) ||
                    ((row >= I->Pressed) && (row <= I->Over)))) {

                  if(((panel->is_group) && ((xx - 1) / DIP2PIXEL(8)) > (panel->nest_level + 1)) ||
                     ((!panel->is_group) && ((xx - 1) / DIP2PIXEL(8)) > panel->nest_level)) {
                    /* dragged over name */

                    I->OverWhat = 1;

                    switch (I->ToggleMode) {
                    case 0:
                      if(row || (row == I->Pressed))
                        rec->hilight = 1;
                      break;
                    case 1:
                      if(row)
                        ExecutiveSpecSetVisibility(G, rec, !I->OldVisibility, mod, false);
                      break;
                    case 2:
                      if((row == I->Over) && row) {
                        if(I->LastChanged != rec) {
                          ExecutiveSpecSetVisibility(G, I->LastChanged, false, mod,
                                                     false);
                        }
                        if(!rec->visible) {
                          ExecutiveSpecSetVisibility(G, rec, true, mod, false);
                          I->LastChanged = rec;
                        }
                        if(mod == (cOrthoSHIFT | cOrthoCTRL)) {
                          if(rec != I->LastZoomed)
                            ExecutiveWindowZoom(G, rec->name, 0.0F, -1, false, -1.0F,
                                                true);
                          I->LastZoomed = rec;
                        }
                      }
                      break;
                    }
                  }
                } else if((row == I->Pressed) && (I->PressedWhat == 2)) {
                  if(!((panel->is_group) && ((xx - 1) / DIP2PIXEL(8)) > (panel->nest_level + 1))) {

                    /* on group control */

                    I->OverWhat = 2;
                    if(I->PressedWhat == I->OverWhat) {
                      rec->hilight = 2;
                    }
                  } else {
                    I->OverWhat = 0;
                  }
                }
                row++;
              }
            }
          }
          break;
        case 2:                /* right buttonBROKEN */
          {
            if((I->Over != I->Pressed) && (I->LastOver != I->Over)) {
              SpecRec *new_rec = NULL;
              SpecRec *mov_rec = NULL;
              PanelRec *panel = NULL;

              while(ListIterate(I->Panel, panel, next)) {
                rec = panel->spec;
                if((rec->name[0] != '_') || (!hide_underscore)) {
                  {
                    if(skip) {
                      skip--;
                    } else {
                      if(row == I->Pressed) {
                        mov_rec = rec;
                      }
                      if(row == I->Over) {
                        new_rec = rec;
                      }
                      row++;
                    }
                  }
                }
              }
              {
                int group_flag = false;
                int order_flag = false;
                int location = 0;
                char *first = NULL, *second = NULL;
                int is_child = false;

                if(mov_rec && (!new_rec) && (I->Over > I->Pressed) && mov_rec->group) {
                  first = mov_rec->group->name;
                  second = mov_rec->name;
                  order_flag = true;
                  strcpy(mov_rec->group_name, mov_rec->group->group_name);
                  group_flag = true;
                } else if(mov_rec && new_rec) {
                  if(mov_rec == new_rec->group) {
                    /* do nothing when a group is dragged over one of its members */
                  } else {

                    if(I->Pressed < I->Over) {  /* downward */
                      first = new_rec->name;
                      second = mov_rec->name;
                      order_flag = true;
                    } else {    /* upward */
                      first = mov_rec->name;
                      second = new_rec->name;
                      order_flag = true;
                      location = -2;    /* upper */
                    }

                    if(mov_rec->group == new_rec->group) {      /* reordering within a group level */
                      if((new_rec->type == cExecObject)
                         && (new_rec->obj->type == cObjectGroup)) {
                        ObjectGroup *group = (ObjectGroup *) new_rec->obj;
                        if(group->OpenOrClosed && !is_child) {
                          /* put inside an open group */
                          strcpy(mov_rec->group_name, new_rec->name);
                          order_flag = false;
                          group_flag = true;
                        }
                      }
                    } else if((mov_rec->group != new_rec) && (new_rec->group != mov_rec)) {

                      if((new_rec->type == cExecObject)
                         && (new_rec->obj->type == cObjectGroup)) {
                        ObjectGroup *group = (ObjectGroup *) new_rec->obj;
                        if(group->OpenOrClosed && !is_child) {
                          /* put inside group */
                          strcpy(mov_rec->group_name, new_rec->name);
                        } else {
                          strcpy(mov_rec->group_name, new_rec->group_name);
                        }

                        /* WLD TEST */

                        if(I->Pressed < I->Over) {      /* downward */
                          first = new_rec->name;
                          second = mov_rec->name;
                          order_flag = true;
                        } else {        /* upward */
                          first = mov_rec->name;
                          second = new_rec->name;
                          order_flag = true;
                        }

                        /* WLD END */

                      } else
                        strcpy(mov_rec->group_name, new_rec->group_name);
                      group_flag = true;
                    }
                  }
                }

                if(group_flag) {
                  OrthoLineType buf;
                  if(mov_rec->group_name[0]) {
                    sprintf(buf, "group %s, %s\n", mov_rec->group_name, mov_rec->name);
                  } else {
                    sprintf(buf, "ungroup %s\n", mov_rec->name);
                  }
                  PLog(G, buf, cPLog_no_flush);
                  ExecutiveInvalidateGroups(G, false);
                  I->RecoverPressed = mov_rec;
                  I->Pressed = 0;
                }
                if(order_flag && first && second) {
                  OrthoLineType order_input;
                  sprintf(order_input, "%s %s", first, second);
                  ExecutiveOrder(G, order_input, false, location);
                  sprintf(I->ReorderLog, "cmd.order(\"%s\",location=\"%s\")\n",
                          order_input, (location == -2) ? "upper" : "current");
                  PLog(G, I->ReorderLog, cPLog_no_flush);
                  I->RecoverPressed = mov_rec;
                  I->Pressed = 0;
                }
              }
            }
          }
          break;
        case 3:                /* middle button */
          /* while(ListIterate(I->Spec,rec,next)) { */
          while(ListIterate(I->Panel, panel, next)) {
            rec = panel->spec;
            if((rec->name[0] != '_') || (!hide_underscore)) {
              if(skip) {
                skip--;
              } else {
                rec->hilight = 0;
                if(((row >= I->Over) && (row <= I->Pressed)) ||
                   ((row >= I->Pressed) && (row <= I->Over))) {
                  switch (I->ToggleMode) {
                  case 4:      /* center and activate, while deactivating previous */
                    if((row == I->Over) && row) {
                      if(I->LastChanged != rec) {
                        ExecutiveSpecSetVisibility(G, I->LastChanged, false, mod, false);
                        ExecutiveCenter(G, rec->name, -1, true, -1.0F, NULL, true);
                        if(!rec->visible)
                          ExecutiveSpecSetVisibility(G, rec, true, mod, false);
                        I->LastChanged = rec;
                      }
                      rec->hilight = 0;
                    }
                    break;
                  case 5:      /* zoom and activate, while deactivating previous */
                    if((row == I->Over) && row) {
                      if(I->LastChanged != rec) {
                        ExecutiveSpecSetVisibility(G, I->LastChanged, false, mod, false);
                        ExecutiveWindowZoom(G, rec->name, 0.0F, -1, false, -1.0F, true);
                        if(!rec->visible)
                          ExecutiveSpecSetVisibility(G, rec, true, mod, false);
                        I->LastChanged = rec;
                      }
                      rec->hilight = 1;
                    }
                    break;
                  case 6:      /* zoom and make only object enabled */
                    if((row == I->Over) && row) {
                      if(rec != I->LastZoomed) {
                        ExecutiveSpecSetVisibility(G, I->LastZoomed, false, mod, false);
                        ExecutiveWindowZoom(G, rec->name, 0.0F, -1, false, -1.0F, true);
                        I->LastZoomed = rec;
                        ExecutiveSpecSetVisibility(G, rec, true, 0, false);
                      }
                      rec->hilight = 1;
                    }
                  }
                }
                row++;
              }
            }
          }
          break;
        }
        I->LastOver = I->Over;

      } else if(I->LastChanged)
        ExecutiveSpecSetVisibility(G, I->LastChanged, false, mod, false);
      OrthoDirty(G);
    }
  }
  return (1);
}

static void draw_button(int x2, int y2, int w, int h, float *light, float *dark,
                        float *inside ORTHOCGOARG)
{
  if (orthoCGO){
    CGOColorv(orthoCGO, light);
    CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
    CGOVertex(orthoCGO, x2, y2, 0.f);
    CGOVertex(orthoCGO, x2, y2 + h, 0.f);
    CGOVertex(orthoCGO, x2 + w, y2, 0.f);
    CGOVertex(orthoCGO, x2 + w, y2 + h, 0.f);
    CGOEnd(orthoCGO);
  } else {
    glColor3fv(light);
    glBegin(GL_POLYGON);
    glVertex2i(x2, y2);
    glVertex2i(x2, y2 + h);
    glVertex2i(x2 + w, y2 + h);
    glVertex2i(x2 + w, y2);
    glEnd();
  }

  if (orthoCGO){
    CGOColorv(orthoCGO, dark);
    CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
    CGOVertex(orthoCGO, x2 + 1, y2, 0.f);
    CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
    CGOVertex(orthoCGO, x2 + w, y2, 0.f);
    CGOVertex(orthoCGO, x2 + w, y2 + h - 1, 0.f);
    CGOEnd(orthoCGO);
  } else {
    glColor3fv(dark);
    glBegin(GL_POLYGON);
    glVertex2i(x2 + 1, y2);
    glVertex2i(x2 + 1, y2 + h - 1);
    glVertex2i(x2 + w, y2 + h - 1);
    glVertex2i(x2 + w, y2);
    glEnd();
  }

  if(inside) {
    if (orthoCGO){
      CGOColorv(orthoCGO, inside);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, x2 + 1, y2 + 1, 0.f);
      CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
      CGOVertex(orthoCGO, x2 + w - 1, y2 + 1, 0.f);
      CGOVertex(orthoCGO, x2 + w - 1, y2 + h - 1, 0.f);
      CGOEnd(orthoCGO);
    } else {
      glColor3fv(inside);
      glBegin(GL_POLYGON);
      glVertex2i(x2 + 1, y2 + 1);
      glVertex2i(x2 + 1, y2 + h - 1);
      glVertex2i(x2 + w - 1, y2 + h - 1);
      glVertex2i(x2 + w - 1, y2 + 1);
      glEnd();
    }
  } else {                      /* rainbow */
    if (orthoCGO){
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOColor(orthoCGO, 0.1F, 1.0F, 0.1F); // green
      CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
      CGOColor(orthoCGO, 1.0F, 1.0F, 0.1F);  // yellow
      CGOVertex(orthoCGO, x2 + w - 1, y2 + h - 1, 0.f);
      CGOColor(orthoCGO, 1.f, 0.1f, 0.1f); // red
      CGOVertex(orthoCGO, x2 + 1, y2 + 1, 0.f);
      CGOColor(orthoCGO, 0.1F, 0.1F, 1.0F);  // blue
      CGOVertex(orthoCGO, x2 + w - 1, y2 + 1, 0.f);
      CGOEnd(orthoCGO);
    } else {
      glBegin(GL_POLYGON);
      glColor3f(1.0F, 0.1F, 0.1F);
      glVertex2i(x2 + 1, y2 + 1);
      glColor3f(0.1F, 1.0F, 0.1F);
      glVertex2i(x2 + 1, y2 + h - 1);
      glColor3f(1.0F, 1.0F, 0.1F);
      glVertex2i(x2 + w - 1, y2 + h - 1);
      glColor3f(0.1F, 0.1F, 1.0F);
      glVertex2i(x2 + w - 1, y2 + 1);
      glEnd();
    }
  }
}

#ifndef _PYMOL_NOPY
static void draw_button_char(PyMOLGlobals * G, int x2, int y2, char ch ORTHOCGOARG)
{
  TextSetColor3f(G, 0.0F, 0.0F, 0.0F);
  TextSetPos2i(G, x2 + ExecToggleTextShift, y2);
  TextDrawChar(G, ch ORTHOCGOARGVAR);
}
#endif


/*========================================================================*/
static void ExecutiveDraw(Block * block ORTHOCGOARG)
{
  PyMOLGlobals *G = block->G;
  int x, y, xx, x2, y2;
  WordType ch;
  char *c = NULL;
  float enabledColor[3] = { 0.5F, 0.5F, 0.5F };
  float cloakedColor[3] = { 0.35F, 0.35F, 0.35F };
  float pressedColor[3] = { 0.7F, 0.7F, 0.7F };
  float disabledColor[3] = { 0.25F, 0.25F, 0.25F };
  float lightEdge[3] = { 0.6F, 0.6F, 0.6F };
  float darkEdge[3] = { 0.35F, 0.35F, 0.35F };
  float captionColor[3] = { 0.3F, 0.9F, 0.3F };

#ifndef _PYMOL_NOPY
  float activeColor[3] = { 0.9F, 0.9F, 1.0F };
  float toggleColor3[3] = { 0.6F, 0.6F, 0.8F };
#endif

  SpecRec *rec = NULL;
  PanelRec *panel = NULL;
  CExecutive *I = G->Executive;
  int n_ent;
  int n_disp;
  int skip = 0;
  int row = -1;
  int ExecLineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
  int text_lift = (ExecLineHeight / 2) - DIP2PIXEL(5);
  int hide_underscore = SettingGetGlobal_b(G, cSetting_hide_underscore_names);
  int op_cnt = get_op_cnt(G);
  int full_names = SettingGetGlobal_b(G, cSetting_group_full_member_names);
  int arrows = SettingGetGlobal_b(G, cSetting_group_arrow_prefix);

  ExecutiveUpdatePanelList(G);
  
  /* if we're running with a GUI and have a valid panel */
  if(G->HaveGUI && G->ValidContext && ((block->rect.right - block->rect.left) > 6)
     && I->ValidPanel) {
    int max_char;
    int nChar;

    /* count entries
     * do we have enough structures to warrant a scroll bar? */
    n_ent = 0;
    while(ListIterate(I->Panel, panel, next)) {
      rec = panel->spec;
      if(rec && ((rec->name[0] != '_') || (!hide_underscore)))
        n_ent++;
    }

    n_disp =
      ((I->Block->rect.top - I->Block->rect.bottom) - (ExecTopMargin)) / ExecLineHeight;
    if(n_disp < 1)
      n_disp = 1;

    /* we need a scrollbar */
    if(n_ent > n_disp) {
      int bar_maxed = ScrollBarIsMaxed(I->ScrollBar);
      if(!I->ScrollBarActive) {
        ScrollBarSetLimits(I->ScrollBar, n_ent, n_disp);
        if(bar_maxed) {
          ScrollBarMaxOut(I->ScrollBar);
          I->NSkip = (int) ScrollBarGetValue(I->ScrollBar);
        } else {
          ScrollBarSetValue(I->ScrollBar, 0);
          I->NSkip = 0;
        }
      } else {
        ScrollBarSetLimits(I->ScrollBar, n_ent, n_disp);
        if(bar_maxed)
          ScrollBarMaxOut(I->ScrollBar);
        I->NSkip = (int) ScrollBarGetValue(I->ScrollBar);
      }
      I->ScrollBarActive = 1;
    } else {
      I->ScrollBarActive = 0;
      I->NSkip = 0;
    }

    /* determination of longest string based on internal_gui_size, etc... */
    max_char =
      (((I->Block->rect.right - I->Block->rect.left) -
        (ExecLeftMargin + ExecRightMargin + 4)) - (op_cnt * ExecToggleWidth));
    if(I->ScrollBarActive) {
      max_char -= (ExecScrollBarMargin + ExecScrollBarWidth);
    }
    max_char /= DIP2PIXEL(8);

    /* fill and outline the entire block */
    if(SettingGetGlobal_b(G, cSetting_internal_gui_mode) == 0) {
      if (orthoCGO)
	CGOColorv(orthoCGO, I->Block->BackColor);
      else
	glColor3fv(I->Block->BackColor);
      BlockFill(I->Block ORTHOCGOARGVAR);
      BlockDrawLeftEdge(I->Block ORTHOCGOARGVAR);
    }

    /* draw the scroll bar */
    if(I->ScrollBarActive) {
      ScrollBarSetBox(I->ScrollBar, I->Block->rect.top - ExecScrollBarMargin,
                      I->Block->rect.left + ExecScrollBarMargin,
                      I->Block->rect.bottom + 2,
                      I->Block->rect.left + ExecScrollBarMargin + ExecScrollBarWidth);
      ScrollBarDoDraw(I->ScrollBar ORTHOCGOARGVAR);
    }

    x = I->Block->rect.left + ExecLeftMargin;
    y = (I->Block->rect.top - ExecLineHeight) - ExecTopMargin;
    /*    xx = I->Block->rect.right-ExecRightMargin-ExecToggleWidth*(cRepCnt+op_cnt); */
#ifndef _PYMOL_NOPY
    xx = I->Block->rect.right - ExecRightMargin - ExecToggleWidth * (op_cnt);
#else
    xx = I->Block->rect.right - ExecRightMargin;
#endif

    if(I->ScrollBarActive) {
      x += ExecScrollBarWidth + ExecScrollBarMargin;
    }
    skip = I->NSkip;

    /* for each object in the Panel... */
    while(ListIterate(I->Panel, panel, next)) {
      rec = panel->spec;
      {
        if(skip) {
          skip--;
        } else {
	  /* setup the X,Y offsets for this entry */
          row++;
          x2 = xx;
          y2 = y;
          nChar = max_char;

          if((x - ExecToggleMargin) - (xx - ExecToggleMargin) > -10) {
            x2 = x + 10;
          }
#ifndef _PYMOL_NOPY
	  /*
	   * The ASHLC menus; these access Python so,
	   * protect this block from non-python instances
	   */
          {
            int a;
            float toggleColor[3] = { 0.5F, 0.5F, 1.0F };
            float toggleColor2[3] = { 0.4F, 0.4F, 0.6F };
            float toggleDarkEdge[3] = { 0.3F, 0.3F, 0.5F };
            float toggleLightEdge[3] = { 0.7F, 0.7F, 0.9F };

            glColor3fv(toggleColor);
            for(a = 0; a < op_cnt; a++) {
              switch (a) {
              case 0:
                /*
                   glColor3fv(toggleColor);
                   glBegin(GL_POLYGON);
                   glVertex2i(x2,y2+(ExecToggleSize)/2);
                   glVertex2i(x2+(ExecToggleSize)/2,y2);
                   glVertex2i(x2+ExecToggleSize,y2+(ExecToggleSize)/2);
                   glVertex2i(x2+(ExecToggleSize)/2,y2+ExecToggleSize);
                   glEnd();
                 */

		/* the infamous ASHLC! */

                draw_button(x2, y2, ExecToggleSize, (ExecLineHeight - 1),
                            toggleLightEdge, toggleDarkEdge, toggleColor ORTHOCGOARGVAR);

                draw_button_char(G, x2, y2 + text_lift, 'A' ORTHOCGOARGVAR);
                break;
              case 1:
                draw_button(x2, y2, ExecToggleSize, (ExecLineHeight - 1),
                            toggleLightEdge, toggleDarkEdge, toggleColor3 ORTHOCGOARGVAR);

                draw_button_char(G, x2, y2 + text_lift, 'S' ORTHOCGOARGVAR);
                break;
              case 2:
                draw_button(x2, y2, ExecToggleSize, (ExecLineHeight - 1),
                            toggleLightEdge, toggleDarkEdge, toggleColor2 ORTHOCGOARGVAR);
                draw_button_char(G, x2, y2 + text_lift, 'H' ORTHOCGOARGVAR);
                break;
              case 3:
                draw_button(x2, y2, ExecToggleSize, (ExecLineHeight - 1),
                            toggleLightEdge, toggleDarkEdge, toggleColor ORTHOCGOARGVAR);
                draw_button_char(G, x2, y2 + text_lift, 'L' ORTHOCGOARGVAR);
                break;
              case 4:
                draw_button(x2, y2, ExecToggleSize, (ExecLineHeight - 1),
                            toggleLightEdge, toggleDarkEdge, NULL ORTHOCGOARGVAR);
                draw_button_char(G, x2, y2 + text_lift, 'C' ORTHOCGOARGVAR);
                break;
              case 5:
                {
                  float *button_color = toggleColor2;
                  int spec_level = 0;
                  /* choose color / brightness based on specification level */
                  
                  if(rec->type == cExecAll) {
                    spec_level = MovieGetSpecLevel(G,SceneGetFrame(G));
                  } else if(rec->type == cExecObject) {
                    spec_level = ObjectGetSpecLevel(rec->obj,SceneGetFrame(G));
                  }
                  switch(spec_level) {
                    case 1:
                      button_color = toggleColor3;
                      break;
                    case 2:
                      button_color = activeColor;
                      break;
                  }
                  draw_button(x2, y2, ExecToggleSize, (ExecLineHeight - 1),
                              toggleLightEdge, toggleDarkEdge, button_color ORTHOCGOARGVAR);
                }

                draw_button_char(G, x2, y2 + text_lift, 'M' ORTHOCGOARGVAR);
                break;
              }
              x2 += ExecToggleWidth;
            }
          }
	  /* end ASHLC */
#endif

          {
            int x3 = x;
            int hidden_prefix = false;

            TextSetColor(G, I->Block->TextColor);
            TextSetPos2i(G, x3 + DIP2PIXEL(2), y2 + text_lift);

            if((rec->type == cExecObject) ||
               (rec->type == cExecAll) || (rec->type == cExecSelection)) {

              y2 = y;
              x2 = xx;
              if((x - ExecToggleMargin) - (xx - ExecToggleMargin) > DIP2PIXEL(-10)) {
                x2 = x + DIP2PIXEL(10);
              }
              x3 += panel->nest_level * DIP2PIXEL(8);
              TextSetPos2i(G, x3 + DIP2PIXEL(2), y2 + text_lift);
              nChar -= panel->nest_level;
              {
                int but_width = (x2 - x3) - 1;

		/* drawing a group +/- NAME */
                if(panel->is_group) {
                  const int button_width = DIP2PIXEL(15);
                  if((rec->hilight == 2) && (I->Over == I->Pressed)) {
                    draw_button(x3, y2, button_width, (ExecLineHeight - 1), lightEdge, darkEdge,
                                pressedColor ORTHOCGOARGVAR);
                  } else if(panel->is_open) {
                    draw_button(x3, y2, button_width, (ExecLineHeight - 1), lightEdge, darkEdge,
                                disabledColor ORTHOCGOARGVAR);
                  } else {
                    draw_button(x3, y2, button_width, (ExecLineHeight - 1), lightEdge, darkEdge,
                                disabledColor ORTHOCGOARGVAR);
                  }
                  TextSetPos2i(G, x3 + DIP2PIXEL(4), y2 + text_lift);
                  if(panel->is_open) {
                    TextDrawChar(G, '-' ORTHOCGOARGVAR);
                  } else {
                    TextDrawChar(G, '+' ORTHOCGOARGVAR);
                  }

                  but_width -= DIP2PIXEL(16);
                  x3 += DIP2PIXEL(16);
                  nChar -= 2;

                  TextSetPos2i(G, x3 + DIP2PIXEL(2), y2 + text_lift);
                }

                if((rec->hilight == 1) || ((row == I->Over) && (I->OverWhat == 1))) {
		  /* button hull */
                  draw_button(x3, y2, but_width, (ExecLineHeight - 1), lightEdge,
                              darkEdge, pressedColor ORTHOCGOARGVAR);
                } else if(rec->visible) {
                  int enabled = true;
                  SpecRec *group_rec = rec->group;
                  while(enabled && group_rec) {
                    if(!group_rec->visible)
                      enabled = false;
                    else
                      group_rec = group_rec->group;
                  }

                  if(enabled) {
                    draw_button(x3, y2, but_width, (ExecLineHeight - 1), lightEdge,
                                darkEdge, enabledColor ORTHOCGOARGVAR);
                  } else {
                    draw_button(x3, y2, but_width, (ExecLineHeight - 1), lightEdge,
                                darkEdge, cloakedColor ORTHOCGOARGVAR);
                  }
                } else {
                  draw_button(x3, y2, but_width, (ExecLineHeight - 1), lightEdge,
                              darkEdge, disabledColor ORTHOCGOARGVAR);
                }
              }

              TextSetColor(G, I->Block->TextColor);

	      /* object name */
              c = rec->name;
	      
	      /* parse out the prefix if group.foo */
              if(!full_names) {
                if(rec->group) {        /* if prefix matches group name, then truncate */
                  char *p = c, *q = rec->group->name;
                  while((*p == *q) && (*q)) {
                    p++;
                    q++;
                  }
                  if((*p) && (!*q) && (*p == '.')) {
                    hidden_prefix = true;
                    c = p;
                  }
                }
              }

	      /* wrap selection names with "(" and ")" */
              if(rec->type == cExecSelection)
                if((nChar--) > 0) {
                  TextDrawChar(G, '(' ORTHOCGOARGVAR);
                }
            }

            if(c) {
              if(hidden_prefix) {
		/* ^.name */
                if(arrows && ((nChar--) > 0)) {
                  TextDrawChar(G, '^' ORTHOCGOARGVAR);
                  TextSetPos2i(G, x3 + DIP2PIXEL(2), y2 + text_lift);
                  TextDrawChar(G, '|' ORTHOCGOARGVAR);
                }
              }

	      /* draw the object name, char by char */
              while(*c) {
                if((nChar--) > 0) {
                  TextDrawChar(G, *(c++) ORTHOCGOARGVAR);
		}
                else
                  break;
              }
            }

	    /* SELECTIONS: wrap selection names with "(" and ")" */
            if(rec->type == cExecSelection) {
              if((nChar--) > 0) {
                TextDrawChar(G, ')' ORTHOCGOARGVAR);
              }
              c = rec->name;
            }

	    /* OBJECTS: output any label captions, like state number, state title */
            if(rec->type == cExecObject) {
              if(rec->obj->fGetCaption) {
		/* get this object's "caption" that goes on its title line,
		 * currently, this is "state-title [curState/nState]" */
                c = rec->obj->fGetCaption(rec->obj, ch, WordLength);
	      }
	      /* now print the caption */
              if(c && c[0] && nChar > 1 && strcmp(c, rec->obj->Name) != 0) {
                TextSetColor(G, captionColor);
                TextSetPos2i(G, x + DIP2PIXEL(2) + DIP2PIXEL(8) * (max_char - nChar), y2 + text_lift);
                if((nChar--) > 0)
                  TextDrawChar(G, ' ' ORTHOCGOARGVAR);
                while(*c && nChar > 0) {
		    /* allow color encoding for names */
                  if(TextSetColorFromCode(G, c, captionColor)) {
		      c += 4;
                  } else {
                    TextDrawChar(G, *(c++) ORTHOCGOARGVAR);
                    --nChar;
		  }
                }
              }
            }
          }

          y -= ExecLineHeight;
          if(y < (I->Block->rect.bottom))
            break;
        }
      }
    }
    I->HowFarDown = y;
  }
}


/*========================================================================*/
int ExecutiveIterateObject(PyMOLGlobals * G, CObject ** obj, void **hidden)
{
  SpecRec **rec = (SpecRec **) hidden, *I_Spec = G->Executive->Spec;
  while(ListIterate(I_Spec, (*rec), next)) {
    if((*rec)->type == cExecObject)
      break;
  }
  if(*rec)
    (*obj) = (*rec)->obj;
  else
    (*obj) = NULL;
  return ((*rec) != NULL);
}


/*========================================================================*/
int ExecutiveIterateObjectMolecule(PyMOLGlobals * G, ObjectMolecule ** obj, void **hidden)
{
  SpecRec **rec = (SpecRec **) hidden, *I_Spec = G->Executive->Spec;
  while(ListIterate(I_Spec, (*rec), next)) {
    if(((*rec)->type == cExecObject) && ((*rec)->obj->type == cObjectMolecule))
      break;
  }
  if(*rec)
    (*obj) = (ObjectMolecule *) (*rec)->obj;
  else
    (*obj) = NULL;
  return ((*rec) != NULL);
}


/*========================================================================*/
static void ExecutiveReshape(Block * block, int width, int height)
{
  PyMOLGlobals *G = block->G;
  CExecutive *I = G->Executive;

  BlockReshape(block, width, height);

  I->Width = block->rect.right - block->rect.left + 1;
  I->Height = block->rect.top - block->rect.bottom + 1;

}


/*========================================================================*/
int ExecutiveReinitialize(PyMOLGlobals * G, int what, const char *pattern)
{
  CExecutive *I = G->Executive;
  int ok = true;
#ifndef _PYMOL_NOPY
  int blocked = false;
#endif
  /* reinitialize PyMOL */
  if(what == 2)
    pattern = NULL;

  if(pattern && (!pattern[0]))
    pattern = NULL;
  if(!pattern) {

    switch (what) {
    case 0:                    /* everything */
      ExecutiveDelete(G, cKeywordAll);
      ColorReset(G);
      SettingInitGlobal(G, false, false, true);
      ColorUpdateFrontFromSettings(G);
      MovieReset(G);
      EditorInactivate(G);
      ControlRock(G, 0);
      OrthoReshape(G, -1, -1, false);
      MovieScenesInit(G);

#ifndef _PYMOL_NOPY
      blocked = PAutoBlock(G);
      PRunStringInstance(G, "cmd.view('*','clear')");
      PRunStringInstance(G, "cmd.config_mouse(\"three_button\")");
      WizardSet(G, NULL, false);
      PAutoUnblock(G, blocked);
#endif

      SculptCachePurge(G);
      SceneReinitialize(G);
      SelectorReinit(G);
      SeqChanged(G);
      break;
    case 1:                    /* settings */
      SettingInitGlobal(G, false, false, true);
      ExecutiveRebuildAll(G);
      break;
    case 2:                    /* store_defaults */
      SettingStoreDefault(G);
      break;
    case 3:                    /* original_settings */
      SettingInitGlobal(G, false, false, false);
      ExecutiveRebuildAll(G);
      break;
    case 4:                    /* purge_defaults */
      SettingPurgeDefault(G);
      break;
      /* reinitialize is called with what + 5 to reset internal_gui if necessary (PYMOL-1425) */
    case 5:
    case 6:
      if (G->Default){
	SettingSetGlobal_i(G, cSetting_internal_gui, SettingGet_i(G, G->Default, NULL, cSetting_internal_gui));
	SettingGenerateSideEffects(G, cSetting_internal_gui, NULL, -1, 0);
      }
      break; 
    }
    SceneUpdateStereo(G);
  } else {
    {
      CTracker *I_Tracker = I->Tracker;
      int list_id = ExecutiveGetNamesListFromPattern(G, pattern, true, true);
      int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
      SpecRec *rec;

      while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
        if(rec) {
          switch (rec->type) {
          case cExecObject:
            switch (what) {
            case 0:
            case 1:
              if(rec->obj->Setting) {
                ObjectPurgeSettings(rec->obj);
                if(rec->obj->fInvalidate)
                  rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvAll, -1);
                SceneInvalidate(G);
                SeqChanged(G);
              }
              break;
            }
          }
        }
      }
      TrackerDelList(I_Tracker, list_id);
      TrackerDelIter(I_Tracker, iter_id);
    }

    /* to do */
  }
  return (ok);
}


/*========================================================================*/
int ExecutiveInit(PyMOLGlobals * G)
{
  CExecutive *I = NULL;
  if((I = (G->Executive = Calloc(CExecutive, 1)))) {

    SpecRec *rec = NULL;

    ListInit(I->Spec);
    I->Tracker = TrackerNew(G);
    I->all_names_list_id = TrackerNewList(I->Tracker, NULL);
    I->all_obj_list_id = TrackerNewList(I->Tracker, NULL);
    I->all_sel_list_id = TrackerNewList(I->Tracker, NULL);
    I->Block = OrthoNewBlock(G, NULL);
    I->Block->fRelease = ExecutiveRelease;
    I->Block->fClick = ExecutiveClick;
    I->Block->fDrag = ExecutiveDrag;
    I->Block->fDraw = ExecutiveDraw;
    I->Block->fReshape = ExecutiveReshape;
    I->Block->active = true;
    I->ScrollBarActive = 0;
    I->ScrollBar = ScrollBarNew(G, false);
    OrthoAttach(G, I->Block, cOrthoTool);
    I->RecoverPressed = NULL;
    I->Pressed = -1;
    I->Over = -1;
    I->LastEdited = NULL;
    I->ReorderFlag = false;
    I->NSkip = 0;
    I->HowFarDown = 0;
    I->DragMode = 0;
#ifndef GLUT_FULL_SCREEN
    I->oldWidth = 640;
    I->oldHeight = 480;
#endif
    I->LastZoomed = NULL;
    I->LastChanged = NULL;
    I->ValidGroups = false;
    I->ValidSceneMembers = false;
    I->selIndicatorsCGO = NULL;
    I->selectorTexturePosX = I->selectorTexturePosY = I->selectorTextureSize = I->selectorTextureAllocatedSize = 0;
    I->selectorIsRound = 0;

    ListInit(I->Panel);
    I->ValidPanel = false;

    I->Lex = OVLexicon_New(G->Context->heap);
    I->Key = OVOneToOne_New(G->Context->heap);

    /* create "all" entry */

    ListElemCalloc(G, rec, SpecRec);

    strcpy(rec->name, cKeywordAll);
    rec->type = cExecAll;
    rec->visible = true;
    rec->next = NULL;
    rec->cand_id = TrackerNewCand(I->Tracker, (TrackerRef *) (void *) rec);
    TrackerLink(I->Tracker, rec->cand_id, I->all_names_list_id, 1);
    ListAppend(I->Spec, rec, next, SpecRec);
    ExecutiveAddKey(I, rec);

    return 1;
  } else
    return 0;

}


/*========================================================================*/
void ExecutiveFree(PyMOLGlobals * G)
{
  CExecutive *I = G->Executive;
  SpecRec *rec = NULL;
    CGOFree(I->selIndicatorsCGO);
  while(ListIterate(I->Spec, rec, next)) {
    if(rec->type == cExecObject)
      rec->obj->fFree(rec->obj);
  }
  ListFree(I->Spec, next, SpecRec);
  ListFree(I->Panel, next, PanelRec);
  if(I->Tracker)
    TrackerFree(I->Tracker);
  if(I->ScrollBar)
    ScrollBarFree(I->ScrollBar);
  OrthoFreeBlock(G, I->Block);
  I->Block = NULL;
  OVLexicon_DEL_AUTO_NULL(I->Lex);
  OVOneToOne_DEL_AUTO_NULL(I->Key);

  ExecutiveUniqueIDAtomDictInvalidate(G);

  FreeP(G->Executive);
}

#ifdef _undefined

matrix checking code ...

double mt[3][3], mt2[3][3], pr[3][3], im[3][3], em[3][3];
printf("normalized matrix \n");
for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    printf("%12.3f ", evect[a][b]);
  }
  printf("\n");
}

printf("\n");

printf("tensor \n");
for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    printf("%12.3f ", mi[a][b]);
  }
  printf("\n");
}

printf("\n");

for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    mt[a][b] = evect[a][b];
  }
}

for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    mt2[a][b] = evect[b][a];
  }
}

matrix_multiply33d33d(mt, mt2, pr);
printf("self product 1 \n");
for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    printf("%8.3f ", pr[a][b]);
  }
  printf("\n");
}

printf("\n");

matrix_multiply33d33d(mt, mi, im);
matrix_multiply33d33d(im, mt2, pr);
printf("diagonal product 1 \n");
for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    printf("%8.3f ", pr[a][b]);
  }
  printf("\n");
}

printf("\n");

for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    em[a][b] = 0.0;
  }
  em[a][a] = egval[a];
}

matrix_multiply33d33d(mt2, em, im);
matrix_multiply33d33d(im, mt, pr);
printf("diagonal product 4 \n");
for(a = 0; a < 3; a++) {
  for(b = 0; b < 3; b++) {
    printf("%8.3f ", pr[a][b]);
  }
  printf("\n");
}

printf("\n");
#endif

PyObject * ExecutiveCEAlign(PyMOLGlobals * G, PyObject * listA, PyObject * listB, int lenA, int lenB, float d0, float d1, int windowSize, int gapMax) {
#ifdef _PYMOL_NOPY
  return NULL;
#else
  int i=0;
  int smaller;
  double **dmA ,**dmB, **S;
  int bufferSize;
  pcePoint coordsA, coordsB;
  pathCache paths = NULL;
  PyObject * result;

  smaller = lenA < lenB ? lenA : lenB;
	
  /* get the coodinates from the Python objects */
  coordsA = (pcePoint) getCoords(listA, lenA);
  coordsB = (pcePoint) getCoords(listB, lenB);
	
  /* calculate the distance matrix for each protein */
  dmA = (double**) calcDM(coordsA, lenA);
  dmB = (double**) calcDM(coordsB, lenB);
	
  /* calculate the CE Similarity matrix */
  S = (double**) calcS(dmA, dmB, lenA, lenB, windowSize);
	
  /* find the best path through the CE Sim. matrix */
  bufferSize = 0;

  /* the following line HANGS PyMOL */
  paths = (pathCache) findPath(S, dmA, dmB, lenA, lenB, d0, d1, windowSize, gapMax, &bufferSize);
	
  /* Get the optimal superposition here... */
  result = (PyObject*) findBest(coordsA, coordsB, paths, bufferSize, smaller, windowSize);
	
  /* release memory */
  free(coordsA);
  free(coordsB);
  for ( i = 0; i < bufferSize; ++i )
    free(paths[i]);
  free(paths);
	
  /* distance matrices	 */
  for ( i = 0; i < lenA; i++ )
    free( dmA[i] );
  free(dmA);
	
  for  ( i = 0; i < lenB; i++ )
    free( dmB[i] );
  free(dmB);
	
  /* similarity matrix */
  for ( i = 0; i < lenA; i++ )
    free( S[i] );
  free(S);
	
  return (PyObject*) result;
#endif
}

char *ExecutiveGetObjectNames(PyMOLGlobals * G, int mode, const char *name, int enabled_only, int *numstrs){
  char *res;
  int size=0, stlen;
  CExecutive *I = G->Executive;
  CTracker *I_Tracker = I->Tracker;
  *numstrs = 0;
  {
    int list_id = ExecutiveGetNamesListFromPattern(G, name, true, true);
    int iter_id = TrackerNewIter(I_Tracker, 0, list_id);
    SpecRec *rec;
    res = VLAlloc(char, 1000);
    while(TrackerIterNextCandInList(I_Tracker, iter_id, (TrackerRef **) (void *) &rec)) {
      if((rec->type == cExecObject
	  && (((!mode) || (mode == cObjectTypeObjects) || (mode == cObjectTypePublic) || (mode == cObjectTypePublicObjects))
	      || ((rec->obj->type != cObjectGroup) && ((mode == cObjectTypePublicNonGroupObjects) || (mode == cObjectTypeNonGroupObjects)))
	      || ((rec->obj->type == cObjectGroup) && ((mode == cObjectTypePublicGroupObjects) || (mode == cObjectTypeGroupObjects)))))
	 || (rec->type == cExecSelection
	     && ((!mode) || (mode == cObjectTypeSelections) || (mode == cObjectTypePublic) || (mode == cObjectTypePublicSelections)))
	 ) {
	if((mode < 3) || (mode > 7) || (mode == cObjectTypeGroupObjects) || (rec->name[0] != '_')) {
	  if((!enabled_only) || (rec->visible)) {
	    stlen = strlen(rec->name);	    
            VLACheck(res, char, size + stlen + 1);
            strcpy(res + size, rec->name);
            size += stlen + 1;
	    *numstrs += 1;
	  }
	}
      }
    }
  }
  if (!size){
    VLAFreeP(res);
    res = NULL;
  } else {
    VLASize(res, char, size);
  }
  return (res);
}

/*
 * Get the coord set for the given object name and state index. If "omp" is
 * not NULL, then also store a pointer to the object molecule.
 */
CoordSet * ExecutiveGetCoordSet(PyMOLGlobals * G, const char * name, int state, ObjectMolecule ** omp) {
  CObject * obj;
  ObjectMolecule * om = NULL;
  CoordSet * cs = NULL;

  ok_assert(1, obj = ExecutiveFindObjectByName(G, (char*) name));
  ok_assert(1, obj->type == cObjectMolecule);

  om = (ObjectMolecule*) obj;
  ok_assert(1, cs = ObjectMoleculeGetCoordSet(om, state));

ok_except1:
  if (omp != NULL)
    *omp = om;
  return cs;
}

void ExecutiveUniqueIDAtomDictInvalidate(PyMOLGlobals * G) {
  CExecutive *I = G->Executive;
  if (I->m_eoo) {
    OVOneToOne_DEL_AUTO_NULL(I->m_id2eoo);
    VLAFreeP(I->m_eoo);
  }
}

const ExecutiveObjectOffset * ExecutiveUniqueIDAtomDictGet(PyMOLGlobals * G, int i) {
  CExecutive *I = G->Executive;
  OVreturn_word offset;

  if (!I->m_eoo)
    ExecutiveGetUniqueIDAtomVLADict(G, &I->m_eoo, &I->m_id2eoo);

  if(!OVreturn_IS_OK(offset = OVOneToOne_GetForward(I->m_id2eoo, i)))
    return NULL;

  return I->m_eoo + offset.word;
}
