Files
magic/graphics/grOGL1.c
T
Darryl L. Miles 54f49829f2 graphics: multiple definition of `various_x11_symbols'
Solution is to make the grX11thread.c and grX11su1[5].c versions
the official location.  Another solution maybe to split them into
their own file grX11common.c that would be shared.

Multiple configurations tested, tested configurations assume X11
is available.  The configuration wording indicates X11 must be
available for all graphics enabled build configurations.

Affected symbols appear to have multiple definitions:
grCursors
grXdpy
grXscrn
pipeRead
pipeWrite
Xhelper
grVisual

GCC14 and linker will not link the final executable due to this.

GCC14 --without-tk --without-tcl
Related issue: https://github.com/RTimothyEdwards/magic/issues/323
2024-10-09 20:35:19 -04:00

1090 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;
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 (brack = strchr(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);
}