1 
2 /*
3    A* -------------------------------------------------------------------
4    B* This file contains source code for the PyMOL computer program
5    C* Copyright (c) Schrodinger, LLC.
6    D* -------------------------------------------------------------------
7    E* It is unlawful to modify or remove this copyright notice.
8    F* -------------------------------------------------------------------
9    G* Please see the accompanying LICENSE file for further information.
10    H* -------------------------------------------------------------------
11    I* Additional authors of this source file include:
12    -*
13    -*
14    -*
15    Z* -------------------------------------------------------------------
16 */
17 #include"os_python.h"
18 #include "os_std.h"
19 #include "os_gl.h"
20 
21 #include <clocale>
22 
23 #include "MemoryDebug.h"
24 
25 #include "Base.h"
26 
27 #include "OVContext.h"
28 
29 #include "MemoryDebug.h"
30 #include "Err.h"
31 #include "Util.h"
32 #include "Selector.h"
33 #include "Color.h"
34 #include "Ortho.h"
35 #include "Scene.h"
36 #include "PyMOLObject.h"
37 #include "Executive.h"
38 #include "Word.h"
39 #include "RepMesh.h"
40 #include "ObjectMolecule.h"
41 #include "Control.h"
42 #include "Sphere.h"
43 #include "Setting.h"
44 #include "Ray.h"
45 #include "Util.h"
46 #include "Movie.h"
47 #include "P.h"
48 #include "Editor.h"
49 #include "SculptCache.h"
50 #include "Isosurf.h"
51 #include "Tetsurf.h"
52 #include "PConv.h"
53 #include "VFont.h"
54 #include "Wizard.h"
55 #include "Text.h"
56 #include "Character.h"
57 #include "Seq.h"
58 #include "Seeker.h"
59 #include "Texture.h"
60 #include "TestPyMOL.h"
61 #include "TypeFace.h"
62 #include "PlugIOManager.h"
63 #include "MovieScene.h"
64 #include "Lex.h"
65 #include "SelectorDef.h"
66 
67 #ifdef _PYMOL_OPENVR
68 #include "OpenVRMode.h"
69 #endif
70 
71 #include "PyMOL.h"
72 #include "PyMOLGlobals.h"
73 #include "PyMOLOptions.h"
74 #include "Feedback.h"
75 #include "GraphicsUtil.h"
76 #include "pymol/zstring_view.h"
77 
78 #include "ShaderMgr.h"
79 #include "Version.h"
80 
81 #ifndef _PYMOL_NOPY
82 PyMOLGlobals *SingletonPyMOLGlobals = NULL;
83 #endif
84 
85 #ifdef _PYMOL_LIB_HAS_PYTHON
86 #define PYMOL_API_LOCK if(I->PythonInitStage && (!I->ModalDraw)) { PLockAPIAndUnblock(I->G); {
87 #define PYMOL_API_LOCK_MODAL if(I->PythonInitStage) { PLockAPIAndUnblock(I->G); {
88 #define PYMOL_API_TRYLOCK if(I->PythonInitStage && (!I->ModalDraw)) { if(PTryLockAPIAndUnblock(I->G)) {
89 #define PYMOL_API_UNLOCK PBlockAndUnlockAPI(I->G); }}
90 #define PYMOL_API_UNLOCK_NO_FLUSH PBlockAndUnlockAPI(I->G); }}
91 #else
92 #define PYMOL_API_LOCK if(!I->ModalDraw) {
93 #define PYMOL_API_LOCK_MODAL {
94 #define PYMOL_API_TRYLOCK if(!I->ModalDraw) {
95 #define PYMOL_API_UNLOCK }
96 #define PYMOL_API_UNLOCK_NO_FLUSH }
97 #endif
98 #define IDLE_AND_READY 3
99 
100 typedef struct _CPyMOL {
101   PyMOLGlobals *G;
102   int FakeDragFlag;
103   int RedisplayFlag;
104   int PassiveFlag;
105   int SwapFlag;
106   int BusyFlag;
107   int InterruptFlag;
108   int ReshapeFlag;
109   int ClickReadyFlag;
110   int DrawnFlag;
111   ObjectNameType ClickedObject;
112   int ClickedIndex, ClickedButton, ClickedModifiers, ClickedX, ClickedY, ClickedHavePos, ClickedPosState;
113   float ClickedPos[3];
114   int ImageRequestedFlag, ImageReadyFlag;
115   int DraggedFlag;
116   int Reshape[PYMOL_RESHAPE_SIZE];
117   int Progress[PYMOL_PROGRESS_SIZE];
118   int ProgressChanged;
119   int IdleAndReady;
120   int ExpireCount;
121   bool done_ConfigureShaders;
122 
123   PyMOLModalDrawFn *ModalDraw;
124 
125   PyMOLSwapBuffersFn *SwapFn;
126 
127 
128 /* Python stuff */
129 #ifndef _PYMOL_NOPY
130   int PythonInitStage;
131 #endif
132   /* dynamically mapped string constants */
133 
134   OVLexicon *Lex;
135   OVOneToOne *Rep;
136   ov_word lex_everything, lex_sticks, lex_spheres, lex_surface;
137   ov_word lex_labels, lex_nb_spheres, lex_cartoon, lex_ribbon;
138   ov_word lex_lines, lex_mesh, lex_dots, lex_dashes, lex_nonbonded;
139   ov_word lex_cell, lex_cgo, lex_callback, lex_extent, lex_slice;
140 
141   OVOneToOne *Clip;
142   ov_word lex_near, lex_far, lex_move, lex_slab, lex_atoms;
143 
144   OVOneToOne *Reinit;
145   ov_word lex_settings;
146 
147   OVOneToOne *SelectList;
148   ov_word lex_index, lex_id, lex_rank;
149 
150   OVOneToOne *Setting;
151 
152 #ifdef _PYMOL_LIB
153   OVOneToOne *MouseButtonCodeLexicon;
154   ov_word lex_left, lex_middle, lex_right;
155   ov_word lex_wheel;
156   ov_word lex_double_left, lex_double_middle, lex_double_right;
157   ov_word lex_single_left, lex_single_middle, lex_single_right;
158 
159   OVOneToOne *MouseButtonModCodeLexicon;
160   ov_word lex_none, lex_shft, lex_ctrl, lex_ctsh;
161   ov_word lex_alt, lex_alsh, lex_ctal, lex_ctas;
162 
163   OVOneToOne *MouseButtonActionCodeLexicon;
164   ov_word lex_but_rota, lex_but_move, lex_but_movz, lex_but_clip, lex_but_rotz;
165   ov_word lex_but_clpn, lex_but_clpf, lex_but_lb, lex_but_mb, lex_but_rb;
166   ov_word lex_but_plus_lb, lex_but_plus_mb, lex_but_plus_rb, lex_but_pkat, lex_but_pkbd;
167   ov_word lex_but_rotf, lex_but_torf, lex_but_movf, lex_but_orig, lex_but_plus_lbx;
168   ov_word lex_but_minus_lbx, lex_but_lbbx, lex_but_none, lex_but_cent, lex_but_pktb;
169   ov_word lex_but_slab, lex_but_movs, lex_but_pk1;
170   ov_word lex_but_mova, lex_but_menu, lex_but_sele, lex_but_plus_minus;
171   ov_word lex_but_plus_box, lex_but_minus_box, lex_but_mvsz, lex_but_dgrt, lex_but_dgmv;
172   ov_word lex_but_dgmz, lex_but_roto, lex_but_movo, lex_but_mvoz, lex_but_mvfz;
173   ov_word lex_but_mvaz, lex_but_drgm, lex_but_rotv, lex_but_movv, lex_but_mvvz;
174   ov_word lex_but_drgo, lex_but_imsz, lex_but_imvz, lex_but_box, lex_but_irtz;
175 
176   OVOneToOne *MouseModeLexicon;
177 #include "buttonmodes_lex_def.h"
178 
179   OVOneToOne *PaletteLexicon;
180 #include "palettes_lex_def.h"
181 
182 #endif
183 
184   AtomPropertyInfo AtomPropertyInfos[NUM_ATOM_PROPERTIES];
185   OVOneToOne *AtomPropertyLexicon;
186   ov_word lex_atom_prop_model, lex_atom_prop_index, lex_atom_prop_type,
187     lex_atom_prop_name, lex_atom_prop_resn, lex_atom_prop_resi,
188     lex_atom_prop_resv, lex_atom_prop_chain, lex_atom_prop_alt,
189     lex_atom_prop_segi, lex_atom_prop_elem,
190     lex_atom_prop_ss, lex_atom_prop_text_type,
191     lex_atom_prop_custom, lex_atom_prop_label, lex_atom_prop_numeric_type,
192     lex_atom_prop_q, lex_atom_prop_b, lex_atom_prop_vdw,
193     lex_atom_prop_elec_radius, lex_atom_prop_partial_charge, lex_atom_prop_formal_charge,
194     lex_atom_prop_stereo, lex_atom_prop_cartoon, lex_atom_prop_color,
195     lex_atom_prop_ID, lex_atom_prop_rank, lex_atom_prop_flags,
196     lex_atom_prop_geom, lex_atom_prop_valence,
197     lex_atom_prop_x, lex_atom_prop_y, lex_atom_prop_z,
198     lex_atom_prop_settings, lex_atom_prop_properties,
199     lex_atom_prop_reps,
200     lex_atom_prop_protons,
201     lex_atom_prop_oneletter,
202     lex_atom_prop_s, lex_atom_prop_p, lex_atom_prop_state;
203   /*
204     lex_atom_prop_, lex_atom_prop_, lex_atom_prop_,
205     lex_atom_prop_, lex_atom_prop_, lex_atom_prop_,*/
206 
207 } _CPyMOL;
208 
209 
210 /* convenience functions -- inline */
211 
get_status_ok(int ok)212 inline PyMOLstatus get_status_ok(int ok)
213 {
214   if(ok)
215     return PyMOLstatus_SUCCESS;
216   else
217     return PyMOLstatus_FAILURE;
218 }
219 
return_status_ok(int ok)220 inline PyMOLreturn_status return_status_ok(int ok)
221 {
222   PyMOLreturn_status result;
223   result.status = get_status_ok(ok);
224   return result;
225 }
226 
return_status(int status)227 inline PyMOLreturn_status return_status(int status)
228 {
229   PyMOLreturn_status result;
230   result.status = status;
231   return result;
232 }
233 
return_result(const pymol::Result<float> & res)234 inline PyMOLreturn_float return_result(const pymol::Result<float>& res)
235 {
236   PyMOLreturn_float result = {PyMOLstatus_FAILURE};
237   if (res) {
238     result.status = PyMOLstatus_SUCCESS;
239     result.value = res.result();
240   }
241   return result;
242 }
243 
return_result(const pymol::Result<std::vector<const char * >> & res)244 static PyMOLreturn_string_array return_result(
245     const pymol::Result<std::vector<const char*>>& res)
246 {
247   PyMOLreturn_string_array result = {
248       PyMOLstatus_SUCCESS, 0, nullptr};
249   if (!res) {
250     result.status = PyMOLstatus_FAILURE;
251   } else if (!res.result().empty()) {
252     const auto& vec = res.result();
253     result.size = vec.size();
254     result.array = VLAlloc(char*, result.size);
255 
256     // allocate space for concatenated string in first array element
257     size_t reslen = 0;
258     for (const char* s : vec) {
259       reslen += strlen(s) + 1;
260     }
261     result.array[0] = VLAlloc(char, reslen);
262 
263     // copy elements
264     for (size_t pl = 0, i = 0; i != vec.size(); ++i) {
265       result.array[i] = result.array[0] + pl;
266       strcpy(result.array[i], vec[i]);
267       pl += strlen(vec[i]) + 1;
268     }
269   }
270   return result;
271 }
272 
273 #if defined(__cplusplus) && !defined(_WEBGL)
274 extern "C" {
275 #endif
276 
277 #ifdef _PYMOL_LIB
278 int initial_button_modes[cButModeInputCount];
279 #endif
280 
PyMOL_InitAPI(CPyMOL * I)281 static OVstatus PyMOL_InitAPI(CPyMOL * I)
282 {
283   OVContext *C = I->G->Context;
284   OVreturn_word result;
285   I->Lex = OVLexicon_New(C->heap);
286   if(!I->Lex)
287     return_OVstatus_FAILURE;
288 
289   /* the following preprocessor macros may require GNU's cpp or VC++
290      we'll see... */
291 
292 #define LEX(ARG)  \
293   if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,#ARG))))  \
294     return_OVstatus_FAILURE \
295     else \
296       I -> lex_ ## ARG = result.word;
297 
298   /* string constants that are accepted on input */
299 
300 #define LEX_REP(NAME,CODE) LEX(NAME) \
301     if(!OVreturn_IS_OK( OVOneToOne_Set(I->Rep,I->lex_ ## NAME, CODE)))  \
302       return_OVstatus_FAILURE;
303 
304   I->Rep = OVOneToOne_New(C->heap);
305   if(!I->Rep)
306     return_OVstatus_FAILURE;
307 
308   LEX_REP(everything, -1);
309   LEX_REP(sticks, 0);
310   LEX_REP(spheres, 1);
311   LEX_REP(surface, 2);
312   LEX_REP(labels, 3);
313   LEX_REP(nb_spheres, 4);
314   LEX_REP(cartoon, 5);
315   LEX_REP(ribbon, 6);
316   LEX_REP(lines, 7);
317   LEX_REP(mesh, 8);
318   LEX_REP(dots, 9);
319   LEX_REP(dashes, 10);
320   LEX_REP(nonbonded, 11);
321   LEX_REP(cell, 12);
322   LEX_REP(cgo, 13);
323   LEX_REP(callback, 14);
324   LEX_REP(extent, 15);
325   LEX_REP(slice, 16);
326 
327   /* workaround for unexplained bug with nested macro on VC6 */
328 
329 #define LEX_CLIP(NAME,CODE) {if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,#NAME))))  \
330     return_OVstatus_FAILURE \
331     else \
332     I -> lex_ ## NAME = result.word;} \
333     if(!OVreturn_IS_OK( OVOneToOne_Set(I->Clip,I->lex_ ## NAME, CODE)))  \
334       return_OVstatus_FAILURE;
335 
336   I->Clip = OVOneToOne_New(C->heap);
337   if(!I->Clip)
338     return_OVstatus_FAILURE;
339 
340   LEX_CLIP(near, 0);
341   LEX_CLIP(far, 1);
342   LEX_CLIP(move, 2);
343   LEX_CLIP(slab, 3);
344   LEX_CLIP(atoms, 4);
345 
346 #define LEX_REINIT(NAME,CODE) {if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,#NAME))))  \
347     return_OVstatus_FAILURE \
348     else \
349     I -> lex_ ## NAME = result.word;} \
350     if(!OVreturn_IS_OK( OVOneToOne_Set(I->Reinit,I->lex_ ## NAME, CODE)))  \
351       return_OVstatus_FAILURE;
352 
353   I->Reinit = OVOneToOne_New(C->heap);
354   if(!I->Reinit)
355     return_OVstatus_FAILURE;
356 
357   LEX_REINIT(everything, 0);
358   LEX_REINIT(settings, 1);
359 
360 #define LEX_SELLIST(NAME,CODE) {if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,#NAME))))  \
361     return_OVstatus_FAILURE \
362     else \
363     I -> lex_ ## NAME = result.word;} \
364     if(!OVreturn_IS_OK( OVOneToOne_Set(I->SelectList,I->lex_ ## NAME, CODE)))  \
365       return_OVstatus_FAILURE;
366 
367   I->SelectList = OVOneToOne_New(C->heap);
368   if(!I->SelectList)
369     return_OVstatus_FAILURE;
370 
371   LEX_SELLIST(index, 0);
372   LEX_SELLIST(id, 1);
373   LEX_SELLIST(rank, 2);
374 
375   I->Setting = OVOneToOne_New(C->heap);
376   if(!I->Setting)
377     return_OVstatus_FAILURE;
378 
379   if(!CPyMOLInitSetting(I->Lex, I->Setting))
380     return_OVstatus_FAILURE;
381 
382 #ifdef _PYMOL_LIB
383 
384   I->MouseButtonCodeLexicon = OVOneToOne_New(C->heap);
385   if(!I->MouseButtonCodeLexicon)
386     return_OVstatus_FAILURE;
387 
388 #define LEX_MOUSECODE(NAME,CODE) LEX(NAME) \
389     if(!OVreturn_IS_OK( OVOneToOne_Set(I->MouseButtonCodeLexicon,I->lex_ ## NAME, CODE)))  \
390       return_OVstatus_FAILURE;
391 
392   LEX_MOUSECODE(left, 0);
393   LEX_MOUSECODE(middle, 1);
394   LEX_MOUSECODE(right, 2);
395   LEX_MOUSECODE(wheel, 3);
396   LEX_MOUSECODE(double_left, 4);
397   LEX_MOUSECODE(double_middle, 5);
398   LEX_MOUSECODE(double_right, 6);
399   LEX_MOUSECODE(single_left, 7);
400   LEX_MOUSECODE(single_middle, 8);
401   LEX_MOUSECODE(single_right, 9);
402 
403   I->MouseButtonModCodeLexicon = OVOneToOne_New(C->heap);
404   if(!I->MouseButtonModCodeLexicon)
405     return_OVstatus_FAILURE;
406 
407 #define LEX_BUTTONMODCODE(NAME,CODE) LEX(NAME) \
408     if(!OVreturn_IS_OK( OVOneToOne_Set(I->MouseButtonModCodeLexicon,I->lex_ ## NAME, CODE)))  \
409       return_OVstatus_FAILURE;
410 
411   LEX_BUTTONMODCODE(none, 0);
412   LEX_BUTTONMODCODE(shft, 1);
413   LEX_BUTTONMODCODE(ctrl, 2);
414   LEX_BUTTONMODCODE(ctsh, 3);
415   LEX_BUTTONMODCODE(alt, 4);
416   LEX_BUTTONMODCODE(alsh, 5);
417   LEX_BUTTONMODCODE(ctal, 6);
418   LEX_BUTTONMODCODE(ctas, 7);
419 
420   I->MouseButtonActionCodeLexicon = OVOneToOne_New(C->heap);
421   if(!I->MouseButtonActionCodeLexicon)
422     return_OVstatus_FAILURE;
423 
424 #define LEX_BUT(ARG)  \
425   if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,#ARG))))  \
426     return_OVstatus_FAILURE \
427     else \
428       I -> lex_but_ ## ARG = result.word;
429 
430 #define LEX_BUTTONACTIONCODE(NAME,CODE) LEX_BUT(NAME) \
431     if(!OVreturn_IS_OK( OVOneToOne_Set(I->MouseButtonActionCodeLexicon,I->lex_but_ ## NAME, CODE)))  \
432       return_OVstatus_FAILURE;
433 #define LEX_BUTTONACTIONCODEWITHSTRING(NAME,STRARG,CODE) \
434   if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,STRARG))))  \
435     return_OVstatus_FAILURE \
436     else \
437       I -> lex_but_ ## NAME = result.word; \
438   if(!OVreturn_IS_OK( OVOneToOne_Set(I->MouseButtonActionCodeLexicon,I->lex_but_ ## NAME, CODE)))  \
439     return_OVstatus_FAILURE;
440 
441 
442   LEX_BUTTONACTIONCODE(rota, 0);
443   LEX_BUTTONACTIONCODE(move, 1);
444   LEX_BUTTONACTIONCODE(movz, 2);
445   LEX_BUTTONACTIONCODE(clip, 3);
446   LEX_BUTTONACTIONCODE(rotz, 4);
447   LEX_BUTTONACTIONCODE(clpn, 5);
448   LEX_BUTTONACTIONCODE(clpf, 6);
449   LEX_BUTTONACTIONCODE(lb, 7);
450   LEX_BUTTONACTIONCODE(mb, 8);
451   LEX_BUTTONACTIONCODE(rb, 9);
452   LEX_BUTTONACTIONCODEWITHSTRING(plus_lb, "+lb", 10);
453   LEX_BUTTONACTIONCODEWITHSTRING(plus_mb, "+mb", 11);
454   LEX_BUTTONACTIONCODEWITHSTRING(plus_rb, "+rb", 12);
455   LEX_BUTTONACTIONCODE(pkat, 13);
456   LEX_BUTTONACTIONCODE(pkbd, 14);
457   LEX_BUTTONACTIONCODE(rotf, 15);
458   LEX_BUTTONACTIONCODE(torf, 16);
459   LEX_BUTTONACTIONCODE(movf, 17);
460   LEX_BUTTONACTIONCODE(orig, 18);
461   LEX_BUTTONACTIONCODEWITHSTRING(plus_lbx, "+lbx", 19);
462   LEX_BUTTONACTIONCODEWITHSTRING(minus_lbx, "-lbx", 20);
463   LEX_BUTTONACTIONCODE(lbbx, 21);
464   LEX_BUTTONACTIONCODE(none, 22);
465   LEX_BUTTONACTIONCODE(cent, 23);
466   LEX_BUTTONACTIONCODE(pktb, 24);
467   LEX_BUTTONACTIONCODE(slab, 25);
468   LEX_BUTTONACTIONCODE(movs, 26);
469   LEX_BUTTONACTIONCODE(pk1, 27);
470   LEX_BUTTONACTIONCODE(mova, 28);
471   LEX_BUTTONACTIONCODE(menu, 29);
472   LEX_BUTTONACTIONCODE(sele, 30);
473   LEX_BUTTONACTIONCODEWITHSTRING(plus_minus,"+/-", 31);
474   LEX_BUTTONACTIONCODEWITHSTRING(plus_box, "+box", 32);
475   LEX_BUTTONACTIONCODEWITHSTRING(minus_box, "-box", 33);
476   LEX_BUTTONACTIONCODE(mvsz, 34);
477   LEX_BUTTONACTIONCODE(dgrt, 36);
478   LEX_BUTTONACTIONCODE(dgmv, 37);
479   LEX_BUTTONACTIONCODE(dgmz, 38);
480   LEX_BUTTONACTIONCODE(roto, 39);
481   LEX_BUTTONACTIONCODE(movo, 40);
482   LEX_BUTTONACTIONCODE(mvoz, 41);
483   LEX_BUTTONACTIONCODE(mvfz, 42);
484   LEX_BUTTONACTIONCODE(mvaz, 43);
485   LEX_BUTTONACTIONCODE(drgm, 44);
486   LEX_BUTTONACTIONCODE(rotv, 45);
487   LEX_BUTTONACTIONCODE(movv, 46);
488   LEX_BUTTONACTIONCODE(mvvz, 47);
489   LEX_BUTTONACTIONCODE(drgo, 49);
490   LEX_BUTTONACTIONCODE(imsz, 50);
491   LEX_BUTTONACTIONCODE(imvz, 51);
492   LEX_BUTTONACTIONCODE(box, 52);
493   LEX_BUTTONACTIONCODE(irtz, 53);
494 
495   I->MouseModeLexicon = OVOneToOne_New(C->heap);
496   if(!I->MouseModeLexicon)
497     return_OVstatus_FAILURE;
498 
499 #define LEX_MOUSEMODECODE(NAME,CODE) LEX(NAME) \
500     if(!OVreturn_IS_OK( OVOneToOne_Set(I->MouseModeLexicon,I->lex_ ## NAME, CODE)))  \
501       return_OVstatus_FAILURE;
502 
503 #include "buttonmodes_lex_init.h"
504 
505   {
506     int a;
507     /* These are set by default for the modes, basically, any single or double
508        click is a simple click (i.e., cButModeSimpleClick), mouse button
509        actions are initialized to a potential click, wheel actions are set to none.
510        This is very similar to what is done in PyMOL_SetMouseButtonMode(),
511        and it makes it easier to specify new modes without needing to set
512        every mouse function */
513     for(a = cButModeLeftDouble /* 16 */; a <= cButModeRightCtrlAltShftSingle /* 63 */; a++) {
514       /* all single and double clicks */
515       initial_button_modes[a] = cButModeSimpleClick;
516     }
517     for(a = cButModeLeftAlt /* 68 */; a <= cButModeRightCtrlAltShft /* 79 */; a++) {
518       /* all button modes with Alt */
519       initial_button_modes[a] = cButModePotentialClick;
520     }
521     for(a = cButModeLeftNone /* 0 */; a <= cButModeRightCtSh /* 11 */; a++) {
522       /* all button modes without Alt */
523       initial_button_modes[a] = cButModePotentialClick;
524     }
525     for(a = cButModeWheelNone /* 12 */; a <= cButModeWheelCtSh /* 15 */; a++) {
526       initial_button_modes[a] = cButModeNone;
527     }
528     for(a = cButModeWheelAlt /* 64 */; a <= cButModeWheelCtrlAltShft /* 67 */; a++) {
529       initial_button_modes[a] = cButModeNone;
530     }
531   }
532 
533   I->PaletteLexicon = OVOneToOne_New(C->heap);
534   if(!I->PaletteLexicon)
535     return_OVstatus_FAILURE;
536 
537 #define LEX_PALETTE(NAME,CODE) LEX(NAME) \
538     if(!OVreturn_IS_OK( OVOneToOne_Set(I->PaletteLexicon,I->lex_ ## NAME, CODE)))  \
539       return_OVstatus_FAILURE;
540 
541 #include "palettes_lex_init.h"
542 
543 #endif
544 
545 
546   I->AtomPropertyLexicon = OVOneToOne_New(C->heap);
547   if(!I->AtomPropertyLexicon)
548     return_OVstatus_FAILURE;
549 
550 #define LEX_ATM_PROP(ARG)  \
551   if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->Lex,#ARG))))  \
552     return_OVstatus_FAILURE \
553     else \
554       I -> lex_atom_prop_ ## ARG = result.word;
555 #define LEX_ATOM_PROP(NAME,CODE,TYPE,OFFSET) LEX_ATM_PROP(NAME)		\
556     if(!OVreturn_IS_OK( OVOneToOne_Set(I->AtomPropertyLexicon,I->lex_atom_prop_ ## NAME, CODE)))  \
557       return_OVstatus_FAILURE;     \
558     I->AtomPropertyInfos[CODE].id = CODE;    \
559     I->AtomPropertyInfos[CODE].Ptype = TYPE;    \
560     I->AtomPropertyInfos[CODE].offset = OFFSET;  \
561     I->AtomPropertyInfos[CODE].maxlen = 0;
562 
563 #define LEX_ATOM_PROP_S(NAME,CODE,TYPE,OFFSET,MAXLEN) LEX_ATM_PROP(NAME)	\
564     if(!OVreturn_IS_OK( OVOneToOne_Set(I->AtomPropertyLexicon,I->lex_atom_prop_ ## NAME, CODE)))  \
565       return_OVstatus_FAILURE;     \
566     I->AtomPropertyInfos[CODE].id = CODE;    \
567     I->AtomPropertyInfos[CODE].Ptype = TYPE;    \
568     I->AtomPropertyInfos[CODE].offset = OFFSET;  \
569     I->AtomPropertyInfos[CODE].maxlen = MAXLEN;
570 
571   /*TEMP*/
572   LEX_ATOM_PROP(model, 0, cPType_model, 0);
573   LEX_ATOM_PROP(index, 1, cPType_index, 0);
574   LEX_ATOM_PROP(type, 2, cPType_char_as_type, 0);
575   LEX_ATOM_PROP(name, 3, cPType_int_as_string, offsetof(AtomInfoType,name));
576   LEX_ATOM_PROP(resn, 4, cPType_int_as_string, offsetof(AtomInfoType,resn));
577   LEX_ATOM_PROP(resi, 5, 0, 0);
578   LEX_ATOM_PROP(resv, 6, cPType_int, offsetof(AtomInfoType,resv));
579   LEX_ATOM_PROP(chain, 7, cPType_int_as_string, offsetof(AtomInfoType,chain));
580   LEX_ATOM_PROP_S(alt, 8, cPType_string, offsetof(AtomInfoType,alt), 1);
581   LEX_ATOM_PROP(segi, 9, cPType_int_as_string, offsetof(AtomInfoType,segi));
582   LEX_ATOM_PROP_S(elem, 10, cPType_string, offsetof(AtomInfoType,elem), cElemNameLen);
583   LEX_ATOM_PROP_S(ss, 11, cPType_string, offsetof(AtomInfoType,ssType), 1);
584   LEX_ATOM_PROP(text_type, 12, cPType_int_as_string, offsetof(AtomInfoType,textType));
585   LEX_ATOM_PROP(custom, 13, cPType_int_as_string, offsetof(AtomInfoType,custom));
586   LEX_ATOM_PROP(label, 14, cPType_int_as_string, offsetof(AtomInfoType,label));
587   LEX_ATOM_PROP(numeric_type, 15, cPType_int_custom_type, offsetof(AtomInfoType,customType));
588   LEX_ATOM_PROP(q, 16, cPType_float, offsetof(AtomInfoType,q));
589   LEX_ATOM_PROP(b, 17, cPType_float, offsetof(AtomInfoType,b));
590   LEX_ATOM_PROP(vdw, 18, cPType_float, offsetof(AtomInfoType,vdw));
591   LEX_ATOM_PROP(elec_radius, 19, cPType_float, offsetof(AtomInfoType,elec_radius));
592   LEX_ATOM_PROP(partial_charge, 20, cPType_float, offsetof(AtomInfoType,partialCharge));
593   LEX_ATOM_PROP(formal_charge, 21, cPType_schar, offsetof(AtomInfoType,formalCharge));
594   LEX_ATOM_PROP(stereo, 22, 0, 0);
595   LEX_ATOM_PROP(cartoon, 23, cPType_schar, offsetof(AtomInfoType,cartoon));
596   LEX_ATOM_PROP(color, 24, cPType_int, offsetof(AtomInfoType,color));
597   LEX_ATOM_PROP(ID, 25, cPType_int, offsetof(AtomInfoType,id));
598   LEX_ATOM_PROP(rank, 26, cPType_int, offsetof(AtomInfoType,rank));
599   LEX_ATOM_PROP(flags, 27, cPType_int, offsetof(AtomInfoType,flags));
600   LEX_ATOM_PROP(geom, 28, cPType_schar, offsetof(AtomInfoType,geom));
601   LEX_ATOM_PROP(valence, 29, cPType_schar, offsetof(AtomInfoType,valence));
602   LEX_ATOM_PROP(x, 30, cPType_xyz_float, 0);
603   LEX_ATOM_PROP(y, 31, cPType_xyz_float, 1);
604   LEX_ATOM_PROP(z, 32, cPType_xyz_float, 2);
605   LEX_ATOM_PROP(settings, 33, cPType_settings, 0);
606   LEX_ATOM_PROP(properties, 34, cPType_properties, 0);
607   LEX_ATOM_PROP(s, 35, cPType_settings, 0);
608   LEX_ATOM_PROP(p, 36, cPType_properties, 0);
609   LEX_ATOM_PROP(state, 37, cPType_state, 0);
610   LEX_ATOM_PROP(reps, 38, cPType_int, offsetof(AtomInfoType, visRep));
611   LEX_ATOM_PROP(protons, 39, cPType_schar, offsetof(AtomInfoType, protons));
612   LEX_ATOM_PROP(oneletter, 40, 0, 0);
613   //  LEX_ATOM_PROP(, );
614 
615   return_OVstatus_SUCCESS;
616 }
617 
PyMOL_NewG3DStream(CPyMOL * I,int ** array_ptr)618 int PyMOL_NewG3DStream(CPyMOL * I, int **array_ptr)
619 {
620   int *return_vla = ExecutiveGetG3d(I->G);
621   int result = OVstatus_FAILURE;
622   if(return_vla) {
623     result = VLAGetSize(return_vla) * (sizeof(G3dPrimitive) / sizeof(int));
624   }
625   if(array_ptr)
626     *array_ptr = return_vla;
627   return result;
628 }
629 
PyMOL_DelG3DStream(CPyMOL * I,int * array_ptr)630 int PyMOL_DelG3DStream(CPyMOL * I, int *array_ptr)
631 {
632   VLAFreeP(array_ptr);
633   return OVstatus_SUCCESS;
634 }
635 
PyMOL_PurgeAPI(CPyMOL * I)636 static OVstatus PyMOL_PurgeAPI(CPyMOL * I)
637 {
638   OVOneToOne_DEL_AUTO_NULL(I->Setting);
639   OVOneToOne_DEL_AUTO_NULL(I->Clip);
640   OVOneToOne_DEL_AUTO_NULL(I->SelectList);
641   OVOneToOne_DEL_AUTO_NULL(I->Reinit);
642   OVOneToOne_DEL_AUTO_NULL(I->Rep);
643 #ifdef _PYMOL_LIB
644   OVOneToOne_DEL_AUTO_NULL(I->MouseButtonCodeLexicon);
645   OVOneToOne_DEL_AUTO_NULL(I->MouseButtonModCodeLexicon);
646   OVOneToOne_DEL_AUTO_NULL(I->MouseButtonActionCodeLexicon);
647   OVOneToOne_DEL_AUTO_NULL(I->MouseModeLexicon);
648   OVOneToOne_DEL_AUTO_NULL(I->PaletteLexicon);
649   OVOneToOne_DEL_AUTO_NULL(I->CartoonLexicon);
650   OVOneToOne_DEL_AUTO_NULL(I->FlagLexicon);
651   OVOneToOne_DEL_AUTO_NULL(I->FlagActionLexicon);
652 #endif
653 
654   OVOneToOne_DEL_AUTO_NULL(I->AtomPropertyLexicon);
655 
656   OVLexicon_DEL_AUTO_NULL(I->Lex);
657   return_OVstatus_SUCCESS;
658 }
659 
PyMOL_FreeResultArray(CPyMOL * I,void * array)660 int PyMOL_FreeResultArray(CPyMOL * I, void *array)
661 {
662   if(array) {
663     VLAFreeP(array);
664     return PyMOLstatus_SUCCESS;
665   } else {
666     return PyMOLstatus_FAILURE;
667   }
668 }
669 
PyMOL_CmdDraw(CPyMOL * I,int width,int height,int antialias,int quiet)670 PyMOLreturn_status PyMOL_CmdDraw(CPyMOL * I, int width, int height,
671                                  int antialias, int quiet)
672 {
673   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
674   PYMOL_API_LOCK
675     result.status =
676     get_status_ok(ExecutiveDrawCmd(I->G, width, height, antialias, false, quiet));
677   I->ImageRequestedFlag = true;
678   I->ImageReadyFlag = false;
679   PYMOL_API_UNLOCK return result;
680 }
681 
PyMOL_CmdCapture(CPyMOL * I,int quiet)682 PyMOLreturn_status PyMOL_CmdCapture(CPyMOL * I, int quiet)
683 {
684   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
685   PYMOL_API_LOCK
686     result.status = get_status_ok(ExecutiveDrawCmd(I->G, -1, -1, 0, true, quiet));
687   I->ImageRequestedFlag = true;
688   I->ImageReadyFlag = false;
689   PYMOL_API_UNLOCK return result;
690 }
691 
PyMOL_CmdRay(CPyMOL * I,int width,int height,int antialias,float angle,float shift,int renderer,int defer,int quiet)692 PyMOLreturn_status PyMOL_CmdRay(CPyMOL * I, int width, int height, int antialias,
693                                 float angle, float shift, int renderer, int defer,
694                                 int quiet)
695 {
696   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
697   PYMOL_API_LOCK if(renderer < 0)
698     renderer = SettingGetGlobal_i(I->G, cSetting_ray_default_renderer);
699   SceneInvalidateCopy(I->G, true);
700   result.status =
701     get_status_ok(ExecutiveRay
702                   (I->G, width, height, renderer, angle, shift, quiet, defer, antialias));
703   if(defer) {
704     I->ImageRequestedFlag = true;
705     I->ImageReadyFlag = false;
706   } else {
707     I->ImageRequestedFlag = false;
708     if(SceneHasImage(I->G)) {
709       I->ImageReadyFlag = true;
710     } else {
711       I->ImageReadyFlag = false;
712     }
713   }
714   PYMOL_API_UNLOCK return result;
715 }
716 
PyMOL_CmdSetView(CPyMOL * I,float * view,int view_len,float animate,int quiet)717 PyMOLreturn_status PyMOL_CmdSetView(CPyMOL * I, float *view, int view_len,
718                                     float animate, int quiet)
719 {
720   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
721   SceneViewType tmp;
722   PYMOL_API_LOCK if(view_len >= 18) {
723     int a;
724     UtilZeroMem(tmp, sizeof(tmp));
725     tmp[15] = 1.0F;
726     for(a = 0; a < 3; a++) {
727       tmp[a] = view[a];
728       tmp[a + 4] = view[a + 3];
729       tmp[a + 8] = view[a + 6];
730       tmp[a + 16] = view[a + 9];
731       tmp[a + 19] = view[a + 12];
732       tmp[a + 22] = view[a + 15];
733     }
734     SceneSetView(I->G, tmp, quiet, animate, 0); /* TO DO -- add hand to the API */
735     result.status = get_status_ok(true);
736   } else {
737     result.status = get_status_ok(false);
738   }
739   PYMOL_API_UNLOCK return result;
740 }
741 
PyMOL_CmdGetView(CPyMOL * I,int quiet)742 PyMOLreturn_float_array PyMOL_CmdGetView(CPyMOL * I, int quiet)
743 {
744   PyMOLreturn_float_array result = { PyMOLstatus_FAILURE };
745   SceneViewType tmp;
746   PYMOL_API_LOCK result.size = 18;
747   result.array = VLAlloc(float, result.size);
748   if(result.array) {
749     int a;
750     SceneGetView(I->G, tmp);
751     for(a = 0; a < 3; a++) {
752       result.array[a] = tmp[a];
753       result.array[a + 3] = tmp[a + 4];
754       result.array[a + 6] = tmp[a + 8];
755       result.array[a + 9] = tmp[a + 16];
756       result.array[a + 12] = tmp[a + 19];
757       result.array[a + 15] = tmp[a + 22];
758     }
759     result.status = get_status_ok(true);
760   } else {
761     result.status = get_status_ok(false);
762   }
763   PYMOL_API_UNLOCK return result;
764 }
765 
766 
PyMOL_CmdAlign(CPyMOL * I,const char * source,const char * target,float cutoff,int cycles,float gap,float extend,int max_gap,const char * object,const char * matrix,int source_state,int target_state,int quiet,int max_skip,int transform,int reset)767 PyMOLreturn_float_array PyMOL_CmdAlign(CPyMOL * I, const char *source, const char *target,
768                                        float cutoff, int cycles, float gap, float extend,
769                                        int max_gap, const char *object, const char *matrix,
770                                        int source_state, int target_state, int quiet,
771                                        int max_skip, int transform, int reset)
772 {
773   PyMOLreturn_float_array result = { PyMOLstatus_FAILURE };
774   PYMOL_API_LOCK OrthoLineType s2 = "", s3 = "";
775   int ok = false;
776   ExecutiveRMSInfo rms_info;
777   result.size = 7;
778   result.array = VLAlloc(float, result.size);
779   if(!result.array) {
780     ok = false;
781   } else {
782     ok = ((SelectorGetTmp(I->G, source, s2) >= 0) &&
783           (SelectorGetTmp(I->G, target, s3) >= 0));
784     if(ok) {
785       const float _0 = 0.0F;    /* GCC compiler bug workaround */
786       const float _m1 = -1.0F;
787       ok = ExecutiveAlign(I->G, s2, s3, matrix, gap, extend, max_gap,
788                           max_skip, cutoff, cycles, quiet, object,
789                           source_state - 1, target_state - 1,
790                           &rms_info, transform, reset, _m1, _0, _0, _0, _0, _0, 0, _0);
791       if(ok) {
792         result.array[0] = rms_info.final_rms;
793         result.array[1] = rms_info.final_n_atom;
794         result.array[2] = rms_info.n_cycles_run;
795         result.array[3] = rms_info.initial_rms;
796         result.array[4] = rms_info.initial_n_atom;
797         result.array[5] = rms_info.raw_alignment_score;
798         result.array[6] = rms_info.n_residues_aligned;
799       }
800     }
801   }
802   SelectorFreeTmp(I->G, s2);
803   SelectorFreeTmp(I->G, s3);
804   if(!ok) {
805     VLAFreeP(result.array);
806   }
807   result.status = get_status_ok(ok);
808 
809   PYMOL_API_UNLOCK return result;
810 
811 }
812 
PyMOL_CmdDelete(CPyMOL * I,const char * name,int quiet)813 PyMOLreturn_status PyMOL_CmdDelete(CPyMOL * I, const char *name, int quiet)
814 {
815   PYMOL_API_LOCK ExecutiveDelete(I->G, name);
816   PyMOL_NeedRedisplay(I);  /* this should really only get called if ExecutiveDelete deletes something */
817   PYMOL_API_UNLOCK return return_status_ok(true);       /* TO DO: return a real result */
818 }
819 
PyMOL_CmdZoom(CPyMOL * I,const char * selection,float buffer,int state,int complete,float animate,int quiet)820 PyMOLreturn_status PyMOL_CmdZoom(CPyMOL * I, const char *selection, float buffer,
821                                  int state, int complete, float animate, int quiet)
822 {
823   int ok = false;
824   PYMOL_API_LOCK
825     auto result = ExecutiveWindowZoom(I->G, selection, buffer, state - 1,
826                              complete, animate, quiet);
827     ok = static_cast<bool>(result);
828   PYMOL_API_UNLOCK return return_status_ok(ok);
829 }
830 
PyMOL_CmdOrient(CPyMOL * I,const char * selection,float buffer,int state,int complete,float animate,int quiet)831 PyMOLreturn_status PyMOL_CmdOrient(CPyMOL * I, const char *selection, float buffer,
832                                    int state, int complete, float animate, int quiet)
833 {
834   int ok = true;
835   PYMOL_API_LOCK
836   auto res = ExecutiveOrient(
837       I->G, selection, state - 1, animate, complete, buffer, quiet);
838   ok = static_cast<bool>(res);
839   PYMOL_API_UNLOCK return return_status_ok(ok);
840 }
841 
PyMOL_CmdCenter(CPyMOL * I,const char * selection,int state,int origin,float animate,int quiet)842 PyMOLreturn_status PyMOL_CmdCenter(CPyMOL * I, const char *selection, int state, int origin,
843                                    float animate, int quiet)
844 {
845   int ok = false;
846   PYMOL_API_LOCK
847   auto result = ExecutiveCenter(I->G, selection,
848       state - 1, origin, animate, nullptr, quiet);
849   ok = static_cast<bool>(result);
850   PYMOL_API_UNLOCK return return_status_ok(ok);
851 }
852 
PyMOL_CmdOrigin(CPyMOL * I,const char * selection,int state,int quiet)853 PyMOLreturn_status PyMOL_CmdOrigin(CPyMOL * I, const char *selection, int state, int quiet)
854 {
855   int ok = true;
856   PYMOL_API_LOCK
857   float v[3] = { 0.0F, 0.0F, 0.0F };
858   auto result = ExecutiveOrigin(I->G, selection, true, "", v, state - 1);
859   ok = static_cast<bool>(result);
860   PYMOL_API_UNLOCK return return_status_ok(ok);
861 }
862 
PyMOL_CmdOriginAt(CPyMOL * I,float x,float y,float z,int quiet)863 PyMOLreturn_status PyMOL_CmdOriginAt(CPyMOL * I, float x, float y, float z, int quiet)
864 {
865   int ok = true;
866   PYMOL_API_LOCK float v[3];
867   v[0] = x;
868   v[1] = y;
869   v[2] = z;
870   auto result = ExecutiveOrigin(I->G, "", true, "", v, 0);
871   ok = static_cast<bool>(ok);
872   PYMOL_API_UNLOCK return return_status_ok(ok);
873 }
874 
get_rep_id(CPyMOL * I,const char * representation)875 static OVreturn_word get_rep_id(CPyMOL * I, const char *representation)
876 {
877   OVreturn_word result;
878 
879   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, representation))))
880     return result;
881   return OVOneToOne_GetForward(I->Rep, result.word);
882 }
883 
get_setting_id(CPyMOL * I,const char * setting)884 OVreturn_word get_setting_id(CPyMOL * I, const char *setting)
885 {
886   OVreturn_word result;
887   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, setting))))
888     return result;
889   return OVOneToOne_GetForward(I->Setting, result.word);
890 }
891 
get_reinit_id(CPyMOL * I,const char * reinit)892 static OVreturn_word get_reinit_id(CPyMOL * I, const char *reinit)
893 {
894   OVreturn_word result;
895   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, reinit))))
896     return result;
897   return OVOneToOne_GetForward(I->Reinit, result.word);
898 }
899 
get_select_list_mode(CPyMOL * I,const char * mode)900 static OVreturn_word get_select_list_mode(CPyMOL * I, const char *mode)
901 {
902   OVreturn_word result;
903   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, mode))))
904     return result;
905   return OVOneToOne_GetForward(I->SelectList, result.word);
906 }
907 
PyMOL_CmdClip(CPyMOL * I,const char * mode,float amount,const char * selection,int state,int quiet)908 PyMOLreturn_status PyMOL_CmdClip(CPyMOL * I,
909                                  const char *mode, float amount,
910                                  const char *selection,
911                                  int state, int quiet)
912 {
913   int ok = true;
914   PYMOL_API_LOCK
915     cSceneClip clip_id = SceneClipGetEnum(mode);
916     SelectorTmp2 s1(I->G, selection);
917     SceneClip(I->G, clip_id, amount, s1.getName(), state - 1);
918   PYMOL_API_UNLOCK return return_status_ok(ok);
919 }
920 
PyMOL_CmdLabel(CPyMOL * I,const char * selection,const char * text,int quiet)921 PyMOLreturn_status PyMOL_CmdLabel(CPyMOL * I, const char *selection, const char *text, int quiet)
922 {
923   int ok = true;
924   PYMOL_API_LOCK
925   auto result = ExecutiveLabel(I->G, selection, text, quiet, cExecutiveLabelEvalAlt);
926   ok = static_cast<bool>(result);
927   PYMOL_API_UNLOCK return return_status_ok(ok);
928 }
929 
PyMOL_CmdSelect(CPyMOL * I,const char * name,const char * selection,int quiet)930 PyMOLreturn_status PyMOL_CmdSelect(CPyMOL * I, const char *name, const char *selection, int quiet)
931 {
932   int ret = -1;
933   PYMOL_API_LOCK
934 
935   auto res = SelectorCreate(I->G, name, selection, NULL, quiet, NULL);
936   ret = res ? res.result() : -1;
937 
938   PYMOL_API_UNLOCK return return_status_ok(ret >= 0); // if ret is negative it should fail
939 }
940 
PyMOL_CmdSelectList(CPyMOL * I,const char * name,const char * object,int * list,int list_len,int state,const char * mode,int quiet)941 PyMOLreturn_status PyMOL_CmdSelectList(CPyMOL * I, const char *name, const char *object, int *list,
942                                        int list_len, int state, const char *mode, int quiet)
943 {
944   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
945   PYMOL_API_LOCK OVreturn_word mode_id;
946   if(OVreturn_IS_OK((mode_id = get_select_list_mode(I, mode)))) {
947     result.status =
948       ExecutiveSelectList(I->G, name, object, list, list_len, state - 1, mode_id.word,
949                           quiet);
950   }
951   PYMOL_API_UNLOCK return result;
952 }
953 
PyMOL_CmdShow(CPyMOL * I,const char * representation,const char * selection,int quiet)954 PyMOLreturn_status PyMOL_CmdShow(CPyMOL * I,
955                                  const char *representation,
956                                  const char *selection,
957                                  int quiet)
958 {
959   int ok = true;
960   PYMOL_API_LOCK OrthoLineType s1;
961   OVreturn_word rep_id;
962   if(OVreturn_IS_OK((rep_id = get_rep_id(I, representation)))) {
963     SelectorGetTmp2(I->G, selection, s1);
964     if (!s1[0]){  /* This doesn't catch patterns that don't match, but everything else */
965       ok = false;
966     } else {
967       ExecutiveSetRepVisib(I->G, s1, rep_id.word, true);
968       PyMOL_NeedRedisplay(I);  /* this should really only get called if ExecutiveSetRepVisib changes something */
969       SelectorFreeTmp(I->G, s1);
970     }
971   } else {
972     ok = false;
973   }
974   PYMOL_API_UNLOCK return return_status_ok(ok);
975 }
976 
PyMOL_CmdHide(CPyMOL * I,const char * representation,const char * selection,int quiet)977 PyMOLreturn_status PyMOL_CmdHide(CPyMOL * I,
978                                  const char *representation,
979                                  const char *selection,
980                                  int quiet)
981 {
982   int ok = true;
983   PYMOL_API_LOCK OrthoLineType s1;
984   OVreturn_word rep_id;
985   if(OVreturn_IS_OK((rep_id = get_rep_id(I, representation)))) {
986     SelectorGetTmp2(I->G, selection, s1);
987     if (!s1[0]){  /* This doesn't catch patterns that don't match, but everything else */
988       ok = false;
989     } else {
990       ExecutiveSetRepVisib(I->G, s1, rep_id.word, false);
991       SelectorFreeTmp(I->G, s1);
992     }
993   } else {
994     ok = false;
995   }
996   PYMOL_API_UNLOCK return return_status_ok(ok);
997 }
998 
PyMOL_CmdEnable(CPyMOL * I,const char * name,int quiet)999 PyMOLreturn_status PyMOL_CmdEnable(CPyMOL * I, const char *name, int quiet)
1000 {
1001   int ok = false;
1002   PYMOL_API_LOCK if(name[0] == '(') {
1003     auto result1 = ExecutiveSetOnOffBySele(I->G, name, true);
1004     ok = static_cast<bool>(ok);
1005   }
1006   auto result2 = ExecutiveSetObjVisib(I->G, name, true, false);   /* TO DO: parents */
1007   ok = static_cast<bool>(result2);
1008   PYMOL_API_UNLOCK return return_status_ok(ok);
1009 }
1010 
PyMOL_CmdDisable(CPyMOL * I,const char * name,int quiet)1011 PyMOLreturn_status PyMOL_CmdDisable(CPyMOL * I, const char *name, int quiet)
1012 {
1013   int ok = false;
1014   PYMOL_API_LOCK if(name[0] == '(') {
1015     auto result = ExecutiveSetOnOffBySele(I->G, name, true);
1016     ok = static_cast<bool>(result);
1017   } else {
1018     auto result = ExecutiveSetObjVisib(I->G, name, false, false);
1019     ok = static_cast<bool>(result);
1020   }
1021   PYMOL_API_UNLOCK return return_status_ok(ok);
1022 }
1023 
PyMOL_CmdSetBond(CPyMOL * I,const char * setting,const char * value,const char * selection1,const char * selection2,int state,int quiet,int side_effects)1024 PyMOLreturn_status PyMOL_CmdSetBond(CPyMOL * I, const char *setting, const char *value,
1025                                     const char *selection1, const char *selection2,
1026                                     int state, int quiet, int side_effects)
1027 {
1028   int ok = true;
1029   PYMOL_API_LOCK {
1030     OVreturn_word setting_id;
1031     OrthoLineType s1 = "";
1032     OrthoLineType s2 = "";
1033     if(ok) ok = OVreturn_IS_OK((setting_id = get_setting_id(I, setting)));
1034     if(ok) ok = (SelectorGetTmp(I->G, selection1, s1) >= 0);
1035     if(ok) {
1036       if(selection2 && selection2[0]) {
1037         ok = (SelectorGetTmp(I->G, selection2, s2) >= 0);
1038       } else {
1039         ok = (SelectorGetTmp(I->G, selection1, s2) >= 0);
1040       }
1041     }
1042     if(ok) {
1043       ok = ExecutiveSetBondSettingFromString(I->G, setting_id.word, value,
1044                                              s1, s2,
1045                                              state - 1, quiet, side_effects);
1046     }
1047     SelectorFreeTmp(I->G, s1);
1048     SelectorFreeTmp(I->G, s2);
1049   } PYMOL_API_UNLOCK
1050       return return_status_ok(ok);
1051 }
1052 
PyMOL_CmdUnsetBond(CPyMOL * I,const char * setting,const char * selection1,const char * selection2,int state,int quiet,int side_effects)1053 PyMOLreturn_status PyMOL_CmdUnsetBond(CPyMOL * I, const char *setting,
1054                                       const char *selection1, const char *selection2,
1055                                       int state, int quiet, int side_effects)
1056 {
1057   int ok = true;
1058   PYMOL_API_LOCK {
1059     OVreturn_word setting_id;
1060     OrthoLineType s1 = "";
1061     OrthoLineType s2 = "";
1062     if(ok) ok = OVreturn_IS_OK((setting_id = get_setting_id(I, setting)));
1063     if(ok) ok = (SelectorGetTmp(I->G, selection1, s1) >= 0);
1064     if(ok) {
1065       if(selection2 && selection2[0]) {
1066         ok = (SelectorGetTmp(I->G, selection2, s2) >= 0);
1067       } else {
1068         ok = (SelectorGetTmp(I->G, selection1, s2) >= 0);
1069       }
1070     }
1071     if(ok) {
1072       ok = ExecutiveUnsetBondSetting(I->G, setting_id.word,
1073                                      s1, s2,
1074                                      state - 1, quiet, side_effects);
1075     }
1076     SelectorFreeTmp(I->G, s1);
1077     SelectorFreeTmp(I->G, s2);
1078   } PYMOL_API_UNLOCK
1079       return return_status_ok(ok);
1080 }
1081 
PyMOL_CmdSet(CPyMOL * I,const char * setting,const char * value,const char * selection,int state,int quiet,int side_effects)1082 PyMOLreturn_status PyMOL_CmdSet(CPyMOL * I,
1083                                 const char *setting,
1084                                 const char *value,
1085                                 const char *selection,
1086                                 int state, int quiet, int side_effects)
1087 {
1088   int ok = true;
1089   PYMOL_API_LOCK {
1090     OVreturn_word setting_id;
1091     OrthoLineType s1 = "";
1092     if(ok) ok = OVreturn_IS_OK((setting_id = get_setting_id(I, setting)));
1093     if(ok) ok = (SelectorGetTmp2(I->G, selection, s1) >= 0);
1094 
1095     if(ok) {
1096       ExecutiveSetSettingFromString(I->G, setting_id.word, value, s1,
1097                                     state - 1, quiet, side_effects);
1098     }
1099     SelectorFreeTmp(I->G, s1);
1100   }
1101   PYMOL_API_UNLOCK return return_status_ok(ok);
1102 }
1103 
PyMOL_CmdGet(CPyMOL * I,const char * setting,const char * selection,int state,int quiet)1104 PyMOLreturn_value PyMOL_CmdGet(CPyMOL * I,
1105                                 const char *setting,
1106                                 const char *selection,
1107                                 int state, int quiet){
1108   int ok = true;
1109   PyMOLreturn_value result = { PyMOLstatus_SUCCESS };
1110 
1111   PYMOL_API_LOCK {
1112     OVreturn_word setting_id;
1113     OrthoLineType s1 = "";
1114     if(ok) ok = OVreturn_IS_OK((setting_id = get_setting_id(I, setting)));
1115     if(ok) ok = (SelectorGetTmp2(I->G, selection, s1) >= 0);
1116 
1117     if(ok) {
1118       ExecutiveGetSettingFromString(I->G, &result, setting_id.word, s1,
1119                                     state - 1, quiet);
1120     }
1121     SelectorFreeTmp(I->G, s1);
1122   }
1123   PYMOL_API_UNLOCK return result;
1124 }
1125 
1126 
PyMOL_CmdUnset(CPyMOL * I,const char * setting,const char * selection,int state,int quiet,int side_effects)1127 PyMOLreturn_status PyMOL_CmdUnset(CPyMOL * I, const char *setting, const char *selection,
1128                                   int state, int quiet, int side_effects)
1129 {
1130   int ok = true;
1131   PYMOL_API_LOCK {
1132     OVreturn_word setting_id;
1133     OrthoLineType s1 = "";
1134     if(ok) ok = OVreturn_IS_OK((setting_id = get_setting_id(I, setting)));
1135     if(ok) ok = (SelectorGetTmp2(I->G, selection, s1) >= 0);
1136     if(ok) {
1137       ExecutiveUnsetSetting(I->G, setting_id.word, s1,
1138                             state - 1, quiet, side_effects);
1139     }
1140     SelectorFreeTmp(I->G, s1);
1141   }
1142   PYMOL_API_UNLOCK return return_status_ok(ok);
1143 }
1144 
PyMOL_CmdColor(CPyMOL * I,const char * color,const char * selection,int flags,int quiet)1145 PyMOLreturn_status PyMOL_CmdColor(CPyMOL * I, const char *color, const char *selection, int flags,
1146                                   int quiet)
1147 {
1148   int ok = true;
1149   PYMOL_API_LOCK
1150   auto result = ExecutiveColor(I->G, selection, color, flags, quiet);
1151   ok = static_cast<bool>(result);
1152   PYMOL_API_UNLOCK return return_status_ok(ok);
1153 }
1154 
1155 /* -- JV */
PyMOL_CmdBackgroundColor(CPyMOL * I,const char * value)1156 PyMOLreturn_status PyMOL_CmdBackgroundColor(CPyMOL * I, const char *value) {
1157   int ok = true;
1158   PYMOL_API_LOCK
1159 
1160   int idx = ColorGetIndex(I->G, value);
1161   if(idx >= 0){
1162     SettingSetGlobal_i(I->G, cSetting_bg_rgb, idx);
1163   } else {
1164     ErrMessage(I->G, "Color", "Bad color name.");
1165   }
1166   PYMOL_API_UNLOCK return return_status_ok(ok);
1167 }
1168 
PyMOL_CmdReinitialize(CPyMOL * I,const char * what,const char * object_name)1169 PyMOLreturn_status PyMOL_CmdReinitialize(CPyMOL * I,
1170     const char *what,
1171     const char *object_name)
1172 {
1173   int ok = true;
1174   OVreturn_word what_id;
1175   PYMOL_API_LOCK if(OVreturn_IS_OK((what_id = get_reinit_id(I, what)))) {
1176     auto res = ExecutiveReinitialize(I->G, what_id.word, object_name);
1177     ok = static_cast<bool>(res);
1178   }
1179   PYMOL_API_UNLOCK return return_status_ok(ok);
1180 }
1181 
PyMOL_CmdGetMovieLength(CPyMOL * I,int quiet)1182 PyMOLreturn_int PyMOL_CmdGetMovieLength(CPyMOL * I,int quiet)
1183 {
1184   int ok = true;
1185   PyMOLreturn_int result;
1186   result.status = PyMOLstatus_FAILURE;
1187   result.value = 0;
1188 
1189   PYMOL_API_LOCK
1190   if(ok) {
1191     result.value = MovieGetLength(I->G);
1192     result.status = get_status_ok(ok);
1193   };
1194   PYMOL_API_UNLOCK return result;
1195 }
1196 
PyMOL_CmdGetDistance(CPyMOL * I,const char * selection1,const char * selection2,int state,int quiet)1197 PyMOLreturn_float PyMOL_CmdGetDistance(CPyMOL * I,
1198                                        const char *selection1,
1199                                        const char *selection2, int state, int quiet)
1200 {
1201   PyMOLreturn_float result;
1202   PYMOL_API_LOCK {
1203     result = return_result(ExecutiveGetDistance(I->G,
1204         selection1,
1205         selection2,
1206         state));
1207   }
1208   PYMOL_API_UNLOCK return result;
1209 }
1210 
PyMOL_CmdDistance(CPyMOL * I,const char * name,const char * selection1,const char * selection2,int mode,float cutoff,int label,int reset,int zoom,int state,int quiet)1211 PyMOLreturn_float PyMOL_CmdDistance(CPyMOL * I,
1212                                     const char *name,
1213                                     const char *selection1,
1214                                     const char *selection2,
1215                                     int mode,
1216                                     float cutoff,
1217                                     int label, int reset, int zoom, int state, int quiet)
1218 {
1219   PyMOLreturn_float result;
1220   PYMOL_API_LOCK {
1221     int defState1 = -4, defState2 = -4;
1222     auto res = ExecutiveDistance(I->G, name,
1223         selection1, selection2, mode, cutoff, label, quiet, reset, state, zoom, defState1, defState2);
1224     result = return_result(res);
1225   }
1226   PYMOL_API_UNLOCK return result;
1227 }
1228 
PyMOL_CmdGetAngle(CPyMOL * I,const char * selection1,const char * selection2,const char * selection3,int state,int quiet)1229 PyMOLreturn_float PyMOL_CmdGetAngle(CPyMOL * I,
1230                                     const char *selection1,
1231                                     const char *selection2,
1232                                     const char *selection3, int state, int quiet)
1233 {
1234   PyMOLreturn_float result;
1235   PYMOL_API_LOCK {
1236     result = return_result(ExecutiveGetAngle(I->G,
1237         selection1,
1238         selection2,
1239         selection3,
1240         state));
1241   }
1242   PYMOL_API_UNLOCK return result;
1243 }
1244 
PyMOL_CmdAngle(CPyMOL * I,const char * name,const char * selection1,const char * selection2,const char * selection3,int mode,int label,int reset,int zoom,int state,int quiet)1245 PyMOLreturn_float PyMOL_CmdAngle(CPyMOL * I,
1246                                  const char *name,
1247                                  const char *selection1,
1248                                  const char *selection2,
1249                                  const char *selection3,
1250                                  int mode,
1251                                  int label, int reset, int zoom, int state, int quiet)
1252 {
1253   PyMOLreturn_float result;
1254   PYMOL_API_LOCK {
1255     int defState1 = -4, defState2 = -4, defState3 = -3;
1256     auto res = ExecutiveAngle(I->G, name,
1257         selection1, selection2, selection3, mode, label, reset, zoom, quiet,
1258         state, defState1, defState2, defState3);
1259     result = return_result(res);
1260   }
1261   PYMOL_API_UNLOCK return result;
1262 }
1263 
PyMOL_CmdGetDihedral(CPyMOL * I,const char * selection1,const char * selection2,const char * selection3,const char * selection4,int state,int quiet)1264 PyMOLreturn_float PyMOL_CmdGetDihedral(CPyMOL * I,
1265                                        const char *selection1,
1266                                        const char *selection2,
1267                                        const char *selection3,
1268                                        const char *selection4, int state, int quiet)
1269 {
1270   PyMOLreturn_float result;
1271   PYMOL_API_LOCK {
1272     result = return_result(ExecutiveGetDihe(I->G,
1273         selection1,
1274         selection2,
1275         selection3,
1276         selection4,
1277         state));
1278   }
1279   PYMOL_API_UNLOCK return result;
1280 }
1281 
PyMOL_CmdDihedral(CPyMOL * I,const char * name,const char * selection1,const char * selection2,const char * selection3,const char * selection4,int mode,int label,int reset,int zoom,int state,int quiet)1282 PyMOLreturn_float PyMOL_CmdDihedral(CPyMOL * I,
1283                                     const char *name,
1284                                     const char *selection1,
1285                                     const char *selection2,
1286                                     const char *selection3,
1287                                     const char *selection4,
1288                                     int mode,
1289                                     int label, int reset, int zoom, int state, int quiet)
1290 {
1291   PyMOLreturn_float result;
1292   PYMOL_API_LOCK {
1293     auto res = ExecutiveDihedral(I->G,
1294         name, selection1, selection2, selection3, selection4, mode, label,
1295         reset, zoom, quiet, state);
1296     result = return_result(res);
1297   }
1298   PYMOL_API_UNLOCK return result;
1299 }
1300 
PyMOL_CmdIsodot(CPyMOL * I,const char * name,const char * map_name,float level,const char * selection,float buffer,int state,float carve,int source_state,int quiet)1301 PyMOLreturn_status PyMOL_CmdIsodot(CPyMOL * I, const char *name, const char *map_name, float level,
1302                                    const char *selection, float buffer, int state, float carve,
1303                                    int source_state, int quiet)
1304 {
1305   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
1306   PYMOL_API_LOCK
1307   auto res = ExecutiveIsomeshEtc(I->G, name, map_name, level, selection, buffer,
1308       state - 1, carve, source_state - 1, quiet, 1, level);
1309   result.status = get_status_ok(bool(res));
1310   PYMOL_API_UNLOCK return result;
1311 
1312 }
1313 
PyMOL_CmdIsomesh(CPyMOL * I,const char * name,const char * map_name,float level,const char * selection,float buffer,int state,float carve,int source_state,int quiet)1314 PyMOLreturn_status PyMOL_CmdIsomesh(CPyMOL * I, const char *name, const char *map_name, float level,
1315                                     const char *selection, float buffer, int state, float carve,
1316                                     int source_state, int quiet)
1317 {
1318   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
1319   PYMOL_API_LOCK
1320   auto res = ExecutiveIsomeshEtc(I->G, name, map_name, level, selection, buffer,
1321       state - 1, carve, source_state - 1, quiet, 0, level);
1322   result.status = get_status_ok(bool(res));
1323   PYMOL_API_UNLOCK return result;
1324 }
1325 
PyMOL_CmdIsosurface(CPyMOL * I,const char * name,const char * map_name,float level,const char * selection,float buffer,int state,float carve,int source_state,int side,int mode,int quiet)1326 PyMOLreturn_status PyMOL_CmdIsosurface(CPyMOL * I, const char *name, const char *map_name,
1327                                        float level, const char *selection, float buffer,
1328                                        int state, float carve, int source_state, int side,
1329                                        int mode, int quiet)
1330 {
1331   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
1332   PYMOL_API_LOCK
1333   auto res = ExecutiveIsosurfaceEtc(I->G, name, map_name, level, selection,
1334       buffer, state - 1, carve, source_state - 1, side, quiet, mode);
1335   result.status = get_status_ok(bool(res));
1336   PYMOL_API_UNLOCK return result;
1337 }
1338 
PyMOL_CmdGradient(CPyMOL * I,const char * name,const char * map_name,float minimum,float maximum,const char * selection,float buffer,int state,float carve,int source_state,int quiet)1339 PyMOLreturn_status PyMOL_CmdGradient(CPyMOL * I, const char *name, const char *map_name,
1340                                      float minimum, float maximum, const char *selection,
1341                                      float buffer, int state, float carve,
1342                                      int source_state, int quiet)
1343 {
1344   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
1345   PYMOL_API_LOCK
1346   auto res = ExecutiveIsomeshEtc(I->G, name, map_name, minimum, selection,
1347       buffer, state - 1, carve, source_state - 1, quiet, 3, maximum);
1348   result.status = get_status_ok(bool(res));
1349   PYMOL_API_UNLOCK return result;
1350 }
1351 
PyMOL_CmdIsolevel(CPyMOL * I,const char * name,float level,int state,int query,int quiet)1352 PyMOLreturn_float PyMOL_CmdIsolevel(CPyMOL * I, const char *name, float level, int state,
1353                                     int query, int quiet)
1354 {
1355   PyMOLreturn_float result;
1356   PYMOL_API_LOCK
1357     if(query) {
1358       auto res = ExecutiveGetIsolevel(I->G, name, state - 1);
1359       result = return_result(res);
1360   } else {
1361       auto res = ExecutiveIsolevel(I->G, name, level, state - 1, quiet);
1362       result.status = get_status_ok(static_cast<bool>(res));
1363       result.value = level;
1364   }
1365   PYMOL_API_UNLOCK return result;
1366 }
1367 
word_count(const char * src)1368 static int word_count(const char *src)
1369 {                               /* only works for ascii */
1370   int cnt = 0;
1371   while((*src) && ((*src) < 33))        /* skip leading whitespace */
1372     src++;
1373   while(*src) {
1374     if((*src) > 32) {
1375       cnt++;
1376       while((*src) && ((*src) > 32))
1377         src++;
1378     }
1379     while((*src) && ((*src) < 33))
1380       src++;
1381   }
1382   return cnt;
1383 }
1384 
next_word(const char * src,char * dst,int buf_size)1385 static const char *next_word(const char *src, char *dst, int buf_size)
1386 {                               /* only works for ascii */
1387   while((*src) && ((*src) < 33))        /* skip leading whitespace */
1388     src++;
1389   while(*src) {
1390     if((*src) > 32) {
1391       while((*src) && ((*src) > 32) && (buf_size > 1)) {
1392         *(dst++) = *(src++);
1393         buf_size--;
1394       }
1395       break;
1396     }
1397   }
1398   dst[0] = 0;
1399   return src;
1400 }
1401 
PyMOL_CmdRampNew(CPyMOL * I,const char * name,const char * map,float * range,int n_level,const char * color,int state,const char * selection,float beyond,float within,float sigma,int zero,int calc_mode,int quiet)1402 PyMOLreturn_status PyMOL_CmdRampNew(CPyMOL * I, const char *name, const char *map, float *range,
1403                                     int n_level, const char *color, int state, const char *selection,
1404                                     float beyond, float within, float sigma,
1405                                     int zero, int calc_mode, int quiet)
1406 {
1407   int ok = true;
1408   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
1409   OrthoLineType s1 = "";
1410   float *color_vla = NULL;
1411   float *range_vla = NULL;
1412   PYMOL_API_LOCK if(selection && selection[0]) {
1413     if(ok)
1414       ok = (SelectorGetTmp(I->G, selection, s1) >= 0);
1415   }
1416   if(ok) {
1417     if(range && n_level) {
1418       range_vla = VLAlloc(float, n_level);
1419       UtilCopyMem(range_vla, range, sizeof(float) * n_level);
1420     }
1421   }
1422 
1423   if(ok && color) {
1424     int n_color = word_count(color);
1425     /* to do */
1426     if(color && n_color) {
1427       color_vla = VLAlloc(float, n_color * 3);
1428       if(color_vla) {
1429         WordType colorName;
1430         int a;
1431         for(a = 0; a < n_color; a++) {
1432           color = next_word(color, colorName, sizeof(colorName));
1433           {
1434             const float *src = ColorGetNamed(I->G, colorName);
1435             float *dst = color_vla + 3 * a;
1436             copy3f(src, dst);
1437           }
1438         }
1439       }
1440     }
1441   }
1442   if(ok) {
1443     auto res =
1444         ExecutiveRampNew(I->G, name, map, pymol::vla_take_ownership(range_vla),
1445             pymol::vla_take_ownership(color_vla), state, s1, beyond, within,
1446             sigma, zero, calc_mode, quiet);
1447     ok = static_cast<bool>(res);
1448     result.status = get_status_ok(ok);
1449   } else {
1450     result.status = PyMOLstatus_FAILURE;
1451   }
1452   SelectorFreeTmp(I->G, s1);
1453   PYMOL_API_UNLOCK return result;
1454 }
1455 
1456 /*
1457  * Supported file formats and they internal codes
1458  */
1459 struct {
1460   const char * name;
1461   cLoadType_t code_buffer;
1462   cLoadType_t code_filename;
1463 } const ContentTypeTable[] = {
1464   // molecules
1465   {"pdb",           cLoadTypePDBStr,    cLoadTypePDB},
1466   {"vdb",           cLoadTypeVDBStr,    cLoadTypeUnknown},
1467   {"cif",           cLoadTypeCIFStr,    cLoadTypeCIF},
1468   {"mmtf",          cLoadTypeMMTFStr,   cLoadTypeMMTF},
1469   {"mae",           cLoadTypeMAEStr,    cLoadTypeMAE},
1470   {"sdf",           cLoadTypeSDF2Str,   cLoadTypeSDF2},
1471   {"mol",           cLoadTypeMOLStr,    cLoadTypeMOL},
1472   {"mol2",          cLoadTypeMOL2Str,   cLoadTypeMOL2},
1473   {"xyz",           cLoadTypeXYZStr,    cLoadTypeXYZ},
1474   {"pqr",           cLoadTypeUnknown,   cLoadTypePQR},
1475   {"macromodel",    cLoadTypeMMDStr,    cLoadTypeMMD},
1476   // maps
1477   {"ccp4",          cLoadTypeCCP4Str,   cLoadTypeUnknown},
1478   {"xplor",         cLoadTypeXPLORStr,  cLoadTypeXPLORMap},
1479   {"phi",           cLoadTypePHIStr,    cLoadTypePHIMap},
1480   {"dx",            cLoadTypeUnknown,   cLoadTypeDXMap},
1481   // special
1482   {"cgo",           cLoadTypeCGO,       cLoadTypeUnknown},
1483   {NULL,            cLoadTypeUnknown,   cLoadTypeUnknown}
1484 };
1485 
1486 /*
1487  * Proxy for "ExecutiveLoad" with string "content_format" (and "content_type")
1488  * argument.
1489  *
1490  * content:     Either file name or file contents, depending on "content_type"
1491  * content_type:        "filename", "string", "raw", or "cgo"
1492  * content_length:      Length of "content", if it's not a file name or a
1493  *                      null-terminated string (pass -1).
1494  * content_format:      The file format, e.g. "pdb", "sdf", "mol2", ...
1495  * object_name:         New object name. Can be empty if "content_type" is
1496  *                      "filename".
1497  */
Loader(CPyMOL * I,const char * content,const char * content_type,int content_length,const char * content_format,const char * object_name,int state,int discrete,int finish,int quiet,int multiplex,int zoom)1498 static PyMOLreturn_status Loader(CPyMOL * I, const char *content, const char *content_type,
1499                                  int content_length, const char *content_format,
1500                                  const char *object_name, int state,
1501                                  int discrete, int finish,
1502                                  int quiet, int multiplex, int zoom)
1503 {
1504   PyMOLGlobals * G = I->G;
1505   bool content_is_filename = false;
1506   int ok = true;
1507   WordType obj_name;
1508 
1509   // `content` can be a file name, or the file contents
1510   if (strcmp(content_type, "filename") == 0) {
1511     content_is_filename = true;
1512   } else if (strcmp(content_type, "string") == 0) {
1513     if (content_length < 0)
1514       content_length = strlen(content);
1515   } else if (
1516       strcmp(content_type, "raw") != 0 &&
1517       strcmp(content_type, "cgo") != 0) {
1518     PRINTFB(G, FB_Executive, FB_Errors)
1519       " Error: Unknown content type '%s'\n", content_type ENDFB(G);
1520     ok = false;
1521   }
1522 
1523   if(ok) {
1524     {                           /* if object_name is blank and content is a filename, then
1525                                    compute the object_name from the file prefix */
1526       if((!object_name[0]) && content_is_filename) {
1527         const char *start, *stop;
1528         stop = start = content + strlen(content) - 1;
1529         while(start > content) {        /* known path separators */
1530           if((start[-1] == ':') || (start[-1] == '\'') || (start[-1] == '/'))
1531             break;
1532           start--;
1533         }
1534         while(stop > start) {
1535           if(*stop == '.')
1536             break;
1537           stop--;
1538         }
1539         if(stop == start)
1540           stop = content + strlen(content);
1541         if((stop - start) >= sizeof(WordType))
1542           stop = start + sizeof(WordType) - 1;
1543         {
1544           char *q;
1545           const char *p = start;
1546           q = obj_name;
1547           while(p < stop) {
1548             *(q++) = *(p++);
1549           }
1550           *q = 0;
1551           object_name = obj_name;
1552         }
1553       }
1554     }
1555     {
1556       cLoadType_t pymol_content_type = cLoadTypeUnknown;
1557 
1558       for (auto it = ContentTypeTable; it->name; ++it) {
1559         if (strcmp(it->name, content_format) == 0) {
1560           pymol_content_type = content_is_filename ?
1561             it->code_filename : it->code_buffer;
1562           break;
1563         }
1564       }
1565 
1566       if (pymol_content_type == cLoadTypeUnknown) {
1567         PRINTFB(G, FB_Executive, FB_Errors)
1568           " Error: Unknown content format '%s' with type '%s'\n",
1569           content_format, content_type ENDFB(G);
1570         ok = false;
1571       }
1572 
1573       if(ok) {
1574         auto result = ExecutiveLoad(I->G,
1575             content_is_filename ? content : nullptr,
1576             content_is_filename ? nullptr : content,
1577                            content_length,
1578                            pymol_content_type,
1579                            object_name,
1580                            state - 1, zoom, discrete, finish, multiplex, quiet, NULL, 0, NULL);
1581         ok = static_cast<bool>(result);
1582       }
1583     }
1584   }
1585   if (ok)
1586     PyMOL_NeedRedisplay(I);
1587   return return_status_ok(ok);
1588 }
1589 
PyMOL_CmdLoad(CPyMOL * I,const char * content,const char * content_type,const char * content_format,const char * object_name,int state,int discrete,int finish,int quiet,int multiplex,int zoom)1590 PyMOLreturn_status PyMOL_CmdLoad(CPyMOL * I,
1591                                  const char *content,
1592                                  const char *content_type,
1593                                  const char *content_format,
1594                                  const char *object_name, int state,
1595                                  int discrete, int finish,
1596                                  int quiet, int multiplex, int zoom)
1597 {
1598   PyMOLreturn_status status = { PyMOLstatus_FAILURE };
1599   PYMOL_API_LOCK
1600     status = Loader(I, content, content_type, -1, content_format, object_name,
1601                     state, discrete, finish, quiet, multiplex, zoom);
1602   PYMOL_API_UNLOCK return status;
1603 }
1604 
PyMOL_CmdLoadRaw(CPyMOL * I,const char * content,int content_length,const char * content_format,const char * object_name,int state,int discrete,int finish,int quiet,int multiplex,int zoom)1605 PyMOLreturn_status PyMOL_CmdLoadRaw(CPyMOL * I,
1606                                     const char *content,
1607                                     int content_length,
1608                                     const char *content_format,
1609                                     const char *object_name, int state,
1610                                     int discrete, int finish,
1611                                     int quiet, int multiplex, int zoom)
1612 {
1613   PyMOLreturn_status status = { PyMOLstatus_FAILURE };
1614   PYMOL_API_LOCK
1615     status = Loader(I, content, "raw", content_length, content_format,
1616                     object_name, state, discrete, finish, quiet, multiplex, zoom);
1617   PYMOL_API_UNLOCK return status;
1618 }
1619 
PyMOL_CmdLoadCGO(CPyMOL * I,const float * content,int content_length,const char * object_name,int state,int quiet,int zoom)1620 PyMOLreturn_status PyMOL_CmdLoadCGO(CPyMOL * I,
1621                                     const float *content,
1622                                     int content_length,
1623                                     const char *object_name, int state, int quiet, int zoom)
1624 {
1625   PyMOLreturn_status status = { PyMOLstatus_FAILURE };
1626   PYMOL_API_LOCK
1627     status = Loader(I, (char *) content, "cgo", content_length, "cgo",
1628                     object_name, state, 0, 1, quiet, 0, zoom);
1629   PYMOL_API_UNLOCK return status;
1630 }
1631 
PyMOL_CmdCreate(CPyMOL * I,const char * name,const char * selection,int source_state,int target_state,int discrete,int zoom,int quiet,int singletons,const char * extract,int copy_properties)1632 PyMOLreturn_status PyMOL_CmdCreate(CPyMOL * I,
1633                                    const char *name,
1634                                    const char *selection, int source_state,
1635                                    int target_state, int discrete,
1636                                    int zoom, int quiet, int singletons,
1637                                    const char *extract, int copy_properties)
1638 {
1639   int ok = true;
1640   PYMOL_API_LOCK
1641   auto result = ExecutiveSeleToObject(I->G,
1642       name, selection, source_state, target_state, discrete, zoom, quiet,
1643       singletons, copy_properties);
1644   ok = static_cast<bool>(result);
1645   PYMOL_API_UNLOCK return return_status_ok(ok);
1646 }
1647 
PyMOL_CmdPseudoatom(CPyMOL * I,const char * object_name,const char * selection,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 * color,const char * label,int use_xyz,float x,float y,float z,int state,int mode,int quiet)1648 PyMOLreturn_status PyMOL_CmdPseudoatom(CPyMOL * I, const char *object_name, const char *selection,
1649 				       const char *name, const char *resn, const char *resi, const char *chain,
1650 				       const char *segi, const char *elem, float vdw, int hetatm,
1651 				       float b, float q, const char *color, const char *label,
1652 				       int use_xyz, float x, float y, float z,
1653 				       int state, int mode, int quiet)
1654 {
1655   int ok = true;
1656   PYMOL_API_LOCK
1657   if(ok) {
1658     int color_index = ColorGetIndex(I->G, color);
1659     if(ok) {
1660       float pos_tmp[3], *pos = pos_tmp;
1661       if(use_xyz) {
1662 	pos[0] = x;
1663 	pos[1] = y;
1664 	pos[2] = z;
1665       } else {
1666 	pos = NULL;
1667       }
1668       auto pseudoatom_name = ExecutivePreparePseudoatomName(I->G, object_name);
1669       auto res = ExecutivePseudoatom(I->G, pseudoatom_name, selection, name,
1670           resn, resi, chain, segi, elem, vdw, hetatm, b, q, label, pos,
1671           color_index, state - 1, mode, quiet);
1672       ok = static_cast<bool>(res);
1673     }
1674   }
1675   PYMOL_API_UNLOCK return return_status_ok(ok);
1676 }
1677 
PyMOL_CmdTurn(CPyMOL * I,char axis,float angle)1678 PyMOLreturn_status PyMOL_CmdTurn(CPyMOL * I, char axis, float angle){
1679   PyMOLreturn_status result = { PyMOLstatus_SUCCESS };
1680   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
1681   switch (axis){
1682   case 'x':
1683     SceneRotate(G, angle, 1.0, 0.0, 0.0);
1684     break;
1685   case 'y':
1686     SceneRotate(G, angle, 0.0, 1.0, 0.0);
1687     break;
1688   case 'z':
1689     SceneRotate(G, angle, 0.0, 0.0, 1.0);
1690     break;
1691   default:
1692     result.status = PyMOLstatus_FAILURE;
1693     break;
1694   }
1695   PYMOL_API_UNLOCK return result;
1696 }
1697 
PyMOL_CmdMPlay(CPyMOL * I,int cmd)1698 PyMOLreturn_status PyMOL_CmdMPlay(CPyMOL * I, int cmd){
1699   PyMOLreturn_status result = { PyMOLstatus_SUCCESS };
1700   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
1701   MoviePlay(G, cmd);
1702   PYMOL_API_UNLOCK return result;
1703 }
1704 
PyMOL_CmdSetFeedbackMask(CPyMOL * I,int action,int module,int mask)1705 PyMOLreturn_status PyMOL_CmdSetFeedbackMask(CPyMOL * I, int action, int module, int mask){
1706   PyMOLreturn_status result = { PyMOLstatus_SUCCESS };
1707   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
1708   switch (action){
1709   case 0:
1710     G->Feedback->setMask(module, (uchar) mask);
1711     break;
1712   case 1:
1713     G->Feedback->enable(module, (uchar) mask);
1714     break;
1715   case 2:
1716     G->Feedback->disable(module, (uchar) mask);
1717     break;
1718   case 3:
1719     G->Feedback->push();
1720     break;
1721   case 4:
1722     G->Feedback->pop();
1723     break;
1724   }
1725   PYMOL_API_UNLOCK return result;
1726 }
1727 
1728 static const CPyMOLOptions Defaults = {
1729   true,                         /* pmgui */
1730 #ifndef _PYMOL_NOPY
1731   true,                         /* internal_gui */
1732 #else
1733   false,
1734 #endif
1735 #ifndef _PYMOL_NOPY
1736   true,                         /* show_splash */
1737 #else
1738   false,
1739 #endif
1740 #ifndef _PYMOL_NOPY
1741   1,                            /* internal_feedback */
1742 #else
1743   0,
1744 #endif
1745   true,                         /* security */
1746   false,                        /* game mode */
1747   0,                            /* force_stereo */
1748   640,                          /* winX */
1749   480,                          /* winY */
1750   false,                        /* blue_line */
1751   0,                            /* winPX */
1752   175,                          /* winPY */
1753   true,                         /* external_gui */
1754   true,                         /* siginthand */
1755   false,                        /* reuse helper */
1756   false,                        /* auto reinitialize */
1757   false,                        /* keep thread alive */
1758   false,                        /* quiet */
1759   false,                        /* incentive product */
1760   "",                           /* after_load_script */
1761   0,                            /* multisample */
1762   1,                            /* window_visible */
1763   0,                            /* read_stdin */
1764   0,                            /* presentation */
1765   0,                            /* defer builds mode */
1766   0,                            /* full screen mode */
1767   -1,                           /* sphere mode */
1768   0,                            /* stereo capable */
1769   0,                            /* stereo mode */
1770   -1,                           /* zoom mode */
1771   0,                            /* launch_status */
1772   0,                            /* no quit */
1773   0,                            /* gldebug */
1774   false,                        /* no openvr stub */
1775 };
1776 
PyMOLOptions_New(void)1777 CPyMOLOptions *PyMOLOptions_New(void)
1778 {
1779   CPyMOLOptions *result = NULL;
1780   result = pymol::calloc<CPyMOLOptions>(1);
1781   if(result)
1782     *result = Defaults;
1783   return result;
1784 }
1785 
1786 #ifndef _PYMOL_NOPY
1787 void init_cmd(void);
1788 
init_python(int argc,char * argv[])1789 static void init_python(int argc, char *argv[])
1790 {
1791   Py_Initialize();
1792   if(argv) {
1793 #if PY_MAJOR_VERSION < 3
1794     PySys_SetArgv(argc, argv);
1795 #endif
1796   }
1797 
1798   PyEval_InitThreads();
1799 
1800   PyRun_SimpleString("import sys");
1801   PyRun_SimpleString("import os");
1802   PyRun_SimpleString("sys.path.insert(0,os.environ['PYMOL_PATH']+'/modules')");
1803 
1804   /* initialize our embedded C modules */
1805   init_cmd();
1806 
1807   PyRun_SimpleString("import pymol");
1808 
1809   /* parse arguments */
1810   PyRun_SimpleString("pymol.invocation.parse_args(sys.argv)");
1811 }
1812 
1813 
1814 /* WARNING: the routine below only works with the global singleton
1815    model -- not Python-enabled PyMOL instances */
1816 
PyMOLOptions_NewWithPython(int argc,char * argv[])1817 CPyMOLOptions *PyMOLOptions_NewWithPython(int argc, char *argv[])
1818 {
1819   CPyMOLOptions *result = PyMOLOptions_New();
1820 
1821   /* use Python to parse options based on the command line */
1822 
1823   init_python(argc, argv);
1824   PGetOptions(result);
1825   return result;
1826 }
1827 #endif
1828 
PyMOLOptions_Free(CPyMOLOptions * options)1829 void PyMOLOptions_Free(CPyMOLOptions * options)
1830 {
1831   FreeP(options);
1832 }
1833 
PyMOL_ResetProgress(CPyMOL * I)1834 void PyMOL_ResetProgress(CPyMOL * I)
1835 {
1836   I->ProgressChanged = true;
1837   UtilZeroMem(I->Progress, sizeof(int) * 6);
1838 }
1839 
PyMOL_SetProgress(CPyMOL * I,int offset,int current,int range)1840 void PyMOL_SetProgress(CPyMOL * I, int offset, int current, int range)
1841 {
1842   switch (offset) {
1843   case PYMOL_PROGRESS_SLOW:
1844   case PYMOL_PROGRESS_MED:
1845   case PYMOL_PROGRESS_FAST:
1846     if(current != I->Progress[offset]) {
1847       I->Progress[offset] = current;
1848       I->ProgressChanged = true;
1849     }
1850     if(range != I->Progress[offset + 1]) {
1851       I->Progress[offset + 1] = range;
1852       I->ProgressChanged = true;
1853     }
1854   }
1855 }
1856 
PyMOL_GetProgress(CPyMOL * I,int * progress,int reset)1857 int PyMOL_GetProgress(CPyMOL * I, int *progress, int reset)
1858 {
1859   int a;
1860   int result = I->ProgressChanged;
1861   for(a = 0; a < PYMOL_PROGRESS_SIZE; a++) {
1862     progress[a] = I->Progress[a];
1863   }
1864   if(reset)
1865     I->ProgressChanged = false;
1866   return result;
1867 }
1868 
PyMOL_GetProgressChanged(CPyMOL * I,int reset)1869 int PyMOL_GetProgressChanged(CPyMOL * I, int reset)
1870 {
1871   int result = I->ProgressChanged;
1872   if(reset)
1873     I->ProgressChanged = false;
1874   return result;
1875 }
1876 
_PyMOL_New(void)1877 static CPyMOL *_PyMOL_New(void)
1878 {
1879   CPyMOL *result = NULL;
1880 
1881   /* allocate global container */
1882 
1883   if((result = pymol::calloc<CPyMOL>(1))) {    /* all values initialized to zero */
1884 
1885     if((result->G = pymol::calloc<PyMOLGlobals>(1))) {
1886 
1887       result->G->PyMOL = result;        /* store the instance pointer */
1888 
1889       result->BusyFlag = false;
1890       result->InterruptFlag = false;
1891       PyMOL_ResetProgress(result);
1892 
1893 #ifndef _PYMOL_NOPY
1894 
1895       /* for the time being, the first PyMOL object created becomes
1896          the singleton object -- this is failsafe behavior designed to
1897          carry us through the transition to fully objectified PyMOL
1898          (PS note race in assignment covered by pymol2.pymol2_lock) */
1899 
1900       if(!SingletonPyMOLGlobals) {
1901         SingletonPyMOLGlobals = result->G;
1902       }
1903 #endif
1904 
1905       /* continue initialization */
1906 
1907     } else {
1908       FreeP(result);
1909     }
1910   }
1911   return result;
1912 }
1913 
_PyMOL_Config(CPyMOL * I)1914 static void _PyMOL_Config(CPyMOL * I)
1915 {
1916 #ifndef _PYMOL_NO_MAIN
1917   // also assign in PyMOL_DrawWithoutLock
1918   I->G->HaveGUI = I->G->Option->pmgui;
1919 #endif
1920   I->G->Security = I->G->Option->security;
1921 }
1922 
PyMOL_New(void)1923 CPyMOL *PyMOL_New(void)
1924 {
1925   CPyMOL *result = _PyMOL_New();
1926   if(result && result->G) {
1927     result->G->Option = pymol::calloc<CPyMOLOptions>(1);
1928     if(result->G->Option)
1929       (*result->G->Option) = Defaults;
1930     _PyMOL_Config(result);
1931   }
1932   return result;
1933 }
1934 
PyMOL_NewWithOptions(const CPyMOLOptions * option)1935 CPyMOL *PyMOL_NewWithOptions(const CPyMOLOptions * option)
1936 {
1937   CPyMOL *result = _PyMOL_New();
1938   if(result && result->G) {
1939     result->G->Option = pymol::calloc<CPyMOLOptions>(1);
1940     if(result->G->Option)
1941       *(result->G->Option) = *option;
1942     _PyMOL_Config(result);
1943   }
1944   result->G->StereoCapable = option->stereo_capable;
1945   return result;
1946 }
1947 
PyMOL_Start(CPyMOL * I)1948 void PyMOL_Start(CPyMOL * I)
1949 {
1950   PyMOLGlobals *G = I->G;
1951 
1952   // It's possible to change this from Python, functions which rely on
1953   // C locale should reset it before doing printf, atof, etc.
1954   std::setlocale(LC_NUMERIC, "C");
1955 
1956   G->Context = OVContext_New();
1957   G->Lexicon = OVLexicon_New(G->Context->heap);
1958 
1959   if(OVreturn_IS_ERROR(PyMOL_InitAPI(I))) {
1960     printf("ERROR: PyMOL internal C API initialization failed.\n");
1961   }
1962 
1963   // global lexicon "constants"
1964 #define LEX_CONSTANTS_IMPL
1965 #include "lex_constants.h"
1966 
1967   G->Feedback = new CFeedback(G, G->Option->quiet);
1968   WordInit(G);
1969   UtilInit(G);
1970   ColorInit(G);
1971   CGORendererInit(G);
1972   ShaderMgrInit(G);
1973   SettingInitGlobal(G, true, true, false);
1974   SettingSetGlobal_i(G, cSetting_internal_gui, G->Option->internal_gui);
1975   SettingSetGlobal_i(G, cSetting_internal_feedback, G->Option->internal_feedback);
1976   TextureInit(G);
1977   TypeInit(G);
1978   TextInit(G);
1979   CharacterInit(G);
1980   PlugIOManagerInit(G);
1981   SphereInit(G);
1982   // OpenVRInit() called in ExecutiveStereo
1983   OrthoInit(G, G->Option->show_splash);
1984   SceneInit(G);
1985   MovieScenesInit(G);
1986   WizardInit(G);                /* must come after ortho & scene */
1987   G->Movie = new CMovie(G);
1988   G->SelectorMgr = new CSelectorManager();
1989   G->Selector = new CSelector(G, G->SelectorMgr);
1990   SeqInit(G);
1991   SeekerInit(G);
1992   ButModeInit(G);
1993   ControlInit(G);
1994   AtomInfoInit(G);
1995   SculptCacheInit(G);
1996   VFontInit(G);
1997   ExecutiveInit(G);
1998   IsosurfInit(G);
1999   TetsurfInit(G);
2000   EditorInit(G);
2001 #ifdef TRACKER_UNIT_TEST
2002   TrackerUnitTest(G);
2003 #endif
2004 
2005   I->DrawnFlag = false;
2006   I->RedisplayFlag = true;
2007   G->Ready = true;
2008 }
2009 
2010 /* This function is necessary to be called from PyMOL_StartWithPython
2011    which is called before the PYMOL_API is instantiated, thus
2012    it is not necessary (and you can't) lock the API */
PyMOL_ConfigureShadersGL_WithoutLock(CPyMOL * I)2013 void PyMOL_ConfigureShadersGL_WithoutLock(CPyMOL * I){
2014     I->done_ConfigureShaders = false;
2015     // ShaderMgr->Config() moved to PyMOL_DrawWithoutLock
2016 }
2017 
2018 /* This function is called from CMol and needs to lock
2019    the PYMOL_API */
PyMOL_ConfigureShadersGL(CPyMOL * I)2020 void PyMOL_ConfigureShadersGL(CPyMOL * I){
2021   PYMOL_API_LOCK
2022     PyMOL_ConfigureShadersGL_WithoutLock(I);
2023   PYMOL_API_UNLOCK
2024 }
2025 
2026 #ifndef _PYMOL_NOPY
2027 
PyMOL_StartWithPython(CPyMOL * I)2028 void PyMOL_StartWithPython(CPyMOL * I)
2029 {
2030   PyMOL_Start(I);
2031 
2032   /* now locate all the C to Python function hooks and objects we need */
2033 
2034   PInit(I->G, false);
2035 
2036   /* and begin the initialization sequence */
2037 
2038   I->PythonInitStage = 1;
2039 }
2040 
2041 #endif
2042 
PyMOL_Stop(CPyMOL * I)2043 void PyMOL_Stop(CPyMOL * I)
2044 {
2045   PyMOLGlobals *G = I->G;
2046   G->Terminating = true;
2047   TetsurfFree(G);
2048   IsosurfFree(G);
2049   WizardFree(G);
2050   EditorFree(G);
2051   ExecutiveFree(G);
2052   VFontFree(G);
2053   SculptCacheFree(G);
2054   AtomInfoFree(G);
2055   ButModeFree(G);
2056   ControlFree(G);
2057   SeekerFree(G);
2058   SeqFree(G);
2059   DeleteP(G->Selector);
2060   DeleteP(G->SelectorMgr);
2061   DeleteP(G->Movie);
2062   SceneFree(G);
2063   MovieScenesFree(G);
2064   OrthoFree(G);
2065 #ifdef _PYMOL_OPENVR
2066   OpenVRFree(G);
2067 #endif
2068   DeleteP(G->ShaderMgr);
2069   SettingFreeGlobal(G);
2070   CharacterFree(G);
2071   TextFree(G);
2072   TypeFree(G);
2073   TextureFree(G);
2074   SphereFree(G);
2075   PlugIOManagerFree(G);
2076   PFree(G);
2077   CGORendererFree(G);
2078   ColorFree(G);
2079   UtilFree(G);
2080   WordFree(G);
2081   DeleteP(G->Feedback);
2082 
2083   PyMOL_PurgeAPI(I);
2084   /*    printf("%d \n", OVLexicon_GetNActive(G->Lexicon)); */
2085   OVLexicon_Del(G->Lexicon);
2086   OVContext_Del(G->Context);
2087 }
2088 
PyMOL_Free(CPyMOL * I)2089 void PyMOL_Free(CPyMOL * I)
2090 {
2091 #if !defined(_PYMOL_ACTIVEX) && !defined(_MACPYMOL_XCODE)
2092   PYMOL_API_LOCK
2093 #endif
2094     /* take PyMOL down gracefully */
2095     PyMOLOptions_Free(I->G->Option);
2096 
2097 #ifndef _PYMOL_NOPY
2098   FreeP(I->G->P_inst);
2099   if(I->G == SingletonPyMOLGlobals)
2100     SingletonPyMOLGlobals = NULL;
2101 #endif
2102 
2103   FreeP(I->G);
2104   FreeP(I);
2105   return;
2106 #if !defined(_PYMOL_ACTIVEX) && !defined(_MACPYMOL_XCODE)
2107   PYMOL_API_UNLOCK;
2108 #endif
2109 }
2110 
PyMOL_GetGlobals(CPyMOL * I)2111 struct _PyMOLGlobals *PyMOL_GetGlobals(CPyMOL * I)
2112 {
2113   return I->G;
2114 }
2115 
PyMOL_GetGlobalsHandle(CPyMOL * I)2116 struct _PyMOLGlobals **PyMOL_GetGlobalsHandle(CPyMOL * I)
2117 {
2118   return &(I->G);
2119 }
2120 
PyMOL_LockAPIAndUnblock(CPyMOL * I)2121 void PyMOL_LockAPIAndUnblock(CPyMOL * I)
2122 {
2123   PyMOLGlobals *G = I->G;
2124   (void)G;
2125   PLockAPIAndUnblock(G);
2126 }
2127 
PyMOL_BlockAndUnlockAPI(CPyMOL * I)2128 void PyMOL_BlockAndUnlockAPI(CPyMOL * I)
2129 {
2130   PyMOLGlobals *G = I->G;
2131   (void)G;
2132   PBlockAndUnlockAPI(G);
2133 }
2134 
PyMOL_AdaptToHardware(CPyMOL * I)2135 void PyMOL_AdaptToHardware(CPyMOL * I)
2136 {
2137   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2138   if(G->HaveGUI) {
2139     PyMOL_PushValidContext(I);
2140     {
2141       char *vendor = (char *) glGetString(GL_VENDOR);
2142       char *renderer = (char *) glGetString(GL_RENDERER);
2143       char *version = (char *) glGetString(GL_VERSION);
2144       if(vendor && version) {
2145         /* work around broken lighting under Windows GDI Generic */
2146         if((strcmp(vendor, "Microsoft Corporation") == 0) &&
2147            (strcmp(renderer, "GDI Generic") == 0)) {
2148           ExecutiveSetSettingFromString(I->G, cSetting_light_count, "1", "", 0, 1, 0);
2149           ExecutiveSetSettingFromString(I->G, cSetting_spec_direct, "0.7", "", 0, 1, 0);
2150         }
2151       }
2152     }
2153     PyMOL_PopValidContext(I);
2154   }
2155 PYMOL_API_UNLOCK}
2156 
setup_gl_state(void)2157 static void setup_gl_state(void)
2158 {
2159 
2160   /* get us into a well defined GL state */
2161 
2162   /*glMatrixMode(GL_PROJECTION);
2163      glLoadIdentity();
2164      glMatrixMode(GL_MODELVIEW);
2165      glLoadIdentity(); */
2166 
2167 #ifndef PURE_OPENGL_ES_2
2168   glDisable(GL_ALPHA_TEST);
2169   glDisable(GL_COLOR_LOGIC_OP);
2170   glDisable(GL_COLOR_MATERIAL);
2171   glDisable(GL_FOG);
2172   glDisable(GL_LIGHTING);
2173   glDisable(GL_LIGHT0);
2174   glDisable(GL_LIGHT1);
2175   glDisable(GL_LINE_SMOOTH);
2176   glDisable(GL_NORMALIZE);
2177 #endif
2178 
2179   glDisable(GL_BLEND);
2180   glDisable(GL_CULL_FACE);
2181   glDisable(GL_DEPTH_TEST);
2182   glDisable(GL_DITHER);
2183 #ifndef PURE_OPENGL_ES_2
2184   glDisable(GL_POLYGON_SMOOTH);
2185 #endif
2186 }
2187 void PyMOL_DrawWithoutLock(CPyMOL * I);
2188 
PyMOL_Draw(CPyMOL * I)2189 void PyMOL_Draw(CPyMOL * I){
2190   PYMOL_API_LOCK_MODAL
2191   PyMOL_DrawWithoutLock(I);
2192   PYMOL_API_UNLOCK
2193 }
2194 
PyMOL_LaunchStatus_Feedback(PyMOLGlobals * G)2195 static void PyMOL_LaunchStatus_Feedback(PyMOLGlobals * G)
2196 {
2197   G->LaunchStatus |= G->Option->launch_status;
2198 
2199   if(G->StereoCapable) {
2200     OrthoAddOutput(G,
2201         " OpenGL quad-buffer stereo 3D detected and enabled.\n");;
2202   } else {
2203     if(G->LaunchStatus & cPyMOLGlobals_LaunchStatus_StereoFailed) {
2204       G->Feedback->addColored(
2205           "Error: The requested stereo 3D visualization mode is not available.\n",
2206           FB_Errors);
2207     }
2208   }
2209 
2210   if(G->LaunchStatus & cPyMOLGlobals_LaunchStatus_MultisampleFailed) {
2211     G->Feedback->addColored(
2212         "Error: The requested multisampling mode is not available.\n",
2213         FB_Errors);
2214   }
2215 }
2216 
2217 #ifndef PURE_OPENGL_ES_2
check_gl_stereo_capable(PyMOLGlobals * G)2218 static void check_gl_stereo_capable(PyMOLGlobals * G)
2219 {
2220   // quad buffer stereo available?
2221   GLboolean state;
2222   glGetBooleanv(GL_STEREO, &state);
2223   G->StereoCapable = state || G->Option->force_stereo > 0;
2224   if (!state && G->Option->force_stereo > 0) {
2225     printf("Warning: forcing stereo despite GL_STEREO=0\n");
2226   }
2227 
2228   // stereo request feedback
2229   if (state && G->Option->stereo_mode == cStereo_default) {
2230     SettingSetGlobal_i(G, cSetting_stereo_mode, cStereo_quadbuffer);
2231   } else if (!state && G->Option->stereo_mode == cStereo_quadbuffer) {
2232     G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_StereoFailed;
2233   }
2234 
2235   // multisample request feedback
2236   if (G->Option->multisample) {
2237     GLint samplebuffers = 0;
2238     glGetIntegerv(GL_SAMPLE_BUFFERS, &samplebuffers);
2239     if (!samplebuffers) {
2240       G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_MultisampleFailed;
2241     }
2242   }
2243 
2244   // GL_BACK if GL_DOUBLEBUFFER else GL_FRONT
2245   // With QOpenGLWidget -> framebuffer object
2246   GLint buf;
2247   glGetIntegerv(GL_DRAW_BUFFER0, &buf);
2248   if (!buf) {
2249     printf("Warning: GL_DRAW_BUFFER0=0 -> using GL_BACK\n");
2250     buf = GL_BACK;
2251   }
2252   G->DRAW_BUFFER0 = buf;
2253 
2254   // double buffer check
2255   glGetBooleanv(GL_DOUBLEBUFFER, &state);
2256   if (!state && buf <= GL_BACK) {
2257     printf("Warning: GL_DOUBLEBUFFER=0\n");
2258   }
2259 
2260   // default framebuffer
2261   glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buf);
2262   G->ShaderMgr->default_framebuffer_id = buf;
2263 }
2264 #endif
2265 
PyMOL_DrawWithoutLock(CPyMOL * I)2266 void PyMOL_DrawWithoutLock(CPyMOL * I)
2267 {
2268   if (!I->done_ConfigureShaders) {
2269     I->done_ConfigureShaders = true;
2270 
2271     I->G->HaveGUI = I->G->Option->pmgui;
2272 
2273 #ifndef PURE_OPENGL_ES_2
2274     // stereo test with PyQt5 on Linux is broken (QTBUG-59636), so we
2275     // test for stereo here
2276     if (I->G->HaveGUI)
2277     {
2278       check_gl_stereo_capable(I->G);
2279     }
2280 #endif
2281 
2282     PyMOL_LaunchStatus_Feedback(I->G);
2283 
2284     I->G->ShaderMgr->Config();
2285 
2286     // OpenGL debugging (glewInit must be called first)
2287     if (I->G->Option->gldebug) {
2288 #ifdef GL_DEBUG_OUTPUT
2289       if (!glDebugMessageCallback) {
2290         printf("glDebugMessageCallback not available\n");
2291       } else {
2292         glDebugMessageCallback(gl_debug_proc, NULL);
2293         glEnable(GL_DEBUG_OUTPUT);
2294       }
2295 #else
2296       printf("GL_DEBUG_OUTPUT not available\n");
2297 #endif
2298     }
2299   }
2300 
2301   PyMOLGlobals * G = I->G;
2302   if(I->ModalDraw) {
2303     if(G->HaveGUI) {
2304       PyMOL_PushValidContext(I);
2305       setup_gl_state();
2306     }
2307     {
2308       PyMOLModalDrawFn *fn = I->ModalDraw;
2309       I->ModalDraw = NULL;      /* always resets to NULL! */
2310       fn(G);
2311     }
2312 
2313     if(G->HaveGUI) {
2314       PyMOL_PopValidContext(I);
2315     }
2316   } else {
2317 
2318     if(I->DraggedFlag) {
2319       if(ControlIdling(I->G)) {
2320         ExecutiveSculptIterateAll(I->G);
2321       }
2322       I->DraggedFlag = false;
2323     }
2324 
2325     if(G->HaveGUI) {
2326       PyMOL_PushValidContext(I);
2327 
2328       setup_gl_state();
2329 
2330       if(!I->DrawnFlag) {
2331         SceneSetCardInfo(G, (char *) glGetString(GL_VENDOR),
2332                          (char *) glGetString(GL_RENDERER),
2333                          (char *) glGetString(GL_VERSION));
2334         if(G->Option->show_splash && !G->Option->quiet) {
2335 
2336           PRINTFB(G, FB_OpenGL, FB_Results)
2337             " OpenGL graphics engine:\n"
2338             "  GL_VENDOR:   %s\n"
2339             "  GL_RENDERER: %s\n"
2340             "  GL_VERSION:  %s\n",
2341             (char *) glGetString(GL_VENDOR),
2342             (char *) glGetString(GL_RENDERER),
2343             (char *) glGetString(GL_VERSION) ENDFB(G);
2344           if(Feedback(G, FB_OpenGL, FB_Blather)) {
2345             printf("  GL_EXTENSIONS: %s\n", (char *) glGetString(GL_EXTENSIONS));
2346           }
2347         }
2348         I->DrawnFlag = true;
2349       }
2350     } else {
2351       I->DrawnFlag = true;
2352     }
2353 
2354     I->RedisplayFlag = false;
2355 
2356     OrthoBusyPrime(G);
2357     ExecutiveDrawNow(G);
2358 
2359     if(I->ImageRequestedFlag) {
2360       if(SceneHasImage(G)) {
2361         I->ImageReadyFlag = true;
2362         I->ImageRequestedFlag = false;
2363       } else {
2364         I->ImageReadyFlag = false;
2365       }
2366     } else if(I->ImageReadyFlag) {
2367       if(!SceneHasImage(G))
2368         I->ImageReadyFlag = false;
2369     }
2370 
2371     if(G->HaveGUI)
2372       PyMOL_PopValidContext(I);
2373   }
2374 }
2375 
PyMOL_Key(CPyMOL * I,unsigned char k,int x,int y,int modifiers)2376 void PyMOL_Key(CPyMOL * I, unsigned char k, int x, int y, int modifiers)
2377 {
2378   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2379   if(!WizardDoKey(G, k, x, y, modifiers))
2380     OrthoKey(G, k, x, y, modifiers);
2381   PyMOL_NeedRedisplay(G->PyMOL);
2382 PYMOL_API_UNLOCK}
2383 
PyMOL_Special(CPyMOL * I,int k,int x,int y,int modifiers)2384 void PyMOL_Special(CPyMOL * I, int k, int x, int y, int modifiers)
2385 {
2386   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2387 
2388   int grabbed = false;
2389   char buffer[255];
2390   (void)buffer;
2391   if(!grabbed)
2392     grabbed = WizardDoSpecial(G, (unsigned char) k, x, y, modifiers);
2393 
2394   switch (k) {
2395   case P_GLUT_KEY_UP:
2396   case P_GLUT_KEY_DOWN:
2397     grabbed = 1;
2398     OrthoSpecial(G, k, x, y, modifiers);
2399     break;
2400   case P_GLUT_KEY_LEFT:
2401   case P_GLUT_KEY_RIGHT:
2402     if(OrthoArrowsGrabbed(G)) {
2403       grabbed = 1;
2404       OrthoSpecial(G, k, x, y, modifiers);
2405     }
2406     break;
2407   }
2408 
2409 #ifndef _PYMOL_NOPY
2410   if(!grabbed) {
2411     sprintf(buffer, "_special %d,%d,%d,%d", k, x, y, modifiers);
2412     PLog(G, buffer, cPLog_pml);
2413     PParse(G, buffer);
2414     PFlush(G);
2415   }
2416 #endif
2417 
2418 PYMOL_API_UNLOCK}
2419 
PyMOL_Reshape(CPyMOL * I,int width,int height,int force)2420 void PyMOL_Reshape(CPyMOL * I, int width, int height, int force)
2421 {
2422   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2423 
2424   G->Option->winX = width;
2425   G->Option->winY = height;
2426 
2427   OrthoReshape(G, width, height, force);
2428 PYMOL_API_UNLOCK}
2429 
PyMOL_Idle(CPyMOL * I)2430 int PyMOL_Idle(CPyMOL * I)
2431 {
2432   int did_work = false;
2433   PYMOL_API_TRYLOCK PyMOLGlobals * G = I->G;
2434 
2435   I->DraggedFlag = false;
2436   if(I->IdleAndReady < IDLE_AND_READY) {
2437     if(I->DrawnFlag)
2438       I->IdleAndReady++;
2439   }
2440   if(I->FakeDragFlag == 1) {
2441     I->FakeDragFlag = false;
2442     OrthoFakeDrag(G);
2443     did_work = true;
2444   }
2445 
2446   if(ControlIdling(G)) {
2447     ExecutiveSculptIterateAll(G);
2448     ControlSdofIterate(G);
2449     did_work = true;
2450   }
2451 
2452   SceneIdle(G);
2453 
2454   if(SceneRovingCheckDirty(G)) {
2455     SceneRovingUpdate(G);
2456     did_work = true;
2457   }
2458 #ifndef _PYMOL_NOPY
2459   if(PFlush(G)) {
2460     did_work = true;
2461   }
2462 
2463   if(I->PythonInitStage > 0) {
2464     if(I->PythonInitStage < 2) {
2465       I->PythonInitStage++;
2466     } else {
2467       I->PythonInitStage = -1;
2468       PBlock(G);
2469 
2470       PXDecRef(PYOBJECT_CALLMETHOD
2471                (G->P_inst->obj, "adapt_to_hardware", "O", G->P_inst->obj));
2472 
2473       if(PyErr_Occurred())
2474         PyErr_Print();
2475 
2476       PXDecRef(PYOBJECT_CALLMETHOD(G->P_inst->obj, "exec_deferred", "O", G->P_inst->obj));
2477 
2478       if(PyErr_Occurred())
2479         PyErr_Print();
2480 
2481       PUnblock(G);
2482       PFlush(G);
2483     }
2484   }
2485 #endif
2486 
2487   /* reset the interrupt flag if we're not doing anything */
2488 
2489   if(!(did_work || I->ModalDraw))
2490     if(PyMOL_GetInterrupt(I, false))
2491       PyMOL_SetInterrupt(I, false);
2492 
2493   PYMOL_API_UNLOCK_NO_FLUSH return (did_work || I->ModalDraw);
2494 }
2495 
PyMOL_ExpireIfIdle(CPyMOL * I)2496 void PyMOL_ExpireIfIdle(CPyMOL * I)
2497 {
2498   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2499   int final_init_done = true;
2500 #ifndef _PYMOL_NOPY
2501   final_init_done = (I->PythonInitStage == -1);
2502 #endif
2503 
2504   if(!G->HaveGUI) {
2505     if(final_init_done) {
2506       if(!OrthoCommandWaiting(G)) {
2507         if((!G->Option->keep_thread_alive) && (!G->Option->read_stdin)) {
2508           I->ExpireCount++;
2509           if(I->ExpireCount == 10) {
2510             PParse(G, "_quit");
2511           }
2512         }
2513       }
2514     }
2515   }
2516   PYMOL_API_UNLOCK;
2517 }
2518 
PyMOL_NeedFakeDrag(CPyMOL * I)2519 void PyMOL_NeedFakeDrag(CPyMOL * I)
2520 {
2521   I->FakeDragFlag = true;
2522 }
2523 
PyMOL_NeedRedisplay(CPyMOL * I)2524 void PyMOL_NeedRedisplay(CPyMOL * I)
2525 {
2526   I->RedisplayFlag = true;
2527 }
2528 
PyMOL_NeedSwap(CPyMOL * I)2529 void PyMOL_NeedSwap(CPyMOL * I)
2530 {
2531   I->SwapFlag = true;
2532 }
2533 
PyMOL_NeedReshape(CPyMOL * I,int mode,int x,int y,int width,int height)2534 void PyMOL_NeedReshape(CPyMOL * I, int mode, int x, int y, int width, int height)
2535 {
2536   PyMOLGlobals *G = I->G;
2537   if(width < 0) {
2538     if (!G->HaveGUI)
2539       return;
2540 
2541     width = SceneGetBlock(G)->getWidth();
2542     if(SettingGetGlobal_b(G, cSetting_internal_gui))
2543       width += DIP2PIXEL(SettingGetGlobal_i( G, cSetting_internal_gui_width));
2544   }
2545 
2546   /* if height is negative, force a reshape based on the current height */
2547 
2548   if(height < 0) {
2549     int internal_feedback;
2550     height = SceneGetBlock(G)->getHeight();
2551     internal_feedback = SettingGetGlobal_i(G, cSetting_internal_feedback);
2552     if(internal_feedback)
2553       height += (internal_feedback - 1) * cOrthoLineHeight + cOrthoBottomSceneMargin;
2554     if(SettingGetGlobal_b(G, cSetting_seq_view)
2555        && !SettingGetGlobal_b(G, cSetting_seq_view_overlay)) {
2556       height += SeqGetHeight(G);
2557     }
2558     height += MovieGetPanelHeight(G);
2559   }
2560 
2561   if(G->HaveGUI) {
2562     float sf = DIP2PIXEL(1);
2563 
2564     I->Reshape[1] = x / sf;
2565     I->Reshape[2] = y / sf;
2566     I->Reshape[3] = width / sf;
2567     I->Reshape[4] = height / sf;
2568 
2569     I->ReshapeFlag = true;
2570     I->Reshape[0] = mode;
2571     PyMOL_NeedRedisplay(I);
2572   } else {
2573     /* if no gui, then force immediate reshape */
2574     PyMOLGlobals *G = I->G;
2575 
2576     G->Option->winX = width;
2577     G->Option->winY = height;
2578 
2579     OrthoReshape(G, width, height, true);
2580   }
2581 }
2582 
PyMOL_GetIdleAndReady(CPyMOL * I)2583 int PyMOL_GetIdleAndReady(CPyMOL * I)
2584 {
2585   return (I->IdleAndReady == IDLE_AND_READY);
2586 }
2587 
PyMOL_GetReshape(CPyMOL * I)2588 int PyMOL_GetReshape(CPyMOL * I)
2589 {
2590   return I->ReshapeFlag;
2591 }
2592 
PyMOL_GetReshapeInfo(CPyMOL * I,int reset)2593 PyMOLreturn_int_array PyMOL_GetReshapeInfo(CPyMOL * I, int reset)
2594 {
2595   PyMOLreturn_int_array result = { PyMOLstatus_SUCCESS, PYMOL_RESHAPE_SIZE, NULL };
2596   PYMOL_API_LOCK
2597   if(reset)
2598     I->ReshapeFlag = false;
2599   result.array = VLAlloc(int, PYMOL_RESHAPE_SIZE);
2600   if(!result.array) {
2601     result.status = PyMOLstatus_FAILURE;
2602   } else {
2603     int a;
2604     for(a = 0; a < PYMOL_RESHAPE_SIZE; a++)
2605       result.array[a] = I->Reshape[a];
2606   }
2607 
2608  PYMOL_API_UNLOCK
2609    return result;
2610 }
2611 
PyMOL_SetPassive(CPyMOL * I,int onOff)2612 void PyMOL_SetPassive(CPyMOL * I, int onOff)
2613 {
2614   I->PassiveFlag = onOff;
2615 }
2616 
PyMOL_SetClickReady(CPyMOL * I,const char * name,int index,int button,int mod,int x,int y,const float * pos,int state)2617 void PyMOL_SetClickReady(CPyMOL * I, const char *name, int index, int button, int mod, int x,
2618                          int y, const float *pos, int state)
2619 {
2620 
2621   if(name && name[0] && (index >= 0)) {
2622     I->ClickReadyFlag = true;
2623     strcpy(I->ClickedObject, name);
2624     I->ClickedIndex = index;
2625     I->ClickedButton = button;
2626     I->ClickedModifiers = mod;
2627     I->ClickedX = x;
2628     I->ClickedY = y;
2629   } else {
2630     I->ClickedObject[0] = 0;
2631     I->ClickReadyFlag = true;
2632     I->ClickedX = x;
2633     I->ClickedY = y;
2634     I->ClickedIndex = index;
2635     I->ClickedButton = button;
2636     I->ClickedModifiers = mod;
2637   }
2638   if(pos) {
2639     I->ClickedHavePos = true;
2640     copy3f(pos, I->ClickedPos);
2641     I->ClickedPosState = state;
2642   } else {
2643     I->ClickedHavePos = false;
2644     zero3f(I->ClickedPos);
2645     I->ClickedPosState = 0;
2646   }
2647 }
2648 
PyMOL_GetClickReady(CPyMOL * I,int reset)2649 int PyMOL_GetClickReady(CPyMOL * I, int reset)
2650 {
2651   int result = I->ClickReadyFlag;
2652   if(reset) {
2653     I->ClickReadyFlag = false;
2654   }
2655   return result;
2656 }
2657 
PyMOL_GetClickString(CPyMOL * I,int reset)2658 char *PyMOL_GetClickString(CPyMOL * I, int reset)
2659 {
2660   char *result = NULL;
2661   PYMOL_API_LOCK int ready = I->ClickReadyFlag;
2662   if(reset)
2663     I->ClickReadyFlag = false;
2664   if(ready) {
2665     result = pymol::malloc<char>(OrthoLineLength + 1);
2666     if(result) {
2667       WordType butstr = "left", modstr = "", posstr = "";
2668       result[0] = 0;
2669       switch (I->ClickedButton) {
2670       case P_GLUT_SINGLE_LEFT:
2671         strcpy(butstr, "single_left");
2672         break;
2673       case P_GLUT_SINGLE_MIDDLE:
2674         strcpy(butstr, "single_middle");
2675         break;
2676       case P_GLUT_SINGLE_RIGHT:
2677         strcpy(butstr, "single_right");
2678         break;
2679       case P_GLUT_DOUBLE_LEFT:
2680         strcpy(butstr, "double_left");
2681         break;
2682       case P_GLUT_DOUBLE_MIDDLE:
2683         strcpy(butstr, "double_middle");
2684         break;
2685       case P_GLUT_DOUBLE_RIGHT:
2686         strcpy(butstr, "double_right");
2687         break;
2688       }
2689       if(cOrthoCTRL & I->ClickedModifiers) {
2690         if(modstr[0])
2691           strcat(modstr, " ");
2692         strcat(modstr, "ctrl");
2693       }
2694       if(cOrthoALT & I->ClickedModifiers) {
2695         if(modstr[0])
2696           strcat(modstr, " ");
2697         strcat(modstr, "alt");
2698       }
2699       if(cOrthoSHIFT & I->ClickedModifiers) {
2700         if(modstr[0])
2701           strcat(modstr, " ");
2702         strcat(modstr, "shift");
2703       }
2704       if(I->ClickedHavePos) {
2705 	sprintf(posstr,"px=%.7g\npy=%.7g\npz=%.7g\nstate=%d",I->ClickedPos[0],I->ClickedPos[1],I->ClickedPos[2],I->ClickedPosState);
2706       }
2707       if(!I->ClickedObject[0]) {
2708         sprintf(result,
2709                 "type=none\nclick=%s\nmod_keys=%s\nx=%d\ny=%d\n%s",
2710                 butstr, modstr, I->ClickedX, I->ClickedY,posstr);
2711       } else {
2712         ObjectMolecule *obj = ExecutiveFindObjectMoleculeByName(I->G, I->ClickedObject);
2713         if(obj && (I->ClickedIndex < obj->NAtom)) {
2714           AtomInfoType *ai = obj->AtomInfo + I->ClickedIndex;
2715           char inscode_str[2] = { ai->inscode, '\0' };
2716           sprintf(result,
2717                   "type=object:molecule\nobject=%s\nindex=%d\nrank=%d\nid=%d\nsegi=%s\nchain=%s\nresn=%s\nresi=%d%s\nname=%s\nalt=%s\nclick=%s\nmod_keys=%s\nx=%d\ny=%d\n%s",
2718                   I->ClickedObject,
2719                   I->ClickedIndex + 1,
2720                   ai->rank,
2721                   ai->id,
2722                   LexStr(I->G, ai->segi),
2723                   LexStr(I->G, ai->chain),
2724                   LexStr(I->G, ai->resn),
2725                   ai->resv, inscode_str,
2726                   LexStr(I->G, ai->name),
2727                   ai->alt, butstr, modstr, I->ClickedX, I->ClickedY, posstr);
2728         }
2729       }
2730     }
2731   }
2732   PYMOL_API_UNLOCK return (result);
2733 }
2734 
PyMOL_GetImageReady(CPyMOL * I,int reset)2735 int PyMOL_GetImageReady(CPyMOL * I, int reset)
2736 {
2737   int result = I->ImageReadyFlag;
2738   if(reset) {
2739     I->ImageReadyFlag = false;
2740   }
2741   return result;
2742 }
2743 
PyMOL_GetImageInfo(CPyMOL * I)2744 PyMOLreturn_int_array PyMOL_GetImageInfo(CPyMOL * I)
2745 {
2746   PyMOLreturn_int_array result = { PyMOLstatus_SUCCESS, 2, NULL };
2747   PYMOL_API_LOCK result.array = VLAlloc(int, 2);
2748   if(!result.array) {
2749     result.status = PyMOLstatus_FAILURE;
2750   } else {
2751     std::tie(result.array[0], result.array[1]) = SceneGetImageSize(I->G);
2752   }
2753   PYMOL_API_UNLOCK return result;
2754 }
2755 
PyMOL_GetImageData(CPyMOL * I,int width,int height,int row_bytes,void * buffer,int mode,int reset)2756 int PyMOL_GetImageData(CPyMOL * I,
2757                        int width, int height,
2758                        int row_bytes, void *buffer, int mode, int reset)
2759 {
2760   int ok = true;
2761   PYMOL_API_LOCK if(reset)
2762     I->ImageReadyFlag = false;
2763   ok = SceneCopyExternal(I->G, width, height, row_bytes, (unsigned char *) buffer, mode);
2764   PYMOL_API_UNLOCK return get_status_ok(ok);
2765 }
2766 
PyMOL_GetImageDataReturned(CPyMOL * I,int width,int height,int row_bytes,int mode,int reset)2767 PyMOLreturn_int_array PyMOL_GetImageDataReturned(CPyMOL * I,
2768                        int width, int height,
2769                        int row_bytes, int mode, int reset)
2770 {
2771   PyMOLreturn_int_array result = { PyMOLstatus_SUCCESS, 0, NULL };
2772   int ok = true;
2773   int size;
2774   void *buffer;
2775   PYMOL_API_LOCK
2776     if(reset){
2777       I->ImageReadyFlag = false;
2778     }
2779   size = width*height;
2780   buffer = VLAlloc(int, size);
2781   ((int*)buffer)[0] = ('A'<<24)|('B'<<16)|('G'<<8)|'R';
2782   ok = SceneCopyExternal(I->G, width, height, row_bytes, (unsigned char *) buffer, mode);
2783   if(ok) {
2784     result.array = (int*) buffer;
2785     result.size = size;
2786   } else {
2787     result.status = PyMOLstatus_FAILURE;
2788   }
2789 
2790   PYMOL_API_UNLOCK return result;
2791 }
2792 
PyMOL_FreeResultString(CPyMOL * I,char * st)2793 int PyMOL_FreeResultString(CPyMOL * I, char *st)
2794 {
2795   PYMOL_API_LOCK FreeP(st);
2796   PYMOL_API_UNLOCK return get_status_ok((st != NULL));
2797 }
2798 
PyMOL_GetRedisplay(CPyMOL * I,int reset)2799 int PyMOL_GetRedisplay(CPyMOL * I, int reset)
2800 {
2801   int result = false;
2802 
2803   PYMOL_API_TRYLOCK PyMOLGlobals * G = I->G;
2804   result = I->RedisplayFlag;
2805 
2806   if(result) {
2807     if(SettingGet_b(G, NULL, NULL, cSetting_defer_updates)) {
2808       result = false;
2809     } else {
2810       if(reset)
2811         I->RedisplayFlag = false;
2812     }
2813   }
2814   PYMOL_API_UNLOCK_NO_FLUSH return (result || I->ModalDraw);    /* always true when ModalDraw is set */
2815 }
2816 
PyMOL_GetPassive(CPyMOL * I,int reset)2817 int PyMOL_GetPassive(CPyMOL * I, int reset)
2818 {                               /* lock intentionally omitted */
2819   int result = I->PassiveFlag;
2820   if(reset)
2821     I->PassiveFlag = false;
2822   return result;
2823 }
2824 
PyMOL_GetModalDraw(CPyMOL * I)2825 int PyMOL_GetModalDraw(CPyMOL * I)
2826 {
2827   if(I)
2828     return (I->ModalDraw != NULL);
2829   return false;
2830 }
2831 
PyMOL_SetModalDraw(CPyMOL * I,PyMOLModalDrawFn * fn)2832 void PyMOL_SetModalDraw(CPyMOL * I, PyMOLModalDrawFn * fn)
2833 {
2834   I->ModalDraw = fn;
2835 }
2836 
PyMOL_GetSwap(CPyMOL * I,int reset)2837 int PyMOL_GetSwap(CPyMOL * I, int reset)
2838 {                               /* lock intentionally omitted */
2839   int result = I->SwapFlag;
2840   if(reset)
2841     I->SwapFlag = false;
2842   return result;
2843 }
2844 
PyMOL_GetBusy(CPyMOL * I,int reset)2845 int PyMOL_GetBusy(CPyMOL * I, int reset)
2846 {                               /* lock intentionally omitted */
2847   int result = I->BusyFlag;
2848   if(reset)
2849     PyMOL_SetBusy(I, false);
2850   return result;
2851 }
2852 
PyMOL_SetBusy(CPyMOL * I,int value)2853 void PyMOL_SetBusy(CPyMOL * I, int value)
2854 {                               /* lock intentionally omitted */
2855   if(!I->BusyFlag)
2856     /* if we weren't busy before, then reset the progress indicators */
2857     PyMOL_ResetProgress(I);
2858 
2859   I->BusyFlag = value;
2860 }
2861 
PyMOL_GetInterrupt(CPyMOL * I,int reset)2862 int PyMOL_GetInterrupt(CPyMOL * I, int reset)
2863 {                               /* lock intentionally omitted */
2864   if(I) {
2865     int result = I->InterruptFlag;
2866 
2867     if(reset)
2868       PyMOL_SetInterrupt(I, false);
2869     return result;
2870   } else
2871     return false;
2872 }
2873 
PyMOL_SetInterrupt(CPyMOL * I,int value)2874 void PyMOL_SetInterrupt(CPyMOL * I, int value)
2875 {                               /* lock intentionally omitted */
2876   if(I) {
2877     I->InterruptFlag = value;
2878     if(I->G)
2879       I->G->Interrupt = value;
2880   }
2881 }
2882 
PyMOL_Drag(CPyMOL * I,int x,int y,int modifiers)2883 void PyMOL_Drag(CPyMOL * I, int x, int y, int modifiers)
2884 {
2885   PYMOL_API_LOCK OrthoDrag(I->G, x, y, modifiers);
2886   I->DraggedFlag = true;
2887 PYMOL_API_UNLOCK}
2888 
2889 /*
2890  * Mouse button and keyboard press handler
2891  *
2892  * button: mouse button or key code
2893  * state:
2894  *   -2 = key press with GLUT_KEY_* special code
2895  *   -1 = key press with ascii code
2896  *    0 = mouse down
2897  *    1 = mouse up
2898  * x, y: mouse pointer position
2899  * modifiers: SHIFT/CTRL/ALT bitmask
2900  */
PyMOL_Button(CPyMOL * I,int button,int state,int x,int y,int modifiers)2901 void PyMOL_Button(CPyMOL * I, int button, int state, int x, int y, int modifiers)
2902 {
2903   PYMOL_API_LOCK
2904     if (state == -1) {
2905       PyMOL_Key(I, (unsigned char)button, x, y, modifiers);
2906     } else if (state == -2) {
2907       PyMOL_Special(I, button, x, y, modifiers);
2908     } else {
2909       OrthoButton(I->G, button, state, x, y, modifiers);
2910     }
2911 PYMOL_API_UNLOCK}
2912 
PyMOL_SetSwapBuffersFn(CPyMOL * I,PyMOLSwapBuffersFn * fn)2913 void PyMOL_SetSwapBuffersFn(CPyMOL * I, PyMOLSwapBuffersFn * fn)
2914 {
2915   I->SwapFn = fn;
2916 }
2917 
PyMOL_SwapBuffers(CPyMOL * I)2918 void PyMOL_SwapBuffers(CPyMOL * I)
2919 {
2920   if(I->SwapFn && I->G->ValidContext) {
2921     I->SwapFn();
2922     I->SwapFlag = false;
2923   } else {
2924     I->SwapFlag = true;
2925   }
2926 }
2927 
PyMOL_RunTest(CPyMOL * I,int group,int test)2928 void PyMOL_RunTest(CPyMOL * I, int group, int test)
2929 {
2930   PYMOL_API_LOCK TestPyMOLRun(I->G, group, test);
2931 PYMOL_API_UNLOCK}
2932 
PyMOL_PushValidContext(CPyMOL * I)2933 void PyMOL_PushValidContext(CPyMOL * I)
2934 {
2935   if(I && I->G)
2936     I->G->ValidContext++;
2937 }
2938 
PyMOL_PopValidContext(CPyMOL * I)2939 void PyMOL_PopValidContext(CPyMOL * I)
2940 {
2941   if(I && I->G && (I->G->ValidContext > 0))
2942     I->G->ValidContext--;
2943 }
2944 
PyMOL_SetStereoCapable(CPyMOL * I,int stereoCapable)2945 void PyMOL_SetStereoCapable(CPyMOL * I, int stereoCapable){
2946   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2947   G->StereoCapable = stereoCapable;
2948   if (SettingGetGlobal_b(I->G, cSetting_stereo_mode)==0){
2949     /* if users haven't set stereo_mode, then set it to default */
2950     if (G->StereoCapable){
2951       SettingSetGlobal_i(I->G, cSetting_stereo_mode, cStereo_quadbuffer);      /* quadbuffer if we can */
2952     } else {
2953       SettingSetGlobal_i(I->G, cSetting_stereo_mode, cStereo_crosseye);      /* otherwise crosseye by default */
2954     }
2955   } else if (G->StereoCapable && SettingGetGlobal_b(G, cSetting_stereo)){
2956     SettingSetGlobal_i(I->G, cSetting_stereo_mode, SettingGetGlobal_b(I->G, cSetting_stereo_mode));
2957   }
2958   SceneUpdateStereo(I->G);
2959   PYMOL_API_UNLOCK
2960 }
2961 
PyMOL_InitializeCMol(CPyMOL * I)2962 void PyMOL_InitializeCMol(CPyMOL * I){
2963   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2964   /* Set stereo_mode to 0, so that PyMOL_SetStereoCapable()
2965      can determine whether user has changed the stereo_mode.  If
2966      users have not changed it, then set to quadbuffer if we can,
2967      or crosseye by default (see above) */
2968   SettingSetGlobal_i(G, cSetting_stereo_mode, 0);
2969   PYMOL_API_UNLOCK
2970 }
2971 
PyMOL_SetDefaultMouse(CPyMOL * I)2972 void PyMOL_SetDefaultMouse(CPyMOL * I)
2973 {
2974   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
2975 
2976   ButModeSet(G, cButModeLeftNone, cButModeRotXYZ);
2977   ButModeSet(G, cButModeMiddleNone, cButModeTransXY);
2978   ButModeSet(G, cButModeRightNone, cButModeTransZ);
2979 
2980   ButModeSet(G, cButModeLeftShft, cButModePotentialClick);
2981   ButModeSet(G, cButModeMiddleShft, cButModePotentialClick);
2982   ButModeSet(G, cButModeRightShft, cButModeClipNF);
2983 
2984   ButModeSet(G, cButModeLeftCtrl, cButModePotentialClick);
2985   ButModeSet(G, cButModeMiddleCtrl, cButModePotentialClick);
2986   ButModeSet(G, cButModeRightCtrl, cButModePotentialClick);
2987 
2988   ButModeSet(G, cButModeLeftCtSh, cButModePotentialClick);
2989   ButModeSet(G, cButModeMiddleCtSh, cButModePotentialClick);
2990   ButModeSet(G, cButModeRightCtSh, cButModePotentialClick);
2991 
2992   ButModeSet(G, cButModeWheelNone, cButModeScaleSlab);
2993   ButModeSet(G, cButModeWheelShft, cButModeMoveSlab);
2994   ButModeSet(G, cButModeWheelCtrl, cButModeMoveSlabAndZoom);
2995   ButModeSet(G, cButModeWheelCtSh, cButModeTransZ);
2996 
2997   ButModeSet(G, cButModeMiddleCtSh, cButModeOrigAt); /* SET TWICE?!? */
2998 
2999   ButModeSet(G, cButModeLeftSingle, cButModeSimpleClick);
3000   ButModeSet(G, cButModeMiddleSingle, cButModeCent);
3001   ButModeSet(G, cButModeRightSingle, cButModeSimpleClick);
3002 
3003   ButModeSet(G, cButModeLeftDouble, cButModeSimpleClick);
3004   ButModeSet(G, cButModeRightDouble, cButModeSimpleClick);
3005 
3006   {
3007     int a;
3008     for(a = cButModeLeftShftDouble; a <= cButModeRightCtrlAltShftSingle; a++) {
3009       ButModeSet(G, a, cButModeSimpleClick);
3010     }
3011     for(a = cButModeLeftAlt; a <= cButModeRightCtrlAltShft; a++) {
3012       ButModeSet(G, a, cButModePotentialClick);
3013     }
3014 
3015   }
3016   G->Feedback->currentMask(FB_Scene) &= ~(FB_Results); /* suppress click messages */
3017 PYMOL_API_UNLOCK}
3018 
PyMOL_CmdRock(CPyMOL * I,int mode)3019 PyMOLreturn_status PyMOL_CmdRock(CPyMOL * I, int mode){
3020   PyMOLreturn_status result = { PyMOLstatus_SUCCESS };
3021   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
3022   ControlRock(G, mode);
3023   PYMOL_API_UNLOCK return result;
3024 }
3025 
3026 
PyMOL_CmdGetNames(CPyMOL * I,int mode,const char * s0,int enabled_only)3027 PyMOLreturn_string_array PyMOL_CmdGetNames(CPyMOL * I, int mode, const char *s0, int enabled_only){
3028   PyMOLreturn_string_array result = { PyMOLstatus_FAILURE };
3029   PYMOL_API_LOCK PyMOLGlobals * G = I->G;
3030   result = return_result(ExecutiveGetNames(G, mode, enabled_only, s0));
3031   PYMOL_API_UNLOCK
3032   return (result);
3033 }
3034 
PyMOL_CmdMapNew(CPyMOL * I,const char * name,int type,float grid_spacing,const char * selection,int state,int normalize,int zoom,int quiet)3035 PyMOLreturn_status PyMOL_CmdMapNew(CPyMOL * I, const char *name, int type, float grid_spacing,
3036 				   const char *selection, int state, int normalize,
3037 				   int zoom, int quiet){
3038   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
3039   float minCorner[3], maxCorner[3];
3040   PYMOL_API_LOCK
3041 
3042   minCorner[0] = minCorner[1] = minCorner[2] = 0.;
3043   maxCorner[0] = maxCorner[1] = maxCorner[2] = 1.;
3044   auto res = ExecutiveMapNew(I->G, name, type, grid_spacing,
3045       selection, -1., minCorner, maxCorner, state, 0, quiet, 0, normalize, 1.,
3046       -1., 0.);
3047   result.status = get_status_ok(static_cast<bool>(res));
3048 
3049   PYMOL_API_UNLOCK return result;
3050 }
3051 
3052 #ifdef _PYMOL_LIB
PyMOL_SetIsEnabledCallback(CPyMOL * I,void * CallbackObject,void (* enabledCallback)(void *,const char *,int))3053 PyMOLreturn_status PyMOL_SetIsEnabledCallback(CPyMOL * I, void *CallbackObject, void (*enabledCallback)(void *, const char *, int )){
3054   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
3055   PYMOL_API_LOCK
3056     I->G->CallbackObject = CallbackObject;
3057     I->G->enabledCallback = enabledCallback;
3058   result.status =  PyMOLstatus_SUCCESS;
3059   PYMOL_API_UNLOCK
3060   return result;
3061 }
3062 
PyMOL_GetRepsInSceneForObject(CPyMOL * I,const char * name)3063 PyMOLreturn_int_array PyMOL_GetRepsInSceneForObject(CPyMOL * I, const char *name){
3064   PyMOLreturn_int_array result = { PyMOLstatus_SUCCESS, 0, NULL };
3065   int *retarr = 0;
3066   PYMOL_API_LOCK
3067     retarr = ExecutiveGetRepsInSceneForObject(I->G, name);
3068   if(!retarr) {
3069     result.status = PyMOLstatus_FAILURE;
3070   } else {
3071     result.size = VLAGetSize(retarr);
3072     result.array = retarr;
3073   }
3074   PYMOL_API_UNLOCK return result;
3075 }
3076 
PyMOL_GetRepsForObject(CPyMOL * I,const char * name)3077 PyMOLreturn_int_array PyMOL_GetRepsForObject(CPyMOL * I, const char *name){
3078   PyMOLreturn_int_array result = { PyMOLstatus_SUCCESS, 0, NULL };
3079   int *retarr = 0;
3080   PYMOL_API_LOCK
3081     retarr = ExecutiveGetRepsForObject(I->G, name);
3082   if(!retarr) {
3083     result.status = PyMOLstatus_FAILURE;
3084   } else {
3085     result.size = VLAGetSize(retarr);
3086     result.array = retarr;
3087   }
3088   PYMOL_API_UNLOCK return result;
3089 }
3090 
3091 static OVreturn_word get_button_code(CPyMOL * I, char *code);
3092 static OVreturn_word get_button_mod_code(CPyMOL * I, char *modcode);
3093 static OVreturn_word get_button_action_code(CPyMOL * I, char *actioncode);
3094 static OVreturn_word get_mouse_mode(CPyMOL * I, char *mousemode);
3095 
PyMOL_SetButton(CPyMOL * I,const char * buttonarg,const char * modifierarg,const char * actionarg)3096 PyMOLreturn_status PyMOL_SetButton(CPyMOL * I, const char *buttonarg, const char *modifierarg, const char *actionarg){
3097   int ok = true;
3098   OVreturn_word button_num, but_mod_num, act_code;
3099   int but_code;
3100   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
3101   OrthoLineType button, modifier, action;
3102   PYMOL_API_LOCK
3103     UtilNCopyToLower(button, buttonarg, strlen(buttonarg)+1);
3104     UtilNCopyToLower(modifier, modifierarg, strlen(modifierarg)+1);
3105     UtilNCopyToLower(action, actionarg, strlen(actionarg)+1);
3106     ok = OVreturn_IS_OK(button_num = get_button_code(I, button));
3107   if (ok) ok = OVreturn_IS_OK((but_mod_num = get_button_mod_code(I, modifier)));
3108   if (ok) ok = OVreturn_IS_OK((act_code = get_button_action_code(I, action)));
3109 
3110   if (ok){
3111     /* This is directly from the button() function in controlling.py */
3112     if (button_num.word < 3){ // normal button (L,M,R)
3113       if (but_mod_num.word < 4){
3114 	// none, shft, ctrl, ctsh
3115 	but_code = button_num.word + 3*but_mod_num.word;
3116       } else {
3117 	// alt, alsh, alct, alcs
3118 	but_code = button_num.word + 68 + 3*(but_mod_num.word-4);
3119       }
3120     } else if (button_num.word < 4){ // wheel
3121       if (but_mod_num.word < 4){
3122 	// none, shft, ctrl, ctsh
3123 	but_code = 12 + but_mod_num.word;
3124       } else {
3125 	but_code = 64 + but_mod_num.word - 4;
3126       }
3127     } else {
3128       // single and double clicks
3129       but_code = (16 + button_num.word -4) + but_mod_num.word * 6;
3130     }
3131     ButModeSet(I->G, but_code, act_code.word);
3132     result.status =  PyMOLstatus_SUCCESS;
3133   }
3134   PYMOL_API_UNLOCK return result;
3135 }
3136 #include "buttonmodes.h"
3137 
PyMOL_SetMouseButtonMode(CPyMOL * I,const char * modename)3138 PyMOLreturn_status PyMOL_SetMouseButtonMode(CPyMOL * I, const char *modename){
3139   int ok = true, i, start;
3140   OVreturn_word mode;
3141   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
3142 
3143   PYMOL_API_LOCK
3144     {
3145         char *nmodename = (char*)malloc(strlen(modename)+1);
3146 	UtilNCopyToLower((char*)nmodename, modename, strlen(modename)+1);
3147         ok = OVreturn_IS_OK(mode = get_mouse_mode(I, (char*)nmodename));
3148         free(nmodename);
3149     }
3150   if (ok){
3151     result.status =  PyMOLstatus_SUCCESS;
3152     {
3153       int a;
3154       /* for Button modes, first initialize all buttons, so that
3155 	 previous functionality does not linger */
3156       for(a = 0; a < cButModeInputCount; a++) {
3157 	ButModeSet(I->G, a, initial_button_modes[a]);
3158       }
3159     }
3160     start = button_mode_start[mode.word];
3161     for (i=0; i<n_button_mode[mode.word]; i++, start+=2){
3162       ButModeSet(I->G, all_buttons[start], all_buttons[start+1]);
3163     }
3164   }
3165   PYMOL_API_UNLOCK return result;
3166 }
3167 
get_button_code(CPyMOL * I,char * code)3168 static OVreturn_word get_button_code(CPyMOL * I, char *code)
3169 {
3170   OVreturn_word result;
3171   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, code))))
3172     return result;
3173   return OVOneToOne_GetForward(I->MouseButtonCodeLexicon, result.word);
3174 }
get_button_mod_code(CPyMOL * I,char * modcode)3175 static OVreturn_word get_button_mod_code(CPyMOL * I, char *modcode)
3176 {
3177   OVreturn_word result;
3178   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, modcode))))
3179     return result;
3180   return OVOneToOne_GetForward(I->MouseButtonModCodeLexicon, result.word);
3181 }
get_button_action_code(CPyMOL * I,char * actioncode)3182 static OVreturn_word get_button_action_code(CPyMOL * I, char *actioncode)
3183 {
3184   OVreturn_word result;
3185   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, actioncode))))
3186     return result;
3187   return OVOneToOne_GetForward(I->MouseButtonActionCodeLexicon, result.word);
3188 }
get_mouse_mode(CPyMOL * I,char * mousemode)3189 static OVreturn_word get_mouse_mode(CPyMOL * I, char *mousemode)
3190 {
3191   OVreturn_word result;
3192   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, mousemode))))
3193     return result;
3194   return OVOneToOne_GetForward(I->MouseModeLexicon, result.word);
3195 }
3196 
PyMOL_ZoomScene(CPyMOL * I,float scale)3197 PyMOLreturn_status PyMOL_ZoomScene(CPyMOL * I, float scale){
3198   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
3199   PYMOL_API_LOCK
3200     SceneZoom(I->G, scale);
3201     PyMOL_NeedRedisplay(I);
3202   result.status =  PyMOLstatus_SUCCESS;
3203   PYMOL_API_UNLOCK return result;
3204 }
3205 
PyMOL_TranslateScene(CPyMOL * I,float x,float y,float z)3206 PyMOLreturn_status PyMOL_TranslateScene(CPyMOL * I, float x, float y, float z){
3207   PyMOLreturn_status result = { PyMOLstatus_FAILURE };
3208   PYMOL_API_LOCK
3209     SceneTranslate(I->G, x, y, z);
3210   result.status =  PyMOLstatus_SUCCESS;
3211   PYMOL_API_UNLOCK return result;
3212 }
3213 
3214 #include "palettes.h"
3215 
get_palette(CPyMOL * I,char * palette)3216 static OVreturn_word get_palette(CPyMOL * I, char *palette)
3217 {
3218   OVreturn_word result;
3219   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, palette))))
3220     return result;
3221   return OVOneToOne_GetForward(I->PaletteLexicon, result.word);
3222 }
3223 
PyMOL_Spectrum(CPyMOL * I,const char * expression,const char * pal,const char * selection,float minimum,float maximum,int byres,int quiet)3224 PyMOLreturn_float_array PyMOL_Spectrum(CPyMOL * I, const char *expression, const char *pal, const char *selection, float minimum, float maximum, int byres, int quiet){
3225   PyMOLreturn_float_array result = { PyMOLstatus_FAILURE };
3226   PYMOL_API_LOCK
3227   int ok = true;
3228   int digits, first, last, array_pl, ret;
3229   float min_ret, max_ret;
3230   char prefix[2];
3231   OVreturn_word pal_word;
3232   char *palette = (char*)malloc(strlen(pal)+1);
3233     UtilNCopyToLower((char*)palette, pal, strlen(pal)+1);
3234 
3235   if (ok)
3236     ok = OVreturn_IS_OK(pal_word = get_palette(I, (char*)palette));
3237   free(palette);
3238   prefix[0] = palette_prefix[pal_word.word];
3239   prefix[1] = 0;
3240   array_pl = pal_word.word * 3;
3241   digits = palette_data[array_pl++];
3242   first = palette_data[array_pl++];
3243   last = palette_data[array_pl++];
3244 
3245   ret = ExecutiveSpectrum(I->G, selection, expression, minimum, maximum,
3246       first, last, prefix, digits, byres, quiet, &min_ret, &max_ret);
3247 
3248   if (ret){
3249     result.size = 2;
3250     result.array = VLAlloc(float, 2);
3251     result.array[0] = min_ret;
3252     result.array[1] = max_ret;
3253     result.status = PyMOLstatus_SUCCESS;
3254   } else {
3255     result.status = PyMOLstatus_FAILURE;
3256   }
3257   PYMOL_API_UNLOCK return result;
3258 }
3259 
3260 #endif
3261 
PyMOL_GetVersion(CPyMOL * I)3262 PyMOLreturn_value PyMOL_GetVersion(CPyMOL * I){
3263   int ok = true;
3264   PyMOLreturn_value result;
3265   result.status = PyMOLstatus_FAILURE;
3266 
3267   PYMOL_API_LOCK
3268   if(ok) {
3269     result.type = PYMOL_RETURN_VALUE_IS_STRING;
3270     result.string = mstrdup(_PyMOL_VERSION);
3271     result.status = PyMOLstatus_SUCCESS;
3272   };
3273   PYMOL_API_UNLOCK return result;
3274 }
3275 
PyMOL_GetAtomPropertyInfo(CPyMOL * I,const char * atompropname)3276 AtomPropertyInfo *PyMOL_GetAtomPropertyInfo(CPyMOL * I, const char *atompropname)
3277 {
3278   OVreturn_word result;
3279   if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->Lex, atompropname))))
3280     return NULL;
3281   result = OVOneToOne_GetForward(I->AtomPropertyLexicon, result.word);
3282   if(!OVreturn_IS_OK(result))
3283     return NULL;
3284   return &I->AtomPropertyInfos[result.word];
3285 }
3286 
3287 #ifdef __cplusplus
3288 }
3289 #endif
3290