1094 lines
27 KiB
C
1094 lines
27 KiB
C
/* grOGL1.c -
|
|
*
|
|
* This file contains primitive functions for OpenGL running under
|
|
* an X window system (using GLUT).
|
|
* Included here are initialization and closing
|
|
* functions, and several utility routines used by the other X
|
|
* modules.
|
|
*/
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glx.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/magsgtty.h"
|
|
#include "utils/geometry.h"
|
|
#include "graphics/graphics.h"
|
|
#include "windows/windows.h"
|
|
#include "graphics/graphicsInt.h"
|
|
#include "textio/textio.h"
|
|
#include "textio/txcommands.h"
|
|
#include "utils/signals.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/hash.h"
|
|
#include "grOGLInt.h"
|
|
#include "utils/paths.h"
|
|
|
|
/* C99 compat */
|
|
#include "dbwind/dbwind.h"
|
|
#include "utils/main.h"
|
|
#include "utils/malloc.h"
|
|
|
|
GLubyte **grOGLStipples;
|
|
HashTable grOGLWindowTable;
|
|
extern Display *grXdpy; /* grX11thread.c */
|
|
GLXContext grXcontext;
|
|
extern int grXscrn; /* grX11su1.c */
|
|
extern int pipeRead, pipeWrite; /* grX11su1.c */
|
|
extern int Xhelper; /* grX11su1.c */
|
|
extern Visual *grVisual; /* grX11su1.c */
|
|
|
|
#ifdef HAVE_PTHREADS
|
|
extern int writePipe;
|
|
extern int readPipe; /* As seen from child */
|
|
#endif
|
|
|
|
OGL_CURRENT oglCurrent= {(XFontStruct *)NULL, 0,0,0,0, (Window)0, (MagWindow *)NULL};
|
|
|
|
/* This is kind of a long story, and very kludgy, but the following
|
|
* things need to be defined as externals because of the way lint
|
|
* libraries are made by taking this module and changing all procedures
|
|
* names "Xxxx" to "Grxxx". The change is only done at the declaration
|
|
* of the procedure, so we need these declarations to handle uses
|
|
* of those names, which don't get modified. Check out the Makefile
|
|
* for details on this.
|
|
*/
|
|
|
|
extern void GrOGLClose(), GrOGLFlush();
|
|
extern void GrOGLDelete(), GrOGLConfigure(), GrOGLRaise(), GrOGLLower();
|
|
extern void GrOGLLock(), GrOGLUnlock(), GrOGLIconUpdate();
|
|
extern bool GrOGLInit(), GrOGLCreate();
|
|
extern void grOGLWStdin();
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
* groglSetWMandC:
|
|
* This is a local routine that resets the value of the current
|
|
* write mask and color, if necessary.
|
|
*
|
|
* Results: None.
|
|
*
|
|
* Side Effects: None.
|
|
*
|
|
* Errors: None.
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
groglSetWMandC (mask, c)
|
|
int mask; /* New value for write mask */
|
|
int c; /* New value for current color */
|
|
{
|
|
static int oldMask = -1;
|
|
static int oldColor = -1;
|
|
|
|
int lr, lb, lg;
|
|
GLfloat fr, fb, fg;
|
|
GLfloat aval = 0.75; /* Alpha value */
|
|
|
|
if (mask == -65) mask = 127; /* All planes */
|
|
if (mask == oldMask && c == oldColor) return;
|
|
|
|
GR_X_FLUSH_BATCH();
|
|
|
|
GrGetColor(c, &lr, &lb, &lg);
|
|
|
|
fr = ((GLfloat)lr / 255);
|
|
fg = ((GLfloat)lg / 255);
|
|
fb = ((GLfloat)lb / 255);
|
|
|
|
if (mask == 127)
|
|
glDisable(GL_BLEND);
|
|
else {
|
|
/* Calculate a "supercolor", out of normal color range, but which */
|
|
/* results in the desired color after a blend with the background. */
|
|
|
|
fr = fr * 2 - 0.8;
|
|
fg = fg * 2 - 0.8;
|
|
fb = fb * 2 - 0.8;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
glColor4f(fr, fb, fg, aval);
|
|
|
|
oldMask = mask;
|
|
oldColor = c;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
* groglSetLineStyle:
|
|
* This local routine sets the current line style.
|
|
*
|
|
* Results: None.
|
|
*
|
|
* Side Effects:
|
|
* A new line style is output to the display.
|
|
*
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
groglSetLineStyle (style)
|
|
int style; /* New stipple pattern for lines. */
|
|
{
|
|
static int oldStyle = -1;
|
|
GLushort glstyle;
|
|
|
|
style &= 0xFF;
|
|
if (style == oldStyle) return;
|
|
oldStyle = style;
|
|
GR_X_FLUSH_BATCH();
|
|
|
|
switch (style) {
|
|
case 0xFF:
|
|
case 0x00:
|
|
glDisable(GL_LINE_STIPPLE);
|
|
break;
|
|
default:
|
|
glstyle = style | (style << 8);
|
|
glEnable(GL_LINE_STIPPLE);
|
|
glLineStipple(1, glstyle);
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
* groglSetSPattern:
|
|
* xSetSPattern associates stipple patterns with
|
|
* OpenGL stipples. This is a local routine
|
|
* called from grStyle.c.
|
|
*
|
|
* Results: None.
|
|
*
|
|
* Side Effects: None.
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
groglSetSPattern (sttable, numstipples)
|
|
int **sttable; /* The table of patterns */
|
|
int numstipples; /* Number of stipples */
|
|
{
|
|
int i, j, k, n;
|
|
GLubyte *pdata;
|
|
|
|
grOGLStipples = (GLubyte **)mallocMagic(numstipples * sizeof(GLubyte *));
|
|
for (k = 0; k < numstipples; k++)
|
|
{
|
|
pdata = (GLubyte *)mallocMagic(128 * sizeof(GLubyte));
|
|
n = 0;
|
|
|
|
/* expand magic's default 8x8 stipple to OpenGL's 32x32 */
|
|
|
|
for (i = 0; i < 32; i++)
|
|
for (j = 0; j < 4; j++)
|
|
pdata[n++] = (GLubyte)sttable[k][i % 8];
|
|
|
|
grOGLStipples[k] = pdata;
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
* groglSetStipple:
|
|
* This routine sets the Xs current stipple number.
|
|
*
|
|
* Results: None.
|
|
*
|
|
* Side Effects:
|
|
* The current clipmask in the X is set to stipple,
|
|
* if it wasn't that already.
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
groglSetStipple (stipple)
|
|
int stipple; /* The stipple number to be used. */
|
|
{
|
|
static int oldStip = -1;
|
|
if (stipple == oldStip) return;
|
|
oldStip = stipple;
|
|
GR_X_FLUSH_BATCH();
|
|
if (stipple == 0 || stipple > grNumStipples) {
|
|
glDisable(GL_POLYGON_STIPPLE);
|
|
} else {
|
|
if (grOGLStipples[stipple] == (GLubyte *)NULL) MainExit(1);
|
|
glEnable(GL_POLYGON_STIPPLE);
|
|
glPolygonStipple(grOGLStipples[stipple]);
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
* GrOGLInit:
|
|
* GrOGLInit initializes the graphics display and clears its screen.
|
|
* Files must have been previously opened with GrSetDisplay();
|
|
*
|
|
* Results: TRUE if successful.
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
GrOGLInit()
|
|
{
|
|
XVisualInfo *grVisualInfo;
|
|
static int attributeList[] = { GLX_RGBA, None, None };
|
|
static char *OGLCMapType = "OpenGL";
|
|
|
|
grCMapType = OGLCMapType;
|
|
grDStyleType = OGLCMapType;
|
|
|
|
#ifdef HAVE_PTHREADS
|
|
XInitThreads();
|
|
#endif
|
|
|
|
grXdpy = XOpenDisplay(NULL);
|
|
if (grXdpy == NULL)
|
|
{
|
|
TxError("Couldn't open display; check DISPLAY variable\n");
|
|
return FALSE;
|
|
}
|
|
grXscrn = DefaultScreen(grXdpy);
|
|
grVisualInfo = glXChooseVisual(grXdpy, grXscrn, attributeList);
|
|
if (!grVisualInfo)
|
|
{
|
|
/* Try for a double-buffered configuration (added by Holger Vogt) */
|
|
attributeList[1] = GLX_DOUBLEBUFFER;
|
|
grVisualInfo = glXChooseVisual(grXdpy, grXscrn, attributeList);
|
|
if (!grVisualInfo)
|
|
{
|
|
TxError("No suitable visual!\n");
|
|
MainExit(1);
|
|
}
|
|
}
|
|
grXscrn = grVisualInfo->screen;
|
|
grVisual = grVisualInfo->visual;
|
|
oglCurrent.depth = grVisualInfo->depth;
|
|
|
|
/* Note: The last parameter is GL_TRUE for direct rendering. */
|
|
/* Direct rendering has a speedup advantange for raw rendering, but */
|
|
/* disallows X11 operations such as XCopyArea, which prevents the */
|
|
/* implementation of backing store and fast screen refreshes. So */
|
|
/* we force an indirect rendering context through the X server. */
|
|
|
|
grXcontext = glXCreateContext(grXdpy, grVisualInfo, NULL, GL_FALSE);
|
|
|
|
/* Basic GL parameters */
|
|
|
|
glLineWidth(1.0);
|
|
glShadeModel (GL_FLAT);
|
|
glPixelStorei(GL_PACK_LSB_FIRST, TRUE);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
HashInit(&grOGLWindowTable,8,HT_WORDKEYS);
|
|
|
|
/* Globally-accessed variables */
|
|
grNumBitPlanes = oglCurrent.depth;
|
|
grBitPlaneMask = (1 << oglCurrent.depth) - 1;
|
|
|
|
if (grVisualInfo != NULL) XFree(grVisualInfo);
|
|
return groglPreLoadFont();
|
|
}
|
|
|
|
/*---------------------------------------------------------
|
|
* GrOGLClose:
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* Helper process/thread killed.
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLClose()
|
|
{
|
|
if (grXdpy == NULL) return;
|
|
TxDelete1InputDevice(pipeRead);
|
|
close(pipeRead);
|
|
#ifndef HAVE_PTHREADS
|
|
kill(Xhelper, SIGKILL);
|
|
do {} while (wait(0) != Xhelper);
|
|
#endif
|
|
XCloseDisplay(grXdpy);
|
|
#ifdef HAVE_PTHREADS
|
|
xloop_end();
|
|
#endif
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
* GrOGLFlush:
|
|
* Flush output to display.
|
|
*
|
|
* Flushing is done automatically the next time input is read,
|
|
* so this procedure should not be used very often.
|
|
*
|
|
* Results: None.
|
|
*
|
|
* Side Effects: None.
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLFlush()
|
|
{
|
|
GR_X_FLUSH_BATCH();
|
|
glFlush();
|
|
glFinish();
|
|
}
|
|
|
|
/*------------------------------------------------------*/
|
|
/* Translate event coordinate to window coordinate */
|
|
/* (y is flipped relative to the window top) */
|
|
/*------------------------------------------------------*/
|
|
|
|
#define glTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n))
|
|
|
|
/*
|
|
int
|
|
glTransYs(int wy)
|
|
{
|
|
int my;
|
|
GLint vparms[4];
|
|
|
|
glGetIntegerv(GL_VIEWPORT, vparms);
|
|
my = vparms[3] - wy;
|
|
|
|
return my;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
* Set the OpenGL viewport (projection matrix) for the current window
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
void
|
|
oglSetProjection(llx, lly, width, height)
|
|
int llx, lly, width, height;
|
|
{
|
|
glXMakeCurrent(grXdpy, (GLXDrawable)oglCurrent.window, grXcontext);
|
|
|
|
#ifndef OGL_SERVER_SIDE_ONLY
|
|
/* For batch-processing lines and rectangles */
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
#endif
|
|
|
|
/* Force draw to front buffer (in case of double-buffered config) */
|
|
glDrawBuffer(GL_FRONT); /* added by Holger Vogt */
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
glViewport((GLsizei)llx, (GLsizei)lly, (GLsizei) width, (GLsizei) height);
|
|
|
|
/* scale to fit window */
|
|
|
|
#ifdef OGL_INVERT_Y
|
|
glScalef(1.0 / (float)(width >> 1), -1.0 / (float)(height >> 1), 1.0);
|
|
#else
|
|
glScalef(1.0 / (float)(width >> 1), 1.0 / (float)(height >> 1), 1.0);
|
|
#endif
|
|
|
|
/* magic origin maps to window center; move to window origin */
|
|
|
|
glTranslated(-(GLsizei)(width >> 1), -(GLsizei)(height >> 1), 0);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* pipehandler() is the callback set up by TxAdd1Input. The purpose is */
|
|
/* to comply with magic's interrupt-driven protocol; magic blocks on */
|
|
/* select() until an input arrives at a registered file descriptor, */
|
|
/* then executes the callback associated with the fd, then checks to */
|
|
/* see if the Tx event queue size grew. X11Handler passes info along */
|
|
/* to X11Stdin() in the X11 version; that's because the X11 XtMainLoop */
|
|
/* is a macro and can be re-implemented using XNextEvent() calls. */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
void
|
|
pipehandler()
|
|
{
|
|
TxInputEvent *event;
|
|
XEvent xevent;
|
|
HashEntry *entry;
|
|
MagWindow *mw;
|
|
|
|
read(pipeRead, &xevent, sizeof(XEvent));
|
|
|
|
switch(xevent.type) {
|
|
case KeyPress: { /* Keyboard Callback Function */
|
|
|
|
int wx, wy, ky;
|
|
int key;
|
|
XKeyPressedEvent *KeyPressedEvent = (XKeyPressedEvent *) &xevent;
|
|
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)KeyPressedEvent->window);
|
|
mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0;
|
|
|
|
event = TxNewEvent();
|
|
|
|
read(pipeRead, &key, sizeof(int));
|
|
|
|
if (key == (int)'\015') key = (int)'\n'; /* Linefeed to Return */
|
|
|
|
event->txe_button = TX_CHARACTER;
|
|
event->txe_ch = key;
|
|
event->txe_buttonAction = TX_KEY_DOWN;
|
|
event->txe_p.p_x = KeyPressedEvent->x;
|
|
event->txe_p.p_y = glTransY(mw, KeyPressedEvent->y);
|
|
event->txe_wid = mw ? mw->w_wid : WIND_UNKNOWN_WINDOW;
|
|
TxAddEvent(event);
|
|
} break;
|
|
|
|
case ButtonPress:
|
|
case ButtonRelease: { /* Mouse Callback Function */
|
|
|
|
XButtonEvent *ButtonEvent = (XButtonEvent *) &xevent;
|
|
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)ButtonEvent->window);
|
|
mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0;
|
|
|
|
event = TxNewEvent();
|
|
switch (ButtonEvent->button) {
|
|
case Button1:
|
|
event->txe_button = TX_LEFT_BUTTON;
|
|
break;
|
|
case Button2:
|
|
event->txe_button = TX_MIDDLE_BUTTON;
|
|
break;
|
|
case Button3:
|
|
event->txe_button = TX_RIGHT_BUTTON;
|
|
break;
|
|
case Button4:
|
|
event->txe_button = TX_BUTTON_4;
|
|
break;
|
|
case Button5:
|
|
event->txe_button = TX_BUTTON_5;
|
|
break;
|
|
}
|
|
switch(ButtonEvent->type) {
|
|
case ButtonRelease:
|
|
event->txe_buttonAction = TX_BUTTON_UP;
|
|
break;
|
|
case ButtonPress:
|
|
event->txe_buttonAction = TX_BUTTON_DOWN;
|
|
break;
|
|
}
|
|
|
|
event->txe_p.p_x = ButtonEvent->x;
|
|
event->txe_p.p_y = glTransY(mw, ButtonEvent->y);
|
|
event->txe_wid = mw ? mw->w_wid : WIND_UNKNOWN_WINDOW;
|
|
|
|
TxAddEvent(event);
|
|
} break;
|
|
|
|
case ConfigureNotify: { /* Reshape/Resize Callback Function */
|
|
|
|
XConfigureEvent *ConfigureEvent = (XConfigureEvent *) &xevent;
|
|
XEvent discard;
|
|
Rect screenRect;
|
|
int width, height;
|
|
|
|
width = ConfigureEvent->width;
|
|
height = ConfigureEvent->height;
|
|
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)ConfigureEvent->window);
|
|
mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0;
|
|
|
|
screenRect.r_xbot = ConfigureEvent->x;
|
|
screenRect.r_xtop = ConfigureEvent->x + width;
|
|
screenRect.r_ybot = glTransYs(ConfigureEvent->y);
|
|
screenRect.r_ytop = glTransYs(ConfigureEvent->y + height);
|
|
|
|
SigDisableInterrupts();
|
|
|
|
/* Redraw the window */
|
|
|
|
WindReframe(mw, &screenRect, FALSE, FALSE);
|
|
WindRedisplay(mw);
|
|
SigEnableInterrupts();
|
|
|
|
} break;
|
|
|
|
case VisibilityNotify: {
|
|
XVisibilityEvent *VisEvent = (XVisibilityEvent*) &xevent;
|
|
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)VisEvent->window);
|
|
mw = (entry)?(MagWindow *)HashGetValue(entry):0;
|
|
if (!mw)
|
|
break;
|
|
|
|
switch(VisEvent->state)
|
|
{
|
|
case VisibilityUnobscured:
|
|
mw->w_flags &= ~WIND_OBSCURED;
|
|
if (mw->w_backingStore == (ClientData)NULL)
|
|
{
|
|
groglCreateBackingStore(mw);
|
|
if (mw->w_backingStore != (ClientData)NULL)
|
|
{
|
|
WindAreaChanged(mw, &mw->w_allArea);
|
|
WindUpdate();
|
|
}
|
|
}
|
|
break;
|
|
case VisibilityPartiallyObscured:
|
|
case VisibilityFullyObscured:
|
|
mw->w_flags |= WIND_OBSCURED;
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
case Expose: { /* (Re)Display Callback Function */
|
|
|
|
Rect screenRect;
|
|
XEvent discard;
|
|
XExposeEvent *ExposeEvent = (XExposeEvent*) &xevent;
|
|
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)ExposeEvent->window);
|
|
mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0;
|
|
if (!mw)
|
|
break;
|
|
|
|
screenRect.r_xbot = ExposeEvent->x;
|
|
screenRect.r_xtop = ExposeEvent->x + ExposeEvent->width;
|
|
screenRect.r_ytop = mw->w_allArea.r_ytop - ExposeEvent->y;
|
|
screenRect.r_ybot = mw->w_allArea.r_ytop -
|
|
(ExposeEvent->y + ExposeEvent->height);
|
|
|
|
if (mw->w_backingStore != (ClientData)NULL)
|
|
{
|
|
Rect surface;
|
|
(*GrLockPtr)(mw, FALSE);
|
|
(*GrGetBackingStorePtr)(mw, &screenRect);
|
|
(*GrUnlockPtr)(mw);
|
|
WindScreenToSurface(mw, &screenRect, &surface);
|
|
DBWHLRedrawPrepWindow(mw, &surface);
|
|
WindDrawBorder(mw, &screenRect);
|
|
}
|
|
else
|
|
WindAreaChanged(mw, &screenRect);
|
|
WindUpdate(mw);
|
|
|
|
} break;
|
|
|
|
case CreateNotify: {
|
|
|
|
XAnyEvent *AnyEvent = (XAnyEvent *) &xevent;
|
|
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)AnyEvent->window);
|
|
mw = (entry)?(MagWindow *)HashGetValue(entry):0;
|
|
|
|
SigDisableInterrupts();
|
|
WindView(mw);
|
|
SigEnableInterrupts();
|
|
} break;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------
|
|
* oglSetDisplay:
|
|
* This routine sets the appropriate parameters so that
|
|
* Magic will work with glX.
|
|
*
|
|
* Results: success / fail
|
|
*
|
|
*---------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
oglSetDisplay (dispType, outFileName, mouseFileName)
|
|
char *dispType; /* arguments not used by X */
|
|
char *outFileName;
|
|
char *mouseFileName;
|
|
{
|
|
int fildes[2], fildes2[2];
|
|
char *planecount;
|
|
char *fullname;
|
|
FILE* f;
|
|
bool execFailed = FALSE;
|
|
|
|
WindPackageType = WIND_X_WINDOWS; /* This works okay. */
|
|
|
|
grCursorType = "bw";
|
|
|
|
WindScrollBarWidth = 14;
|
|
|
|
pipe(fildes);
|
|
pipe(fildes2);
|
|
pipeRead = fildes[0];
|
|
pipeWrite = fildes2[1];
|
|
|
|
TxAdd1InputDevice(pipeRead, pipehandler, (ClientData) NULL);
|
|
|
|
#ifdef HAVE_PTHREADS
|
|
writePipe = fildes[1];
|
|
readPipe = fildes2[0];
|
|
#else
|
|
#ifdef CYGWIN
|
|
f = PaOpen(X11HELP_PROG, "r", ".exe",
|
|
HELPER_PATH, (char *) NULL, &fullname);
|
|
#else
|
|
f = PaOpen(X11HELP_PROG, "r", (char *) NULL,
|
|
HELPER_PATH, (char *) NULL, &fullname);
|
|
#endif
|
|
if (f == NULL) {
|
|
int error;
|
|
TxError("Couldn't find helper process %s in search path \"%s\"\n",
|
|
X11HELP_PROG, HELPER_PATH);
|
|
error = 0;
|
|
write(fildes[1], &error, 4);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
fclose(f);
|
|
}
|
|
|
|
FORK(Xhelper);
|
|
if (Xhelper == 0) { /* Child process */
|
|
char argv[2][100];
|
|
|
|
sprintf(argv[0], "%s", fullname);
|
|
sprintf(argv[1], "%d %d", fildes2[0],fildes[1]);
|
|
if (execl(argv[0], argv[0], argv[1], 0) != 0)
|
|
{
|
|
execFailed = TRUE;
|
|
TxError("Couldn't execute helper process \"%s\".\n", fullname);
|
|
TxFlush();
|
|
/* we're the child process -- don't muck things up by returning */
|
|
_exit(656); /* see vfork man page for reason for _exit() */
|
|
}
|
|
};
|
|
sleep(1);
|
|
#endif
|
|
|
|
/* Set up the procedure values in the indirection table. */
|
|
|
|
GrPixelCorrect = 0;
|
|
|
|
GrLockPtr = GrOGLLock;
|
|
GrUnlockPtr = GrOGLUnlock;
|
|
GrInitPtr = GrOGLInit;
|
|
GrClosePtr = GrOGLClose;
|
|
GrSetCMapPtr = GrOGLSetCMap;
|
|
|
|
GrEnableTabletPtr = GrOGLEnableTablet;
|
|
GrDisableTabletPtr = GrOGLDisableTablet;
|
|
GrSetCursorPtr = GrOGLSetCursor;
|
|
GrTextSizePtr = GrOGLTextSize;
|
|
GrDrawGlyphPtr = GrOGLDrawGlyph;
|
|
GrReadPixelPtr = GrOGLReadPixel;
|
|
GrFlushPtr = GrOGLFlush;
|
|
|
|
GrCreateWindowPtr = GrOGLCreate;
|
|
GrDeleteWindowPtr = GrOGLDelete;
|
|
GrConfigureWindowPtr = GrOGLConfigure;
|
|
GrOverWindowPtr = GrOGLRaise;
|
|
GrUnderWindowPtr = GrOGLLower;
|
|
GrUpdateIconPtr = GrOGLIconUpdate;
|
|
GrBitBltPtr = GrOGLBitBlt;
|
|
|
|
GrFreeBackingStorePtr = groglFreeBackingStore;
|
|
GrCreateBackingStorePtr = groglCreateBackingStore;
|
|
GrGetBackingStorePtr = groglGetBackingStore;
|
|
GrPutBackingStorePtr = groglPutBackingStore;
|
|
GrScrollBackingStorePtr = groglScrollBackingStore;
|
|
|
|
/* local indirections */
|
|
grSetSPatternPtr = groglSetSPattern;
|
|
grPutTextPtr = groglPutText;
|
|
#ifdef VECTOR_FONTS
|
|
grFontTextPtr = groglFontText;
|
|
#endif
|
|
grDefineCursorPtr = groglDefineCursor;
|
|
grDrawGridPtr = groglDrawGrid;
|
|
grDrawLinePtr = groglDrawLine;
|
|
grSetWMandCPtr = groglSetWMandC;
|
|
grFillRectPtr = groglFillRect;
|
|
grSetStipplePtr = groglSetStipple;
|
|
grSetLineStylePtr = groglSetLineStyle;
|
|
grSetCharSizePtr = groglSetCharSize;
|
|
grFillPolygonPtr = groglFillPolygon;
|
|
|
|
if (execFailed)
|
|
{
|
|
TxError("Execution failed!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
TxAdd1InputDevice(fileno(stdin), grOGLWStdin, (ClientData) NULL);
|
|
|
|
if (!GrOGLInit())
|
|
{
|
|
return FALSE;
|
|
}
|
|
GrScreenRect.r_xbot = 0;
|
|
GrScreenRect.r_ybot = 0;
|
|
GrScreenRect.r_xtop = DisplayWidth(grXdpy,grXscrn);
|
|
GrScreenRect.r_ytop = DisplayHeight(grXdpy,grXscrn);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* grOGLWStdin --
|
|
* Handle the stdin device for X window interface.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* Adds events to the event queue.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
/*ARGSUSED*/
|
|
|
|
void
|
|
grOGLWStdin(fd, cdata)
|
|
int fd;
|
|
ClientData cdata;
|
|
{
|
|
int ch;
|
|
TxInputEvent *event;
|
|
|
|
event = TxNewEvent();
|
|
ch = getc(stdin);
|
|
if (ch == EOF)
|
|
event->txe_button = TX_EOF;
|
|
else
|
|
event->txe_button = TX_CHARACTER;
|
|
event->txe_ch = ch;
|
|
event->txe_buttonAction = 0;
|
|
event->txe_wid = WIND_NO_WINDOW;
|
|
event->txe_p.p_x = GR_CURSOR_X;
|
|
event->txe_p.p_y = GR_CURSOR_Y;
|
|
TxAddEvent(event);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLCreate --
|
|
* Create a new window under OpenGL
|
|
* Bind OpenGL window to Magic Window w.
|
|
*
|
|
* Results:
|
|
* Success/Fail
|
|
*
|
|
* Side Effects:
|
|
* Window created, window ID send to OGLhelper.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
GrOGLCreate(w, name)
|
|
MagWindow *w;
|
|
char *name;
|
|
{
|
|
Window wind;
|
|
HashEntry *entry;
|
|
static int firstWindow = 1;
|
|
XSizeHints *xsh;
|
|
char *windowplace;
|
|
char *option = (firstWindow)?"window":"newwindow";
|
|
bool result = TRUE;
|
|
int x = w->w_frameArea.r_xbot;
|
|
int y = glTransYs(w->w_frameArea.r_ytop);
|
|
unsigned int width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot;
|
|
unsigned int height = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot;
|
|
unsigned long attribmask = CWBackPixel | CWBorderPixel | CWColormap;
|
|
XSetWindowAttributes grAttributes;
|
|
XConfigureEvent xevent;
|
|
|
|
WindSeparateRedisplay(w);
|
|
xsh = XAllocSizeHints();
|
|
if (windowplace=XGetDefault(grXdpy,"magic",option)) {
|
|
XParseGeometry(windowplace,&x,&y,&width,&height);
|
|
w->w_frameArea.r_xbot = x;
|
|
w->w_frameArea.r_xtop = x+width;
|
|
w->w_frameArea.r_ytop = glTransYs(y);
|
|
w->w_frameArea.r_ybot = glTransYs(y+height);
|
|
WindReframe(w,&(w->w_frameArea),FALSE,FALSE);
|
|
xsh->flags = USPosition | USSize;
|
|
}
|
|
else {
|
|
xsh->flags = PPosition|PSize;
|
|
}
|
|
|
|
grAttributes.colormap = XCreateColormap(grXdpy, RootWindow(grXdpy, grXscrn),
|
|
grVisual, AllocNone);
|
|
grAttributes.background_pixel = WhitePixel(grXdpy, grXscrn);
|
|
grAttributes.border_pixel = BlackPixel(grXdpy,grXscrn);
|
|
|
|
if (wind = XCreateWindow(grXdpy, RootWindow(grXdpy, grXscrn),
|
|
x, y, width, height, 0, oglCurrent.depth, InputOutput,
|
|
grVisual, attribmask, &grAttributes)) {
|
|
xsh->x = w->w_frameArea.r_xbot;
|
|
xsh->y = glTransYs(w->w_frameArea.r_ytop);
|
|
xsh->width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot;
|
|
xsh->height= w->w_frameArea.r_ytop - w->w_frameArea.r_ybot;
|
|
XSetStandardProperties(grXdpy, wind, (name == NULL) ? "magic" : name,
|
|
"magic", None, 0, 0, xsh);
|
|
|
|
XMapWindow(grXdpy, wind);
|
|
|
|
oglCurrent.window = wind;
|
|
oglCurrent.mw = w;
|
|
glXMakeCurrent(grXdpy, (GLXDrawable)wind, grXcontext);
|
|
|
|
w->w_grdata = (ClientData) wind;
|
|
entry = HashFind(&grOGLWindowTable, (char *)wind);
|
|
HashSetValue(entry,w);
|
|
XDefineCursor(grXdpy, wind, oglCurrent.cursor);
|
|
GrOGLIconUpdate(w, w->w_caption);
|
|
|
|
#ifdef HAVE_PTHREADS
|
|
xloop_create(wind);
|
|
#else
|
|
XSync(grXdpy,0);
|
|
|
|
write(pipeWrite, (char *) &wind, sizeof(Window));
|
|
kill( Xhelper, SIGTERM);
|
|
#endif
|
|
|
|
if (firstWindow)
|
|
{
|
|
firstWindow = 0;
|
|
result = groglLoadFont();
|
|
}
|
|
|
|
/* Force a StructureNotify event to get X11Helper to paint the window */
|
|
usleep(600);
|
|
xevent.type = ConfigureNotify;
|
|
xevent.width = width;
|
|
xevent.height = height;
|
|
xevent.x = xsh->x;
|
|
xevent.y = xsh->y;
|
|
xevent.window = wind;
|
|
XSendEvent(grXdpy, wind, FALSE, StructureNotifyMask, (XEvent *)&xevent);
|
|
XFree(xsh);
|
|
return result;
|
|
}
|
|
else {
|
|
TxError("Could not open new X window\n");
|
|
result = FALSE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLDelete --
|
|
* Destroy an X window.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Window destroyed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLDelete(w)
|
|
MagWindow *w;
|
|
{
|
|
int xw;
|
|
HashEntry *entry;
|
|
|
|
xw = (Window) w->w_grdata;
|
|
entry = HashLookOnly(&grOGLWindowTable, (char *)xw);
|
|
HashSetValue(entry,NULL);
|
|
|
|
XDestroyWindow(grXdpy, xw);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLConfigure --
|
|
* Full Screen function
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* Window reconfigured to w->w_frameArea.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLConfigure(w)
|
|
MagWindow *w;
|
|
{
|
|
XMoveResizeWindow(grXdpy,(Window) w->w_grdata,
|
|
w->w_frameArea.r_xbot, glTransYs(w->w_frameArea.r_ytop),
|
|
w->w_frameArea.r_xtop - w->w_frameArea.r_xbot,
|
|
w->w_frameArea.r_ytop - w->w_frameArea.r_ybot);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLRaise --
|
|
* Raise a window to the top of the screen such that nothing
|
|
* obscures it.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* Window raised.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLRaise(w)
|
|
MagWindow *w;
|
|
{
|
|
XRaiseWindow(grXdpy, (Window) w->w_grdata );
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLLower --
|
|
* Lower a window below all other X windows.
|
|
* obscures it.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* Window lowered.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLLower(w)
|
|
MagWindow *w;
|
|
{
|
|
XLowerWindow(grXdpy, (Window) w->w_grdata );
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLLock --
|
|
* Lock a window and set global variables "oglCurrent.window"
|
|
* and "oglCurrent.mw" to reference the locked window.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* Window locked.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLLock(w, flag)
|
|
MagWindow *w;
|
|
bool flag;
|
|
{
|
|
grSimpleLock(w, flag);
|
|
if ( w != GR_LOCK_SCREEN )
|
|
{
|
|
oglCurrent.mw = w;
|
|
oglCurrent.window = (Window) w->w_grdata;
|
|
|
|
oglSetProjection(w->w_allArea.r_xbot, w->w_allArea.r_ybot,
|
|
w->w_allArea.r_xtop - w->w_allArea.r_xbot,
|
|
w->w_allArea.r_ytop - w->w_allArea.r_ybot);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GrOGLUnlock --
|
|
* Unlock a window, flushing stuff out to the display.
|
|
*
|
|
* Results:
|
|
* Display update.
|
|
*
|
|
* Side Effects:
|
|
* Window unlocked.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLUnlock(w)
|
|
MagWindow *w;
|
|
{
|
|
GrOGLFlush();
|
|
grSimpleUnlock(w);
|
|
}
|
|
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* GrOGLIconUpdate -- updates the icon text with the window script
|
|
*
|
|
* Results: none
|
|
*
|
|
* Side Effects: changes the icon text
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GrOGLIconUpdate(w,text)
|
|
MagWindow *w;
|
|
char *text;
|
|
{
|
|
Window wind = (Window) w->w_grdata;
|
|
XClassHint class;
|
|
char *brack;
|
|
|
|
if (w->w_grdata == (ClientData)NULL) return;
|
|
class.res_name = "magic";
|
|
class.res_class = "magic";
|
|
XSetClassHint( grXdpy, wind, &class);
|
|
|
|
if (text == NULL)
|
|
return;
|
|
if ((brack = strchr(text,'[')) && brack != text)
|
|
{
|
|
brack--;
|
|
*brack = 0;
|
|
XSetIconName(grXdpy,wind,text);
|
|
XStoreName(grXdpy,wind,text);
|
|
*brack = ' ';
|
|
return;
|
|
}
|
|
if ((brack = strrchr(text,' '))) text = brack+1;
|
|
XSetIconName(grXdpy,wind,text);
|
|
XStoreName(grXdpy,wind,text);
|
|
}
|