mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
1544 lines
42 KiB
C++
1544 lines
42 KiB
C++
|
|
/*
|
|
A* -------------------------------------------------------------------
|
|
B* This file contains source code for the PyMOL computer program
|
|
C* Copyright (c) Schrodinger, LLC.
|
|
D* -------------------------------------------------------------------
|
|
E* It is unlawful to modify or remove this copyright notice.
|
|
F* -------------------------------------------------------------------
|
|
G* Please see the accompanying LICENSE file for further information.
|
|
H* -------------------------------------------------------------------
|
|
I* Additional authors of this source file include:
|
|
-*
|
|
-*
|
|
-*
|
|
Z* -------------------------------------------------------------------
|
|
*/
|
|
#include"os_python.h"
|
|
|
|
#include "os_predef.h"
|
|
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef WIN32
|
|
#include <signal.h>
|
|
#include <tchar.h>
|
|
#endif
|
|
|
|
/* END PROPRIETARY CODE SEGMENT */
|
|
|
|
#include "os_std.h"
|
|
#include "os_gl.h"
|
|
|
|
#ifdef _DRI_WORKAROUND
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
#include "PyMOLGlobals.h"
|
|
#include "PyMOL.h"
|
|
#include "PyMOLOptions.h"
|
|
|
|
#include "MemoryDebug.h"
|
|
#include "Base.h"
|
|
#include "main.h"
|
|
|
|
#include "P.h"
|
|
#include "PConv.h"
|
|
#include "Ortho.h"
|
|
#include "Scene.h"
|
|
#include "Seq.h"
|
|
#include "Util.h"
|
|
#include "Control.h"
|
|
#include "Movie.h"
|
|
#include "Executive.h"
|
|
#include "Feedback.h"
|
|
|
|
int _gScaleFactor = 1;
|
|
|
|
#ifdef _PYMOL_NO_MAIN
|
|
|
|
int MainSavingUnderWhileIdle(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
void MainFree(void);
|
|
static void MainReshape(int width, int height);
|
|
static void MainDrawLocked(void);
|
|
static void MainDrag(int x, int y);
|
|
|
|
static CPyMOL *PyMOLInstance = NULL; /* eliminate */
|
|
|
|
struct _CMain {
|
|
int IdleMode;
|
|
double IdleTime;
|
|
int IdleCount;
|
|
int Modifiers;
|
|
int FinalInitCounter, FinalInitTrigger, FinalInitDone;
|
|
int TheWindow;
|
|
int WindowIsVisible;
|
|
double ReshapeTime;
|
|
double DrawAfter, DrawDelay;
|
|
int DrawGovernorActive, DrawDeferred, DrawSignalled;
|
|
int DrawnFlag, DeferReshapeDeferral;
|
|
int MaximizeCheck;
|
|
CPyMOLOptions *OwnedOptions;
|
|
/* if Main owns a reference to a copy of the startup options that
|
|
needs to be freed upon shutdown to fully scrub the heap */
|
|
};
|
|
|
|
|
|
/* global options */
|
|
|
|
static
|
|
void MainOnExit(void);
|
|
|
|
static void MainPushValidContext(PyMOLGlobals * G)
|
|
{
|
|
PLockStatus(G);
|
|
PyMOL_PushValidContext(G->PyMOL);
|
|
PUnlockStatus(G);
|
|
}
|
|
|
|
static void MainPopValidContext(PyMOLGlobals * G)
|
|
{
|
|
PLockStatus(G);
|
|
PyMOL_PopValidContext(G->PyMOL);
|
|
PUnlockStatus(G);
|
|
}
|
|
|
|
static void DrawBlueLine(PyMOLGlobals * G)
|
|
{
|
|
if(G->Option->blue_line) {
|
|
GLint i;
|
|
unsigned long buffer;
|
|
GLint window_width, window_height;
|
|
|
|
window_width = G->Option->winX;
|
|
window_height = G->Option->winY;
|
|
|
|
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_BLEND);
|
|
for(i = 0; i < 6; i++)
|
|
glDisable(GL_CLIP_PLANE0 + i);
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_DITHER);
|
|
glDisable(GL_FOG);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_LINE_SMOOTH);
|
|
glDisable(GL_LINE_STIPPLE);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef _PYMOL_OSX
|
|
/*glDisable(GL_SHARED_TEXTURE_PALETTE_EXT); */
|
|
glDisable(GL_TEXTURE_1D);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_TEXTURE_3D);
|
|
glDisable(GL_TEXTURE_CUBE_MAP);
|
|
glDisable(GL_TEXTURE_RECTANGLE_EXT);
|
|
glDisable(GL_VERTEX_PROGRAM_ARB);
|
|
#endif
|
|
|
|
/* END PROPRIETARY CODE SEGMENT */
|
|
|
|
for(buffer = GL_BACK_LEFT; buffer <= GL_BACK_RIGHT; buffer++) {
|
|
GLint matrixMode;
|
|
GLint vp[4];
|
|
|
|
OrthoDrawBuffer(G, buffer);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, vp);
|
|
glViewport(0, 0, window_width, window_height);
|
|
|
|
glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glScalef(2.0f / window_width, -2.0f / window_height, 1.0f);
|
|
glTranslatef(-window_width / 2.0f, -window_height / 2.0f, 0.0f);
|
|
|
|
/* draw sync lines */
|
|
glColor3d(0.0f, 0.0f, 0.0f);
|
|
glBegin(GL_LINES); /* Draw a background line */
|
|
glVertex3f(0.0F, window_height - 0.5F, 0.0F);
|
|
glVertex3f((float) window_width, window_height - 0.5F, 0.0F);
|
|
glEnd();
|
|
glColor3d(0.0f, 0.0f, 1.0f);
|
|
glBegin(GL_LINES); /* Draw a line of the correct length (the cross
|
|
over is about 40% across the screen from the left */
|
|
glVertex3f(0.0f, window_height - 0.5f, 0.0f);
|
|
if(buffer == GL_BACK_LEFT)
|
|
glVertex3f(window_width * 0.30f, window_height - 0.5f, 0.0f);
|
|
else
|
|
glVertex3f(window_width * 0.80f, window_height - 0.5f, 0.0f);
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(matrixMode);
|
|
|
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
|
}
|
|
glPopAttrib();
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
|
|
void MainOnExit(void)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
/*
|
|
here we enter not knowing anything about the current state...
|
|
so, no graceful exit is possible -- in fact under Window's we'll
|
|
crash unless we take the drastic way out
|
|
*/
|
|
if(G && !G->Terminating) {
|
|
G->Terminating = true;
|
|
printf(" PyMOL: abrupt program termination.\n");
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef WIN32
|
|
TerminateProcess(GetCurrentProcess(), 0); /* only way to avoid a crash */
|
|
#endif
|
|
|
|
/* END PROPRIETARY CODE SEGMENT */
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int MainSavingUnderWhileIdle(void)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
CMain *I = G->Main;
|
|
return (I && (I->IdleMode > 3));
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
void MainSetWindowVisibility(int mode)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
G->Option->window_visible = mode;
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainDrag(int x, int y)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
CMain *I = G->Main;
|
|
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
|
|
y = G->Option->winY - y;
|
|
|
|
PyMOL_Drag(PyMOLInstance, x, y, I->Modifiers);
|
|
|
|
if(PyMOL_GetRedisplay(PyMOLInstance, true)) {
|
|
if(G->HaveGUI) {
|
|
p_glutPostRedisplay();
|
|
}
|
|
}
|
|
I->IdleMode = 0;
|
|
|
|
PUnlockAPIAsGlut(G);
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainButton(int button, int state, int x, int y)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
int glMod;
|
|
|
|
CMain *I = G->Main;
|
|
|
|
#ifdef WIN32
|
|
// fix wheel x/y on Windows (PYMOL-2173)
|
|
switch(button) {
|
|
case P_GLUT_BUTTON_SCROLL_FORWARD:
|
|
case P_GLUT_BUTTON_SCROLL_BACKWARD:
|
|
x -= p_glutGet(P_GLUT_WINDOW_X);
|
|
y -= p_glutGet(P_GLUT_WINDOW_Y);
|
|
}
|
|
#endif
|
|
|
|
glMod = p_glutGetModifiers();
|
|
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
|
|
I->IdleMode = 0; /* restore responsiveness */
|
|
|
|
if(PyMOL_GetPassive(PyMOLInstance, (button < 3) ? true : false)) {
|
|
MainDrag(x, y);
|
|
} else {
|
|
/* stay blocked here because Clicks->SexFrame->PParse */
|
|
|
|
y = G->Option->winY - y;
|
|
|
|
I->Modifiers = ((glMod & P_GLUT_ACTIVE_SHIFT) ? cOrthoSHIFT : 0) |
|
|
((glMod & P_GLUT_ACTIVE_CTRL) ? cOrthoCTRL : 0) |
|
|
((glMod & P_GLUT_ACTIVE_ALT) ? cOrthoALT : 0);
|
|
|
|
PyMOL_Button(PyMOLInstance, button, state, x, y, I->Modifiers);
|
|
}
|
|
|
|
PUnlockAPIAsGlut(G);
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainPassive(int x, int y)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
CMain *I = G->Main;
|
|
|
|
#define PASSIVE_EDGE 20
|
|
|
|
if(PyMOL_GetPassive(G->PyMOL, false)) { /* a harmless race condition -- we don't want
|
|
to slow Python down buy locking on passive
|
|
mouse motion */
|
|
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
if((y < -PASSIVE_EDGE) || (x < -PASSIVE_EDGE) ||
|
|
(x > (G->Option->winX + PASSIVE_EDGE)) ||
|
|
(y > (G->Option->winY + PASSIVE_EDGE))) {
|
|
|
|
/* release passive drag if mouse leaves window...
|
|
[IF we continue to receive mouse events...] */
|
|
|
|
y = G->Option->winY - y;
|
|
|
|
PyMOL_Button(PyMOLInstance, P_GLUT_LEFT_BUTTON, P_GLUT_UP, x, y, I->Modifiers);
|
|
|
|
PyMOL_GetPassive(G->PyMOL, true); /* reset the flag */
|
|
|
|
} else {
|
|
|
|
y = G->Option->winY - y;
|
|
|
|
PyMOL_Drag(PyMOLInstance, x, y, I->Modifiers);
|
|
|
|
}
|
|
|
|
if(PyMOL_GetRedisplay(PyMOLInstance, true)) {
|
|
if(G->HaveGUI) {
|
|
p_glutPostRedisplay();
|
|
}
|
|
I->IdleMode = 0;
|
|
}
|
|
|
|
PUnlockAPIAsGlut(G);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainDrawLocked(void)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
CMain *I = G->Main;
|
|
if(I->FinalInitTrigger) {
|
|
|
|
I->FinalInitTrigger = false;
|
|
|
|
#ifndef _PYMOL_NOPY
|
|
|
|
/* okay, on the way in, the API is locked but the interpreter is
|
|
running async, so we need to block it */
|
|
|
|
PBlock(G);
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
/* next, we need to let PyMOL know we have a valid context,
|
|
because some initializations, involve GL calls (such as going
|
|
into full-screen or stereo mode) */
|
|
|
|
if(G->HaveGUI)
|
|
MainPushValidContext(G);
|
|
|
|
/* restore working directory if asked to */
|
|
PRunStringModule(G,
|
|
"if 'PYMOL_WD' in os.environ: os.chdir(os.environ['PYMOL_WD'])");
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef _PYMOL_OSX
|
|
PRunStringModule(G,
|
|
"if os.getcwd()[-23:]=='.app/Contents/Resources': os.chdir('../../..')");
|
|
#endif
|
|
|
|
/* END PROPRIETARY CODE SEGMENT */
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
PXDecRef(PYOBJECT_CALLMETHOD(G->P_inst->obj, "launch_gui", "O", G->P_inst->obj));
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
PXDecRef(PYOBJECT_CALLMETHOD
|
|
(G->P_inst->obj, "adapt_to_hardware", "O", G->P_inst->obj));
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
if(G->Option->incentive_product) { /* perform incentive product initialization (if any) */
|
|
PyRun_SimpleString("try:\n import ipymol\nexcept:\n pass\n");
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
}
|
|
|
|
PXDecRef(PYOBJECT_CALLMETHOD(G->P_inst->obj, "exec_deferred", "O", G->P_inst->obj));
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
if(G->HaveGUI)
|
|
MainPopValidContext(G);
|
|
|
|
PUnblock(G);
|
|
|
|
#endif
|
|
I->FinalInitDone = true;
|
|
}
|
|
|
|
PyMOL_Draw(PyMOLInstance);
|
|
|
|
if(G->HaveGUI) {
|
|
if(Feedback(G, FB_OpenGL, FB_Debugging)) {
|
|
PyMOLCheckOpenGLErr("During Rendering");
|
|
}
|
|
}
|
|
|
|
if(PyMOL_GetSwap(G->PyMOL, true)) {
|
|
if(!SettingGetGlobal_b(G, cSetting_suspend_updates))
|
|
if(G->HaveGUI) {
|
|
DrawBlueLine(G);
|
|
p_glutSwapBuffers();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void MainDrawProgress(PyMOLGlobals * G)
|
|
{
|
|
int progress[PYMOL_PROGRESS_SIZE];
|
|
int update = false;
|
|
PBlock(G);
|
|
PLockStatus(G);
|
|
update = PyMOL_GetProgress(G->PyMOL, progress, true);
|
|
PUnlockStatus(G);
|
|
PUnblock(G);
|
|
|
|
/*
|
|
printf("show progress %d %d %d %d %d %d\n",
|
|
progress[0],progress[1],progress[2],
|
|
progress[3],progress[4],progress[5]); */
|
|
|
|
if(update &&
|
|
(progress[PYMOL_PROGRESS_SLOW] ||
|
|
progress[PYMOL_PROGRESS_MED] || progress[PYMOL_PROGRESS_FAST])) {
|
|
|
|
int offset;
|
|
int x = 0, y;
|
|
float black[3] = { 0, 0, 0 };
|
|
float white[3] = { 1, 1, 1 };
|
|
GLint ViewPort[4];
|
|
|
|
#define cBusyWidth 240
|
|
#define cBusyHeight 60
|
|
#define cBusyMargin 10
|
|
#define cBusyBar 10
|
|
#define cBusySpacing 15
|
|
|
|
glGetIntegerv(GL_VIEWPORT, ViewPort);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(0, ViewPort[2], 0, ViewPort[3], -100, 100);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glTranslatef(0.33F, 0.33F, 0.0F); /* this generates better
|
|
rasterization on macs */
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_FOG);
|
|
glDisable(GL_NORMALIZE);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
glDisable(GL_LINE_SMOOTH);
|
|
glDisable(GL_DITHER);
|
|
glDisable(GL_BLEND);
|
|
|
|
{
|
|
int pass = 0;
|
|
|
|
int draw_both = SceneMustDrawBoth(G);
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
while(1) {
|
|
if(draw_both) {
|
|
if(!pass)
|
|
OrthoDrawBuffer(G, GL_FRONT_LEFT);
|
|
else
|
|
OrthoDrawBuffer(G, GL_FRONT_RIGHT);
|
|
} else {
|
|
OrthoDrawBuffer(G, GL_FRONT); /* draw into the front buffer */
|
|
}
|
|
|
|
glColor3fv(black);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(0, ViewPort[3]);
|
|
glVertex2i(cBusyWidth, ViewPort[3]);
|
|
glVertex2i(cBusyWidth, ViewPort[3] - cBusyHeight);
|
|
glVertex2i(0, ViewPort[3] - cBusyHeight);
|
|
glVertex2i(0, ViewPort[3]); /* needed on old buggy Mesa */
|
|
glEnd();
|
|
y = ViewPort[3] - cBusyMargin;
|
|
|
|
glColor3fv(white);
|
|
|
|
/*
|
|
c=I->BusyMessage;
|
|
if(*c) {
|
|
TextSetColor(G,white);
|
|
TextSetPos2i(G,cBusyMargin,y-(cBusySpacing/2));
|
|
TextDrawStr(G,c);
|
|
y-=cBusySpacing;
|
|
}
|
|
*/
|
|
|
|
for(offset = 0; offset < PYMOL_PROGRESS_SIZE; offset += 2) {
|
|
|
|
if(progress[offset + 1]) {
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex2i(cBusyMargin, y);
|
|
glVertex2i(cBusyWidth - cBusyMargin, y);
|
|
glVertex2i(cBusyWidth - cBusyMargin, y - cBusyBar);
|
|
glVertex2i(cBusyMargin, y - cBusyBar);
|
|
glVertex2i(cBusyMargin, y); /* needed on old buggy Mesa */
|
|
glEnd();
|
|
glColor3fv(white);
|
|
x =
|
|
(progress[offset] * (cBusyWidth - 2 * cBusyMargin) / progress[offset + 1]) +
|
|
cBusyMargin;
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(cBusyMargin, y);
|
|
glVertex2i(x, y);
|
|
glVertex2i(x, y - cBusyBar);
|
|
glVertex2i(cBusyMargin, y - cBusyBar);
|
|
glVertex2i(cBusyMargin, y); /* needed on old buggy Mesa */
|
|
glEnd();
|
|
y -= cBusySpacing;
|
|
}
|
|
}
|
|
if(!draw_both)
|
|
break;
|
|
if(pass > 1)
|
|
break;
|
|
pass++;
|
|
}
|
|
|
|
glFlush();
|
|
glFinish();
|
|
if(draw_both)
|
|
OrthoDrawBuffer(G, GL_BACK_LEFT);
|
|
else
|
|
OrthoDrawBuffer(G, GL_BACK);
|
|
}
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainDraw(void)
|
|
{
|
|
int usec_sleep_after_draw = 0;
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainDraw: called.\n" ENDFD;
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
CMain *I = G->Main;
|
|
if(I->DrawGovernorActive &&
|
|
(!I->DrawSignalled) && (UtilGetSeconds(G) < I->DrawAfter) && I->FinalInitDone) {
|
|
I->DrawDeferred = true;
|
|
} else {
|
|
int skip = false;
|
|
if(I->MaximizeCheck) {
|
|
{
|
|
/* is the window manager screwing us over??? */
|
|
|
|
int height = p_glutGet(P_GLUT_SCREEN_HEIGHT);
|
|
int width = p_glutGet(P_GLUT_SCREEN_WIDTH);
|
|
int actual_x = p_glutGet(P_GLUT_WINDOW_X);
|
|
int actual_y = p_glutGet(P_GLUT_WINDOW_Y);
|
|
|
|
I->MaximizeCheck = false;
|
|
|
|
if(actual_x != 0) {
|
|
width -= 2 * actual_x;
|
|
height -= actual_x;
|
|
}
|
|
if(actual_y != 0) {
|
|
height -= actual_y;
|
|
}
|
|
p_glutPositionWindow(0, 0);
|
|
p_glutReshapeWindow(width, height);
|
|
skip = true;
|
|
}
|
|
}
|
|
if((!skip) && (!I->DrawnFlag) && I->FinalInitDone) {
|
|
if(I->DeferReshapeDeferral > 0)
|
|
I->DeferReshapeDeferral--;
|
|
else {
|
|
double time_since_reshape = UtilGetSeconds(G) - I->ReshapeTime;
|
|
if(time_since_reshape < 0.05) {
|
|
/* defer screen updates while it's being actively resized */
|
|
skip = true;
|
|
}
|
|
}
|
|
}
|
|
if(!skip) {
|
|
MainDrawLocked();
|
|
I->DrawnFlag = true;
|
|
if(PyMOL_GetModalDraw(PyMOLInstance)) {
|
|
usec_sleep_after_draw = 10000; /* give other threads a chance to run */
|
|
}
|
|
} else {
|
|
PyMOL_NeedRedisplay(PyMOLInstance);
|
|
}
|
|
|
|
I->DrawAfter = UtilGetSeconds(G) + I->DrawDelay;
|
|
I->DrawSignalled = false;
|
|
I->DrawDeferred = false;
|
|
}
|
|
PUnlockAPIAsGlut(G);
|
|
} else { /* we're busy -- so try to display a progress indicator */
|
|
MainDrawProgress(G);
|
|
}
|
|
PRINTFD(G, FB_Main)
|
|
" MainDraw: completed.\n" ENDFD;
|
|
if(usec_sleep_after_draw && G) {
|
|
PSleepUnlocked(G, usec_sleep_after_draw);
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainKey(unsigned char k, int x, int y)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
CMain *I = G->Main;
|
|
int glMod;
|
|
|
|
glMod = p_glutGetModifiers();
|
|
|
|
#if defined(_PYMOL_OSX) && !defined(_PYMOL_LIB)
|
|
// MacOS GLUT.framework: swap delete and backspace
|
|
switch (k) {
|
|
case 0x08: k = 0x7f; break;
|
|
case 0x7f: k = 0x08; break;
|
|
}
|
|
#endif
|
|
|
|
PRINTFB(G, FB_Main, FB_Blather)
|
|
" MainKey: code:%d modifiers:0x%02x x:%d y:%d\n", k, glMod, x, y ENDFB(G);
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
|
|
I->IdleMode = 0; /* restore responsiveness */
|
|
|
|
I->Modifiers = ((glMod & P_GLUT_ACTIVE_SHIFT) ? cOrthoSHIFT : 0) |
|
|
((glMod & P_GLUT_ACTIVE_CTRL) ? cOrthoCTRL : 0) |
|
|
((glMod & P_GLUT_ACTIVE_ALT) ? cOrthoALT : 0);
|
|
|
|
PyMOL_Key(PyMOLInstance, k, x, y, I->Modifiers);
|
|
|
|
PUnlockAPIAsGlut(G);
|
|
} else {
|
|
if((k == 8) || (k == 127)) { /* interrupt busy state (if possibele) */
|
|
PBlock(G);
|
|
PLockStatus(G);
|
|
PyMOL_SetInterrupt(G->PyMOL, true);
|
|
PUnlockStatus(G);
|
|
PUnblock(G);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainSpecial(int k, int x, int y)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
CMain *I = G->Main;
|
|
int glMod;
|
|
|
|
PRINTFB(G, FB_Main, FB_Blather)
|
|
" MainSpecial: %d %d %d\n", k, x, y ENDFB(G);
|
|
glMod = p_glutGetModifiers();
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
|
|
I->Modifiers = ((glMod & P_GLUT_ACTIVE_SHIFT) ? cOrthoSHIFT : 0) |
|
|
((glMod & P_GLUT_ACTIVE_CTRL) ? cOrthoCTRL : 0) |
|
|
((glMod & P_GLUT_ACTIVE_ALT) ? cOrthoALT : 0);
|
|
|
|
PyMOL_Special(PyMOLInstance, k, x, y, I->Modifiers);
|
|
|
|
PUnlockAPIAsGlut(G);
|
|
}
|
|
}
|
|
|
|
|
|
/* new window size or exposure */
|
|
|
|
/*========================================================================*/
|
|
void MainReshape(int width, int height)
|
|
{ /* called by Glut */
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
if(G) {
|
|
CMain *I = G->Main;
|
|
|
|
I->ReshapeTime = (double) UtilGetSeconds(G);
|
|
I->DrawnFlag = false;
|
|
|
|
if (width==0 || height==0)
|
|
return;
|
|
if(PLockAPIAsGlut(G, true)) {
|
|
if(G->HaveGUI) {
|
|
glViewport(0, 0, (GLint) width, (GLint) height);
|
|
if((!PyMOLInstance) ||
|
|
(width != OrthoGetWidth(G)) || (height != OrthoGetHeight(G))) {
|
|
/* wipe the screen ASAP to prevent display of garbage... */
|
|
|
|
int draw_both = G->StereoCapable &&
|
|
((SceneGetStereo(G) == 1) ||
|
|
SettingGetGlobal_b(G, cSetting_stereo_double_pump_mono));
|
|
|
|
SceneGLClearColor(0.0, 0.0, 0.0, 1.0);
|
|
if(draw_both) {
|
|
OrthoDrawBuffer(G, GL_FRONT_LEFT);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
OrthoDrawBuffer(G, GL_FRONT_RIGHT);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
OrthoDrawBuffer(G, GL_BACK_LEFT);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
OrthoDrawBuffer(G, GL_BACK_RIGHT);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
} else {
|
|
OrthoDrawBuffer(G, GL_FRONT);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
OrthoDrawBuffer(G, GL_BACK);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
}
|
|
}
|
|
PyMOL_SwapBuffers(PyMOLInstance);
|
|
}
|
|
}
|
|
if(PyMOLInstance)
|
|
PyMOL_Reshape(PyMOLInstance, width, height, false);
|
|
PUnlockAPIAsGlut(G);
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
/**
|
|
* only called from CmdViewport(), and only with !_PYMOL_NO_MAIN
|
|
*/
|
|
void MainDoReshape(int width, int height)
|
|
{ /* called internally */
|
|
int internal_feedback;
|
|
int force = false;
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
if(G) {
|
|
/* if width and height are negative and we are in full screen, don't reshape window */
|
|
bool keep_fullscreen = (width < 0 && height < 0 && ExecutiveIsFullScreen(G));
|
|
|
|
/* if width is negative, force a reshape based on the current width */
|
|
|
|
if(width < 0) {
|
|
width = SceneGetBlock(G)->getWidth();
|
|
if(SettingGetGlobal_b(G, cSetting_internal_gui))
|
|
width += SettingGetGlobal_i(G, cSetting_internal_gui_width);
|
|
force = true;
|
|
}
|
|
|
|
/* if height is negative, force a reshape based on the current height */
|
|
|
|
if(height < 0) {
|
|
height = SceneGetBlock(G)->getHeight();
|
|
internal_feedback = SettingGetGlobal_i(G, cSetting_internal_feedback);
|
|
if(internal_feedback)
|
|
height += (internal_feedback - 1) * cOrthoLineHeight + cOrthoBottomSceneMargin;
|
|
if(SettingGetGlobal_b(G, cSetting_seq_view)
|
|
&& !SettingGetGlobal_b(G, cSetting_seq_view_overlay))
|
|
height += SeqGetHeight(G);
|
|
height += MovieGetPanelHeight(G);
|
|
force = true;
|
|
}
|
|
|
|
/* if we have a GUI, for a reshape event */
|
|
|
|
if(G->HaveGUI && G->ValidContext && width > 0 && height > 0) {
|
|
p_glutReshapeWindow(width, height);
|
|
glViewport(0, 0, (GLint) width, (GLint) height);
|
|
}
|
|
|
|
if((!width)||(!height)) {
|
|
int actual_width = width ? width : G->Option->winX;
|
|
int actual_height = height ? height : G->Option->winY;
|
|
|
|
PyMOL_Reshape(G->PyMOL, actual_width, actual_height, true);
|
|
|
|
} else {
|
|
PyMOL_Reshape(G->PyMOL, width, height, force);
|
|
if(G->Main) {
|
|
G->Main->DeferReshapeDeferral = 1;
|
|
}
|
|
|
|
/* do we need to become full-screen? */
|
|
if(keep_fullscreen) {
|
|
p_glutFullScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
static void MainInit(PyMOLGlobals * G)
|
|
{
|
|
|
|
CMain *I = (G->Main = pymol::calloc<CMain>(1));
|
|
/* Data structure is zeroed on start...no need for explicit zero inits */
|
|
|
|
I->DeferReshapeDeferral = 1;
|
|
|
|
PyMOL_Start(PyMOLInstance);
|
|
|
|
// moved to PyMOL_DrawWithoutLock
|
|
// PyMOL_ConfigureShadersGL(PyMOLInstance);
|
|
|
|
PyMOL_SetSwapBuffersFn(PyMOLInstance, (PyMOLSwapBuffersFn *) p_glutSwapBuffers);
|
|
I->ReshapeTime = (I->IdleTime = UtilGetSeconds(G));
|
|
|
|
I->DrawGovernorActive = false;
|
|
I->DrawSignalled = true;
|
|
I->DrawDelay = 0.01; /* 100 FPS max */
|
|
I->DrawAfter = 0.0;
|
|
I->DrawDeferred = false;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
void MainFree(void)
|
|
{
|
|
PyMOLGlobals *G = PyMOL_GetGlobals(PyMOLInstance); /* temporary -- will change */
|
|
|
|
CPyMOLOptions *owned_options = G->Main->OwnedOptions;
|
|
|
|
int show_message = G->Option->show_splash && !G->Option->quiet;
|
|
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef WIN32
|
|
int haveGUI = G->HaveGUI;
|
|
int theWindow = G->Main->TheWindow;
|
|
#endif
|
|
#ifdef _PYMOL_OSX
|
|
int game_mode = G->Option->game_mode;
|
|
int haveGUI = G->HaveGUI;
|
|
int theWindow = G->Main->TheWindow;
|
|
#endif
|
|
|
|
/* END PROPRIETARY CODE SEGMENT */
|
|
|
|
FreeP(G->Main);
|
|
|
|
if(owned_options)
|
|
PyMOLOptions_Free(owned_options); /* clean up launch options if we're supposed to */
|
|
|
|
if(show_message) {
|
|
printf(" PyMOL: normal program termination.\n");
|
|
}
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef WIN32
|
|
if(haveGUI)
|
|
p_glutDestroyWindow(theWindow);
|
|
TerminateProcess(GetCurrentProcess(), 0); /* only way to avoid a crash */
|
|
#endif
|
|
#ifdef _PYMOL_OSX
|
|
if(haveGUI) {
|
|
if(game_mode) {
|
|
p_glutLeaveGameMode();
|
|
/* force a full-screen refresh to eliminate garbage on screen
|
|
* NOTE that we currently have to patch Apple's GLUT to make this work */
|
|
p_glutInitWindowPosition(0, 0);
|
|
p_glutInitWindowSize(640, 480);
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | P_GLUT_DOUBLE);
|
|
if(p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE)) {
|
|
theWindow = p_glutCreateWindow("PyMOL Viewer");
|
|
p_glutFullScreen();
|
|
p_glutDestroyWindow(theWindow);
|
|
}
|
|
} else
|
|
p_glutDestroyWindow(theWindow);
|
|
}
|
|
#endif
|
|
|
|
/* END PROPRIETARY CODE SEGMENT */
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
void MainRefreshNow(void)
|
|
{ /* should only be called by the master thread, with a locked API */
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
|
|
CMain *I = G->Main;
|
|
if(PyMOL_GetSwap(G->PyMOL, true)) {
|
|
if(G->HaveGUI) {
|
|
DrawBlueLine(G);
|
|
p_glutSwapBuffers();
|
|
}
|
|
}
|
|
if(PyMOL_GetRedisplay(PyMOLInstance, true)) {
|
|
if(G->HaveGUI)
|
|
p_glutPostRedisplay();
|
|
else
|
|
MainDrawLocked();
|
|
I->IdleMode = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
static void MainBusyIdle(void)
|
|
{
|
|
PyMOLGlobals *G = SingletonPyMOLGlobals;
|
|
/* This is one of the few places in the program where we can be sure
|
|
* that we have the "glut" thread...glut doesn't seem to be completely
|
|
* thread safe or rather thread consistent
|
|
*/
|
|
|
|
CMain *I = G->Main;
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: called.\n" ENDFD;
|
|
|
|
/* flush command and output queues */
|
|
|
|
/* PRINTFD(G,FB_Main)
|
|
" MainBusyIdle: entered, IdleMode %d\n",
|
|
I->IdleMode
|
|
ENDFD; */
|
|
|
|
if(PLockAPIAsGlut(G, false)) {
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: got lock.\n" ENDFD;
|
|
|
|
/* change window visibility & refresh, if necessary */
|
|
|
|
if(G->HaveGUI) {
|
|
if(I->WindowIsVisible != G->Option->window_visible) {
|
|
I->WindowIsVisible = G->Option->window_visible;
|
|
if(I->WindowIsVisible) {
|
|
p_glutShowWindow();
|
|
OrthoDirty(G);
|
|
} else {
|
|
p_glutHideWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: calling idle function.\n" ENDFD;
|
|
|
|
if(PyMOL_Idle(PyMOLInstance)) {
|
|
/* we did some work, so keep PyMOL responsive */
|
|
I->IdleMode = 1;
|
|
} else if(!I->IdleMode) {
|
|
I->IdleMode = 1;
|
|
} else if(I->IdleMode == 1) {
|
|
I->IdleMode = 2;
|
|
I->IdleTime = UtilGetSeconds(G);
|
|
}
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: swap check.\n" ENDFD;
|
|
|
|
if(PyMOL_GetSwap(G->PyMOL, true)) {
|
|
if(G->HaveGUI) {
|
|
DrawBlueLine(G);
|
|
p_glutSwapBuffers();
|
|
}
|
|
}
|
|
|
|
/* if the screen has become dirty, post a redisplay event, or if
|
|
we're running without a GUI, then call the draw routine (if we */
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: redisplay.\n" ENDFD;
|
|
|
|
if(PyMOL_GetRedisplay(PyMOLInstance, true)) {
|
|
if(G->HaveGUI)
|
|
p_glutPostRedisplay();
|
|
else
|
|
MainDrawLocked();
|
|
if(I->IdleMode > 1) {
|
|
I->IdleMode = 1;
|
|
}
|
|
}
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: redisplay.\n" ENDFD;
|
|
|
|
/* the following code enables PyMOL to avoid busy-idling
|
|
* even though we're using GLUT! */
|
|
|
|
switch (I->IdleMode) {
|
|
case 2: /* avoid racing the CPU */
|
|
if((UtilGetSeconds(G) - I->IdleTime) > (SettingGetGlobal_f(G, cSetting_idle_delay) / 5.0)) {
|
|
I->IdleMode = 3;
|
|
I->IdleTime = UtilGetSeconds(G);
|
|
}
|
|
break;
|
|
case 3:
|
|
if((UtilGetSeconds(G) - I->IdleTime) > (SettingGetGlobal_f(G, cSetting_idle_delay))) {
|
|
I->IdleMode = 4;
|
|
if(G->HaveGUI)
|
|
if(SettingGetGlobal_b(G, cSetting_cache_display)) {
|
|
p_glutPostRedisplay(); /* trigger caching of the current scene */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: unlocking.\n" ENDFD;
|
|
|
|
{
|
|
int control_idling = false;
|
|
if(I->IdleMode == 1) {
|
|
control_idling = ControlIdling(G);
|
|
}
|
|
PUnlockAPIAsGlut(G);
|
|
|
|
switch (I->IdleMode) {
|
|
case 4:
|
|
PSleepUnlocked(G, SettingGetGlobal_i(G, cSetting_slow_idle)); /* slow idle - save CPU cycles */
|
|
break;
|
|
case 3:
|
|
PSleepUnlocked(G, SettingGetGlobal_i(G, cSetting_fast_idle)); /* fast idle - more responsive */
|
|
break;
|
|
case 2:
|
|
PSleepUnlocked(G, SettingGetGlobal_i(G, cSetting_no_idle)); /* give Tcl/Tk a chance to run */
|
|
break;
|
|
case 1:
|
|
if(control_idling) {
|
|
PSleepUnlocked(G, SettingGetGlobal_i(G, cSetting_no_idle)); /* give Tcl/Tk a chance to run */
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* run final initilization code for Python-based PyMOL implementations. */
|
|
|
|
#define FINAL_INIT_AT 10
|
|
if(I->FinalInitCounter < FINAL_INIT_AT) {
|
|
I->FinalInitCounter = I->FinalInitCounter + 1;
|
|
if(I->FinalInitCounter == FINAL_INIT_AT) {
|
|
I->FinalInitTrigger = true;
|
|
PyMOL_NeedRedisplay(PyMOLInstance);
|
|
}
|
|
}
|
|
|
|
/* when running in command-line mode, if we're not reading from
|
|
* standard input and if we're not keeping the thread alive, then
|
|
* we can have no further input. Therefore die. */
|
|
|
|
if(!G->HaveGUI) {
|
|
if(!(OrthoCommandWaiting(G) ||
|
|
PyMOL_GetModalDraw(G->PyMOL) ||
|
|
OrthoDeferredWaiting(G) || SettingGetGlobal_b(G, cSetting_keep_alive))) {
|
|
if((!G->Option->keep_thread_alive) &&
|
|
(!G->Option->read_stdin) && (I->FinalInitCounter >= FINAL_INIT_AT)) {
|
|
I->IdleCount++;
|
|
if(I->IdleCount == 10) {
|
|
if(PLockAPIAsGlut(G, true)) {
|
|
PParse(G, "_quit");
|
|
PFlush(G);
|
|
PUnlockAPIAsGlut(G);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
I->IdleCount = 0;
|
|
}
|
|
}
|
|
|
|
{
|
|
int max_ups = SettingGetGlobal_i(G, cSetting_max_ups);
|
|
if(max_ups < 1) {
|
|
I->DrawGovernorActive = false;
|
|
if(I->DrawDeferred) {
|
|
p_glutPostRedisplay();
|
|
}
|
|
} else {
|
|
I->DrawDelay = 1.0 / max_ups;
|
|
I->DrawGovernorActive = true;
|
|
if(I->DrawDeferred) {
|
|
if(UtilGetSeconds(G) > I->DrawAfter) {
|
|
I->DrawSignalled = true;
|
|
}
|
|
if(I->DrawSignalled) {
|
|
I->DrawDeferred = false;
|
|
p_glutPostRedisplay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: lock not obtained...\n" ENDFD;
|
|
|
|
PSleepWhileBusy(G, 100000); /* 10 per second */
|
|
if(G->HaveGUI) {
|
|
PBlock(G);
|
|
PLockStatus(G);
|
|
if(PyMOL_GetProgressChanged(G->PyMOL, false))
|
|
p_glutPostRedisplay();
|
|
PUnlockStatus(G);
|
|
PUnblock(G);
|
|
}
|
|
}
|
|
|
|
PRINTFD(G, FB_Main)
|
|
" MainBusyIdle: leaving... IdleMode %d\n", I->IdleMode ENDFD;
|
|
|
|
}
|
|
|
|
void MainSetWindowPosition(PyMOLGlobals * G, int x, int y)
|
|
{
|
|
#ifdef _PYMOL_FINK
|
|
y -= 22; /* something is wrong with FinkGlut's window positioning... */
|
|
#endif
|
|
p_glutPositionWindow(x, y);
|
|
}
|
|
|
|
void MainSetWindowSize(PyMOLGlobals * G, int w, int h)
|
|
{
|
|
G->Main->DeferReshapeDeferral = 1;
|
|
p_glutReshapeWindow(w, h);
|
|
}
|
|
|
|
void MainMaximizeWindow(PyMOLGlobals * G)
|
|
{
|
|
int height = p_glutGet(P_GLUT_SCREEN_HEIGHT);
|
|
int width = p_glutGet(P_GLUT_SCREEN_WIDTH);
|
|
G->Main->DeferReshapeDeferral = 1;
|
|
G->Main->MaximizeCheck = true;
|
|
p_glutPositionWindow(0, 0);
|
|
p_glutReshapeWindow(width, height);
|
|
|
|
}
|
|
|
|
void MainCheckWindowFit(PyMOLGlobals * G)
|
|
{
|
|
CMain *I = G->Main;
|
|
if(G && G->Main) {
|
|
int height = p_glutGet(P_GLUT_SCREEN_HEIGHT);
|
|
int width = p_glutGet(P_GLUT_SCREEN_WIDTH);
|
|
int actual_x = p_glutGet(P_GLUT_WINDOW_X);
|
|
int actual_y = p_glutGet(P_GLUT_WINDOW_Y);
|
|
int actual_width = p_glutGet(P_GLUT_WINDOW_WIDTH);
|
|
int actual_height = p_glutGet(P_GLUT_WINDOW_HEIGHT);
|
|
int new_width = -1;
|
|
int new_height = -1;
|
|
|
|
I->DeferReshapeDeferral = 1;
|
|
|
|
if((actual_x + actual_width) > width)
|
|
new_width = (width - actual_x) - 5; /* allow room for decoration */
|
|
if((actual_y + actual_height) > height)
|
|
new_height = (height - actual_y) - 5; /* allow room for decoration */
|
|
if((new_width > 0) || (new_height > 0)) {
|
|
if(new_width < 0)
|
|
new_width = actual_width;
|
|
if(new_height < 0)
|
|
new_height = actual_height;
|
|
MainSetWindowSize(G, new_width, new_height);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef WIN32
|
|
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType /* control signal type */
|
|
)
|
|
{
|
|
switch (dwCtrlType) {
|
|
case CTRL_CLOSE_EVENT:
|
|
case CTRL_BREAK_EVENT:
|
|
case CTRL_C_EVENT:
|
|
TerminateProcess(GetCurrentProcess(), 0); /* only way to avoid a crash */
|
|
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
static void launch(CPyMOLOptions * options, int own_the_options)
|
|
{
|
|
|
|
int multisample_mask = 0;
|
|
int theWindow = 0;
|
|
PyMOLGlobals *G = NULL;
|
|
|
|
PyMOLInstance = PyMOL_NewWithOptions(options);
|
|
G = PyMOL_GetGlobals(PyMOLInstance);
|
|
|
|
G->HaveGUI = options->pmgui;
|
|
|
|
assert(!SingletonPyMOLGlobals);
|
|
SingletonPyMOLGlobals = G;
|
|
|
|
if(G->Option->multisample)
|
|
multisample_mask = P_GLUT_MULTISAMPLE;
|
|
|
|
/* if were running GLUT, then we have the ability to increase the
|
|
* size of the window in order to accomodate the context */
|
|
|
|
if(G->Option->internal_gui && (!G->Option->game_mode))
|
|
G->Option->winX += cOrthoRightSceneMargin;
|
|
|
|
if(G->Option->internal_feedback && (!G->Option->game_mode))
|
|
G->Option->winY +=
|
|
(G->Option->internal_feedback - 1) * cOrthoLineHeight + cOrthoBottomSceneMargin;
|
|
|
|
if(G->HaveGUI) {
|
|
#ifndef _PYMOL_OSX
|
|
atexit(MainOnExit); /* register callback to help prevent crashes
|
|
when GLUT spontaneously kills us */
|
|
#endif
|
|
|
|
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
|
|
#ifdef WIN32
|
|
SetConsoleCtrlHandler(HandlerRoutine, // address of handler function
|
|
true // handler to add or remove
|
|
);
|
|
SetConsoleTitle(_T("PyMOL"));
|
|
#endif
|
|
|
|
int myArgc = 0;
|
|
char* myArgv[8] = {strdup("pymol")};
|
|
p_glutInit(&myArgc, myArgv);
|
|
|
|
{
|
|
int display_mode_possible = false;
|
|
if(G->Option->stereo_mode > 1)
|
|
G->Option->force_stereo = 0;
|
|
|
|
switch (G->Option->force_stereo) {
|
|
case -1: /* force mono */
|
|
G->StereoCapable = 0;
|
|
break;
|
|
case 1: /* force quad buffer stereo (if possible) */
|
|
G->Option->stereo_mode = cStereo_quadbuffer;
|
|
case 0: /* default/autodetect */
|
|
switch (G->Option->stereo_mode) {
|
|
case cStereo_default:
|
|
case cStereo_quadbuffer:
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | multisample_mask |
|
|
P_GLUT_DOUBLE | P_GLUT_STEREO);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
if(multisample_mask && (!display_mode_possible)) {
|
|
G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_MultisampleFailed;
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | P_GLUT_DOUBLE |
|
|
P_GLUT_STEREO);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
}
|
|
if(display_mode_possible) {
|
|
G->StereoCapable = 1;
|
|
} else if(G->Option->stereo_mode == cStereo_quadbuffer) {
|
|
G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_StereoFailed;
|
|
}
|
|
break;
|
|
case cStereo_clone_dynamic:
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | P_GLUT_DOUBLE | P_GLUT_ACCUM
|
|
| P_GLUT_STEREO);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
if(!display_mode_possible) {
|
|
G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_StereoFailed;
|
|
G->Option->stereo_mode = 0;
|
|
} else {
|
|
G->StereoCapable = 1;
|
|
}
|
|
break;
|
|
case cStereo_dynamic:
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | P_GLUT_DOUBLE |
|
|
P_GLUT_ACCUM);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
if(!display_mode_possible) {
|
|
G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_StereoFailed;
|
|
G->Option->stereo_mode = 0;
|
|
}
|
|
break;
|
|
case cStereo_stencil_by_row:
|
|
case cStereo_stencil_by_column:
|
|
case cStereo_stencil_checkerboard:
|
|
case cStereo_stencil_custom:
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | P_GLUT_DOUBLE |
|
|
P_GLUT_STENCIL);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
if(!display_mode_possible) {
|
|
G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_StereoFailed;
|
|
G->Option->stereo_mode = 0;
|
|
}
|
|
break;
|
|
case cStereo_anaglyph: /* nothing special required for anaglyph */
|
|
G->StereoCapable = 1;
|
|
break;
|
|
default: /* fall through */
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
/* fallback behavior */
|
|
|
|
if(!display_mode_possible) {
|
|
G->LaunchStatus &= ~cPyMOLGlobals_LaunchStatus_MultisampleFailed;
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | multisample_mask |
|
|
P_GLUT_DOUBLE);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
G->StereoCapable = 0;
|
|
}
|
|
|
|
if(multisample_mask && (!display_mode_possible)) {
|
|
G->LaunchStatus |= cPyMOLGlobals_LaunchStatus_MultisampleFailed;
|
|
p_glutInitDisplayMode(P_GLUT_RGBA | P_GLUT_DEPTH | P_GLUT_DOUBLE);
|
|
display_mode_possible = p_glutGet(P_GLUT_DISPLAY_MODE_POSSIBLE);
|
|
G->StereoCapable = 0;
|
|
}
|
|
}
|
|
|
|
if(!G->Option->game_mode) {
|
|
if((G->Option->winPX > -10000) && (G->Option->winPY > -10000)) {
|
|
#ifndef _PYMOL_FINK
|
|
p_glutInitWindowPosition(G->Option->winPX, G->Option->winPY);
|
|
#else
|
|
p_glutInitWindowPosition(G->Option->winPX, G->Option->winPY - 22); /* somethings wrong with FinkGlut's window positioning... */
|
|
#endif
|
|
}
|
|
|
|
p_glutInitWindowSize(G->Option->winX, G->Option->winY);
|
|
|
|
theWindow = p_glutCreateWindow("PyMOL Viewer");
|
|
|
|
if(G->Option->full_screen) {
|
|
p_glutFullScreen();
|
|
}
|
|
|
|
if(G->Option->window_visible) {
|
|
p_glutShowWindow();
|
|
} else {
|
|
p_glutHideWindow();
|
|
}
|
|
|
|
} else {
|
|
char str[255];
|
|
sprintf(str, "%dx%d:32@120", G->Option->winX, G->Option->winY);
|
|
p_glutGameModeString(str);
|
|
p_glutEnterGameMode();
|
|
}
|
|
}
|
|
MainInit(G);
|
|
if(own_the_options)
|
|
G->Main->OwnedOptions = options;
|
|
/* make sure we can clean up these options later if we've been asked to do so */
|
|
{
|
|
CMain *I = G->Main;
|
|
|
|
I->TheWindow = theWindow;
|
|
|
|
PInit(G, true);
|
|
|
|
if(G->HaveGUI) {
|
|
p_glutDisplayFunc(MainDraw);
|
|
p_glutReshapeFunc(MainReshape);
|
|
p_glutKeyboardFunc(MainKey);
|
|
p_glutMouseFunc(MainButton);
|
|
p_glutMotionFunc(MainDrag);
|
|
p_glutPassiveMotionFunc(MainPassive);
|
|
p_glutSpecialFunc(MainSpecial);
|
|
p_glutIdleFunc(MainBusyIdle);
|
|
}
|
|
|
|
PUnblock(G);
|
|
|
|
if(G->HaveGUI) {
|
|
if(!I->WindowIsVisible)
|
|
MainReshape(G->Option->winX, G->Option->winY);
|
|
I->IdleMode = 3;
|
|
p_glutMainLoop(); /* never returns with traditional GLUT implementation */
|
|
PBlock(G); /* if we've gotten here, then we're heading back to Python... */
|
|
} else {
|
|
SceneSetCardInfo(G, "none", "ray trace only", "none");
|
|
if(G->Option->show_splash && !G->Option->quiet)
|
|
printf(" Command mode. No graphics front end.\n");
|
|
MainReshape(G->Option->winX, G->Option->winY);
|
|
MainDraw(); /* for command line processing */
|
|
while(1) {
|
|
MainBusyIdle();
|
|
MainDraw();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
static int decoy_input_hook(void) { return 0; }
|
|
|
|
int main_shared(int block_input_hook)
|
|
{
|
|
if(block_input_hook)
|
|
PyOS_InputHook = decoy_input_hook;
|
|
|
|
#ifdef _DRI_WORKAROUND
|
|
dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
|
|
#endif
|
|
|
|
{ /* no matter how PyMOL was built, we always come through here... */
|
|
|
|
CPyMOLOptions *options = PyMOLOptions_New();
|
|
|
|
if(options) {
|
|
|
|
PGetOptions(options);
|
|
|
|
launch(options, true);
|
|
/* this only returns when PyMOL is not running under GLUT */
|
|
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
PyObject *MainAsPyList(PyMOLGlobals *G)
|
|
{
|
|
#ifdef _PYMOL_NOPY
|
|
return NULL;
|
|
#else
|
|
PyObject *result = NULL;
|
|
int width, height;
|
|
result = PyList_New(2);
|
|
width = SceneGetBlock(G)->getWidth();
|
|
height = SceneGetBlock(G)->getHeight();
|
|
if(SettingGetGlobal_b(G, cSetting_seq_view)
|
|
&& !SettingGetGlobal_b(G, cSetting_seq_view_overlay))
|
|
height += SeqGetHeight(G);
|
|
PyList_SetItem(result, 0, PyInt_FromLong(width));
|
|
PyList_SetItem(result, 1, PyInt_FromLong(height));
|
|
return (PConvAutoNone(result));
|
|
#endif
|
|
}
|
|
|
|
int MainFromPyList(PyMOLGlobals *G, PyObject * list)
|
|
{
|
|
#ifdef _PYMOL_NOPY
|
|
return 0;
|
|
#else
|
|
|
|
int ok = true;
|
|
int win_x, win_y;
|
|
int ll = 0;
|
|
OrthoLineType buffer;
|
|
|
|
if(ok)
|
|
ok = (list != NULL);
|
|
if(ok)
|
|
ok = PyList_Check(list);
|
|
if(ok)
|
|
ll = PyList_Size(list);
|
|
if(ok && (ll >= 2)) {
|
|
if(!G->Option->presentation &&
|
|
!G->Option->full_screen &&
|
|
!ExecutiveIsFullScreen(G)) {
|
|
if(ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 0), &win_x);
|
|
if(ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 1), &win_y);
|
|
/* BlockGetSize(SceneGetBlock(G),&win_x,&win_y); * so how did this get into 0.98beta29? */
|
|
if(ok) {
|
|
|
|
sprintf(buffer, "viewport %d, %d", win_x, win_y);
|
|
PParse(G, buffer);
|
|
}
|
|
}
|
|
}
|
|
return (ok);
|
|
#endif
|
|
}
|