/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #define tdmWindow_c #ifndef lint static char rcsid[] = "$Header: /home/gda/dxcvs/dx/src/exec/hwrender/hwWindow.c,v 1.4 1999/05/10 15:45:36 gda Exp $"; #endif #define FLING_TIMEOUT 3 #define FLING_GNOMON_FEECHURE /* * Environment: Risc System 6000 * Current Source: $Source: /home/gda/dxcvs/dx/src/exec/hwrender/hwWindow.c,v $ * Author: Tim Murphy * */ #include #include #include #include #include #include "hwDeclarations.h" #include "hwWindow.h" #include "hwClientMessage.h" #include "hwMatrix.h" #include "hwMemory.h" #include "hwDebug.h" /* * X Function Declarations. */ extern Bool XCheckTypedWindowEvent(Display *, Window, int, XEvent *) ; #if 0 #ifdef DXD_WIN extern void XPutBackEvent(Display *, XEvent *) ; #else extern XPutBackEvent(Display *, XEvent *) ; #endif #endif /* * Internal Function Declarations */ static Error _tdmResizeImage(WinP win) ; static Error _tdmResizeWindow(WinP win, int w, int h, int *change) ; static void _tdmClearWindow(WinP win) ; static void _tdmCleanupChild(tdmChildGlobalP childGlobals) ; static Window _getTopLevelShell (Display *dpy, Window w) ; /* * These atoms are used by the window manager to notify us if we're about * to get killed (eg, evil user hits "close" item on Motif window menu). */ static Atom XA_WM_PROTOCOLS ; static Atom XA_WM_DELETE_WINDOW ; static Atom XA_GL_WINDOW_ID ; /* Other commuication Atoms */ extern struct atomRep _dxdtdmAtoms[]; /* * X error handling */ static int _tdmXerror = 0 ; void _dxfSetXError (Display *dpy, XErrorEvent *event) { char buffer[128] ; ENTRY(("_dxfSetXError(0x%x, 0x%x)",dpy, event)); XGetErrorText (dpy, event->error_code, buffer, sizeof(buffer)) ; /* DXSetError (ERROR_INTERNAL, "#13490", buffer) ; */ EXIT(("X Error: %s", buffer)); } int _dxfXErrorHandler (Display *dpy, XErrorEvent *error) { ENTRY(("_dxfXErrorHandler (0x%x, 0x%x)",dpy, error)); _dxfSetXError (dpy, error) ; _tdmXerror = 1 ; EXIT(("1")); return 1 ; } int _dxfCatchWinopenErrors (Display *dpy, XErrorEvent *rep) { /* * We get this during winopen on 3.1.5. */ ENTRY(("_dxfCatchWinopenErrors (0x%x, 0x%x)",dpy, rep)); if (rep->error_code == BadAccess) { EXIT(("BadAccess error ignored")); return 0 ; } _dxfSetXError (dpy, rep) ; EXIT(("1")); return 1 ; } /* * This function creates a graphics window (if possible on this machine), and * attaches the resulting window id to the window that the UI created. * * This function should only be called ONCE per tdmRender module instance. * It will create a graphics window each time. */ Error _dxfCreateWindow (tdmChildGlobalP globals, char *winName) { XEvent event ; XWindowAttributes attr ; unsigned long eventMask ; DEFGLOBALDATA(globals) ; DEFPORT(PORT_HANDLE) ; XWindowChanges xwc; ENTRY(("_dxfCreateWindow(0x%x, \"%s\")",globals, winName)); /* ignore spurious errors generated by some environments */ XSetErrorHandler (_dxfCatchWinopenErrors) ; /* convert text representation of window id */ PARENT_WINDOW = _dxfConvertWinName(winName) ; UI_TYPE = _dxfUIType(winName); /* Assume the window is obsured, we'll change this when we get a * visibilityNotify event. */ VISIBILITY = VisibilityFullyObscured ; /* set window size as uninitialized */ PIXW = -1 ; PIXH = -1 ; /* Mark window as unmapped */ MAPPED = 0; /* create the graphics window */ if (PARENT_WINDOW) { /* if there is a UI ... */ XGetWindowAttributes (DPY, PARENT_WINDOW, &attr) ; PRINT(("Before _dxf_CREATE_WINDOW(UI)")); if(!( XWINID = (Window)_dxf_CREATE_WINDOW (globals, winName, attr.width, attr.height))) goto error; PRINT(("After _dxf_CREATE_WINDOW")); } else { PRINT(("Before _dxf_CREATE_WINDOW (script)")); if(!( XWINID = (Window)_dxf_CREATE_WINDOW (globals, winName, 640, 480))) goto error; PRINT(("\nAfter _dxf_CREATE_WINDOW")); } /* #X * if (PARENT_WINDOW) */ if (DXUI) { /* * UI is present. * * Find the top level shell of the UI image window in order to * select for ConfigureNotify; otherwise, we don't get a * ConfigureNotify on window moves since our graphics window never * moves relative to its immediate parent. * * We need to know when the window moves since some (broken?) X * servers neither copy the graphics window's pixels along with the * window nor send exposure events. * * Also select for ConfigureNotify in the immediate parent * (wigWindow) of the graphics window in order to be informed when * the UI resizes the immediate parent in response to new camera * sizes from us. We don't seem to receive this ConfigureNotify on * the top level shell. */ TOPLEVEL = _getTopLevelShell (DPY, PARENT_WINDOW) ; if (TOPLEVEL) XSelectInput (DPY, TOPLEVEL, StructureNotifyMask) ; else /* Can't find top level UI shell */ DXErrorGoto (ERROR_UNEXPECTED, "#13570") ; /* record initial placment of top level shell */ XGetWindowAttributes (DPY, TOPLEVEL, &attr) ; PIXX = attr.x ; PIXY = attr.y ; /* reparent the graphics window */ XReparentWindow (DPY, XWINID, PARENT_WINDOW, DXD_HW_REPARENT_OFFSET_X, DXD_HW_REPARENT_OFFSET_Y) ; /* select for ConfigureNotify on our new parent */ XSelectInput (DPY, PARENT_WINDOW, StructureNotifyMask | PropertyChangeMask) ; /* setup UI client message protocol */ if (!_dxfInitCMProtocol(LWIN)) { PRINT(("UI client message protocol init failed")) ; DXErrorGoto (ERROR_INTERNAL, "#13580") ; } /* set mask for appropriate events on the graphics window */ if (PIXDEPTH == 8) /* 8 bit display requires enter/leave window events for colormap */ eventMask = VisibilityChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | KeyPressMask; else eventMask = VisibilityChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask; } /* #X follows */ else if (EXTERNALUI) { /* * No UI. Record initial placment of graphics window. Set mask for * ConfigureNotify on the graphics window along with the other events * we need. */ /* reparent the graphics window */ XReparentWindow (DPY, XWINID, PARENT_WINDOW, DXD_HW_REPARENT_OFFSET_X, DXD_HW_REPARENT_OFFSET_Y) ; XGetWindowAttributes (DPY, XWINID, &attr) ; PIXX = attr.x ; PIXY = attr.y ; if (PIXDEPTH == 8) /* 8 bit display requires enter/leave window events for colormap */ eventMask = VisibilityChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | StructureNotifyMask | KeyPressMask; else eventMask = VisibilityChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask | KeyPressMask; } /* #X end */ else { /* * No UI. Record initial placment of graphics window. Set mask for * ConfigureNotify on the graphics window along with the other events * we need. */ XGetWindowAttributes (DPY, XWINID, &attr) ; PIXX = attr.x ; PIXY = attr.y ; if (PIXDEPTH == 8) /* 8 bit display requires enter/leave window events for colormap */ eventMask = VisibilityChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | StructureNotifyMask | KeyPressMask; else eventMask = VisibilityChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask | KeyPressMask; } xwc.stack_mode = Below; XConfigureWindow(DPY, XWINID, CWStackMode, &xwc); /* this handler should handle errors from now on */ XSetErrorHandler(_dxfXErrorHandler) ; /* get the window manager to inform us if it intends to kill our window */ XA_WM_PROTOCOLS = XInternAtom (DPY, "WM_PROTOCOLS", 0) ; XA_WM_DELETE_WINDOW = XInternAtom (DPY, "WM_DELETE_WINDOW", 0) ; XA_GL_WINDOW_ID = XInternAtom (DPY, "GL_WINDOW_ID", 0) ; XChangeProperty (DPY,XWINID, XA_WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XA_WM_DELETE_WINDOW, 1) ; /* select the events we need on the graphics window */ XSelectInput (DPY, XWINID, eventMask) ; /* create a software matrix stack to shadow hardware matrix stack */ MATRIX_STACK = _dxfCreateStack() ; /* initialize hardware direct interactors */ _dxfInitDXInteractors(globals) ; if (_tdmXerror) { PRINT(("X error occured")) ; } _tdmXerror = 0 ; EXIT(("OK")); return OK ; error: EXIT(("ERROR")); return ERROR ; } /* * This is the currently defined resize behavior: * * With the UI: * * When the user changes the camera values the window will size to those * dimensions and redraw. * * When the user grabs the window corner the UI will update the camera and * the window will resize to those dimensions and redraw, isotropically * scaling for an appropriate fit. * * Without the UI: * * When the user changes the camera values the window will size to those * dimensions and redraw, scaling the image isotropically. * * When the user grabs the window corner the window will resize, and as * much of the image as will fit will be moved to the upper left corner * of the new window. The Camera will remain unchanged. The window will * automatically resize to the camera dimensions if Display is called * again. */ static Error _tdmResizeImage (WinP win) { DEFWINDATA(win); Window RootReturn ; int XReturn, YReturn, camw, camh, dummy ; unsigned int WidthReturn, HeightReturn, BorderWidthReturn, DepthReturn ; unsigned int wigW, wigH ; long winw, winh ; ENTRY(("_tdmResizeImage (0x%x)", win)); if (CAMERA) { if (! DXGetCameraResolution (CAMERA, &camw, &camh)) /* unable to get camera resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13530") ; } else /* assume we have been given an image */ if (! DXGetImageSize (OBJECT, &camw, &camh)) /* unable to get image resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13540") ; PRINT (("DX object resolution: %dx%d", camw, camh)); /* #X was * if (PARENT_WINDOW) */ if (DXUI) /* if there is a UI ... */ { XGetGeometry(DPY, PARENT_WINDOW, &RootReturn, &XReturn, &YReturn, &wigW, &wigH, &BorderWidthReturn, &DepthReturn) ; PRINT(("parent window size: %dx%d", wigW, wigH)); /* * If the image resolution and the widget window size are the same, * just get resizeWindow to set the graphics window to that size . */ if (camw == wigW && camh == wigH) _tdmResizeWindow (win, wigW, wigH, &dummy) ; else { /* * Else get the UI to make the widget size and resolution agree. * We'll get the graphics window to agree when we get the configure * notify on the widget window. */ tdmMessageData data ; /* CORRECT_SIZE = FALSE ; */ data.l[0] = camw ; data.l[1] = camh ; PRINT(("notifying UI of current resolution")) ; _dxfSendClientMessage (DPY, PARENT_WINDOW, XA_Integer, &data) ; } } else /* No UI ... */ { /* * Make sure the saved window size is correct for the GLwindow * then resize. */ XGetGeometry (DPY, XWINID, &RootReturn, &XReturn, &YReturn, (unsigned int *)&PIXW, (unsigned int *)&PIXH, &BorderWidthReturn, &DepthReturn) ; PRINT(("graphics window size: %dx%d", PIXW, PIXH)); _dxfSetInteractorWindowSize (INTERACTOR_DATA, camw, camh) ; if (camw != PIXW || camh != PIXH) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; _dxf_SET_WINDOW_SIZE (win, camw, camh) ; } _tdmResizeWindow (win, camw, camh, &dummy) ; } if (_tdmXerror) goto error ; EXIT(("OK")); return OK ; error: _tdmXerror = 0 ; EXIT(("ERROR")); return ERROR ; } static Error _tdmResizeWindow (WinP win, int w, int h, int *winSizeChange) { int camw, camh ; DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; /* * If we're not already at correct size, resize. */ ENTRY(("_tdmResizeWindow (0x%x, %d, %d, 0x%x)",win, w, h, winSizeChange)); if (w != PIXW || h != PIXH) { /* * If we have a UI set the GL window to the new size. * For script we only do this when we resizeImage. */ /* #X was * if (PARENT_WINDOW) */ if (DXUI) /* if there is a UI ... */ { _dxf_SET_WINDOW_SIZE (win, w, h) ; _dxfSetInteractorWindowSize (INTERACTOR_DATA, w, h) ; } PIXW = w ; PIXH = h ; _tdmClearWindow(win) ; *winSizeChange = 1 ; } else *winSizeChange = 0 ; if (CAMERA) { if (! DXGetCameraResolution (CAMERA, &camw, &camh)) /* unable to get camera resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13530") ; } else if (! DXGetImageSize (OBJECT, &camw, &camh)) /* unable to get image resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13540") ; PRINT(("current DX resolution: %dx%d", camw, camh)); PRINT(("current viewport: %dx%d", VIEWPORT_W, VIEWPORT_H)); if (*winSizeChange || VIEWPORT_W != camw || VIEWPORT_H != camh) { _dxf_SET_VIEWPORT (PORT_CTX, 0, camw-1, h-camh, h-1) ; _dxfSetViewport (MATRIX_STACK, 0, camw-1, h-camh, h-1) ; /* !!!! check for increment view_state twice !!!! */ _dxfInteractorViewChanged(INTERACTOR_DATA) ; VIEWPORT_W = camw ; VIEWPORT_H = camh ; } if (_tdmXerror) goto error ; CORRECT_SIZE = TRUE ; EXIT(("OK")); return OK ; error: _tdmXerror = 0 ; EXIT(("ERROR")); return ERROR ; } /* * _dxfProcessEvents() is invoked in two ways: 1) from tdmRender() in * response to a new DX object, camera, or render option; and 2) as a * callback in response to input on the file associated with the X * display connection. */ extern int _dxf_ExIsExecuting(); static Bool checkDestroy(Display *d, XEvent *ev, char *arg) { return (ev->type == DestroyNotify); } Error _dxfProcessEvents (int fd, tdmChildGlobalP globals, int flags) { Display *dpy ; XEvent ev ; unsigned int mask; int doRedraw, fromTdmRender, winSizeChange ; tdmInteractorReturn R ; XWindowAttributes attr; static Time lasttime = 0 ; DEFGLOBALDATA(globals) ; DEFPORT(PORT_HANDLE) ; int dxEventMask = EVENT_MASK(globals->CrntInteractor); Window eventWindow; if (fd != -1) DEBUG_MARKER("_dxfProcessEvents ENTRY"); ENTRY(("_dxfProcessEvents (%d, 0x%x)",fd, globals)); /* * Look ahead for destroy event */ if (XCheckIfEvent(DPY, &ev, checkDestroy, NULL)) { DXMessage("Found destroy notify... cleaning up"); GL_WINDOW = FALSE; _tdmCleanupChild(globals) ; goto done; } dpy = DPY ; /* assume we don't need to refresh image */ doRedraw = FALSE ; if (fd == -1) { /* remap window if unmapped */ if (! MAPPED) { XEvent event; PRINT(("mapping window %d", XWINID)); if(DXUI) { XChangeProperty(DPY,PARENT_WINDOW, XA_GL_WINDOW_ID, XA_GL_WINDOW_ID, 32, PropModeReplace, (unsigned char*)&XWINID, 1); for((*(XPropertyEvent*)&event).state = !PropertyDelete; (*(XPropertyEvent*)&event).state != PropertyDelete;){ /* wait for UI to respond before starting to draw */ XWindowEvent (DPY, PARENT_WINDOW, PropertyChangeMask, &event) ; } } /* #X follows */ else if (EXTERNALUI) { /* map the graphics window */ XMapWindow (DPY, PARENT_WINDOW) ; XMapWindow (DPY, XWINID) ; if (STEREOSYSTEMMODE >= 0) { if (XWINID != LEFTWINDOW) XMapWindow (DPY, LEFTWINDOW) ; if (XWINID != RIGHTWINDOW) XMapWindow (DPY, RIGHTWINDOW) ; } } /* #X end */ else { /* map the graphics window */ XMapWindow (DPY, XWINID) ; if (STEREOSYSTEMMODE >= 0) { if (XWINID != LEFTWINDOW) XMapWindow (DPY, LEFTWINDOW) ; if (XWINID != RIGHTWINDOW) XMapWindow (DPY, RIGHTWINDOW) ; } else XWindowEvent (DPY, XWINID, ExposureMask, &event) ; /* wait for pending requests to be processed by X * before graphics output */ } XSync (DPY, False) ; MAPPED = 1 ; } doRedraw = 1; /* adjust graphics window image size to camera image size if necessary */ _tdmResizeImage(LWIN) ; } /* * Loop while events pending or until UI responds to new camera size with * a ConfigureNotify. */ while (XPending(dpy) || !CORRECT_SIZE) { #if defined(DXD_HW_WINDOW_DESTRUCTION_CHECK) /* * Check to ensure graphics window still exists. On some * architectures (SGI/GL) the graphics window dies without * notification and breaks the connection to the DX server on the * next graphics API call. */ XSync(dpy, False); GL_WINDOW = XGetWindowAttributes(dpy,XWINID,&attr); #else /* set the global variable to TRUE on all other arch. */ GL_WINDOW = TRUE; #endif XNextEvent(dpy, &ev) ; switch (ev.type) { case KeyPress: if (flags || !_dxf_ExIsExecuting()) { PRINT (("KeyPress")) ; if (!CORRECT_SIZE) continue ; if (! (dxEventMask & DXEVENT_KEYPRESS)) { Window tmp = ev.xany.window; ev.xany.window = PARENT_WINDOW; XSendEvent(dpy, PARENT_WINDOW, True, 0, &ev); ev.xany.window = tmp; } else { char buf[32]; XLookupString(&ev, buf, 32, NULL, NULL); if (buf[0]) tdmKeyStruck(globals->CrntInteractor, ev.xkey.x, ev.xkey.y, buf[0], ev.xkey.state); } } break; case ConfigureNotify: PRINT (("ConfigureNotify")); if (DXUI) { /* * UI case: ConfigureNotify selected on top level shell and * the immediate parent. */ winSizeChange = 0 ; if (ev.xconfigure.window == PARENT_WINDOW) { /* check for size changes on the immediate parent only */ XWindowAttributes attr ; XGetWindowAttributes (dpy, PARENT_WINDOW, &attr) ; _tdmResizeWindow (LWIN, attr.width, attr.height, &winSizeChange) ; } } else /* #X comment changed * Script or external UI case: ConfigureNotify selected * on graphics window. */ _tdmResizeWindow (LWIN, ev.xconfigure.width, ev.xconfigure.height, &winSizeChange) ; /* * If no window size change, check for movement. We have to do * this since some (broken) X servers neither copy the * graphics window's pixels nor generate an exposure event on * movement. * * HP and IBM handle this correctly. Need to check on Sun and SGI */ #if !(DXD_HW_XSERVER_MOVE_OK) if (!winSizeChange && (ev.xconfigure.x != PIXX || ev.xconfigure.y != PIXY)) { doRedraw = TRUE ; PIXX = ev.xconfigure.x ; PIXY = ev.xconfigure.y ; } #endif break ; case ClientMessage: PRINT (("ClientMessage")) ; /* check for window manager kill using ICCC protocol */ if (ev.xclient.message_type == XA_WM_PROTOCOLS) { PRINT (("window manager kill")) ; GL_WINDOW = FALSE; _tdmCleanupChild(globals) ; goto done ; } #if 1 /* #X was * if (PARENT_WINDOW && */ else if (DXUI && ev.xclient.message_type == ATOM(GLDestroyWindow)) { _tdmCleanupChild(globals); goto done; } #endif /* #X was * if (PARENT_WINDOW) */ else if (DXUI) _dxfReceiveClientMessage (globals, (XClientMessageEvent *) &ev, &doRedraw) ; break ; case ButtonPress: XSetInputFocus(DPY, XWINID, RevertToPointerRoot, CurrentTime); eventWindow = ev.xbutton.window; if (flags || !_dxf_ExIsExecuting()) { PRINT (("ButtonPress")) ; if (!CORRECT_SIZE) continue ; if ((ev.xbutton.button == Button1 && !(dxEventMask & DXEVENT_LEFT)) || (ev.xbutton.button == Button2 && !(dxEventMask & DXEVENT_MIDDLE)) || (ev.xbutton.button == Button3 && !(dxEventMask & DXEVENT_RIGHT))) { XSendEvent(dpy, PARENT_WINDOW, True, 0, &ev); } else { if (ev.xbutton.time - lasttime < 350) { PRINT(("DoubleClick")) ; lasttime = 0 ; tdmDoubleClick (globals->CrntInteractor, ev.xbutton.x, ev.xbutton.y, &R) ; /* #X was * if (PARENT_WINDOW) */ if (DXUI) _dxfSendInteractorData (globals, globals->CrntInteractor, &R) ; } else { /* sample mouse pointer to drive interactor */ time_t t0, t1 ; Window windummy ; int n, idummy, x, y, x0, y0, xlast, ylast, dx, dy, button ; n = 0 ; t0 = time(0) ; x0 = xlast = ev.xbutton.x ; y0 = ylast = ev.xbutton.y ; button = ev.xbutton.button ; lasttime = ev.xbutton.time ; tdmStartStroke (globals->CrntInteractor, x0, y0, button, ev.xbutton.state) ; XQueryPointer (dpy, eventWindow, &windummy, &windummy, &idummy, &idummy, &x, &y, &mask) ; /* keep going until a button-up */ while (mask & (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask)) { /* maintain a count to compute average fling deltas */ if (x != xlast || y != ylast) { xlast = x ; ylast = y ; n++ ; } tdmStrokePoint (globals->CrntInteractor, x, y, INTERACTOR_BUTTON_DOWN, mask) ; XQueryPointer (dpy, eventWindow, &windummy, &windummy, &idummy, &idummy, &x, &y, &mask) ; } if (!_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(), SF_FLING)) { /* * If user has not asked for FLING (via export of undocumented * env variable)... behave normally. */ XCheckWindowEvent (dpy, eventWindow, ButtonReleaseMask, &ev) ; tdmStrokePoint (globals->CrntInteractor, ev.xbutton.x, ev.xbutton.y, INTERACTOR_BUTTON_UP, ev.xbutton.state) ; } else { /* See if fling conditions have been met */ t1 = time(0) ; dx = n ? (x - x0) / n : 0 ; dy = n ? (y - y0) / n : 0 ; if ((dx != 0 || dy != 0) && #ifndef FLING_GNOMON_FEECHURE globals->executeOnChange && #endif (t1 - t0 < FLING_TIMEOUT) && (x<0 || y<0 || x>PIXW || y>PIXH) && ((button == 2 && (globals->CrntInteractor == globals->RoamGroup || globals->CrntInteractor == globals->CursorGroup)) || (button != 3 && (globals->CrntInteractor == globals->RotateGroup)))) { PRINT(("flinging...")) ; while (!XCheckWindowEvent (dpy, eventWindow, ButtonPressMask, &ev)) { xlast += dx ; ylast += dy ; tdmStrokePoint (globals->CrntInteractor, xlast, ylast, INTERACTOR_BUTTON_DOWN, ev.xbutton.state) ; } } else { /* * if not, behave normally. */ XCheckWindowEvent (dpy, eventWindow, ButtonReleaseMask, &ev) ; if (ev.xbutton.x != x || ev.xbutton.y != y) tdmStrokePoint (globals->CrntInteractor, ev.xbutton.x, ev.xbutton.y, INTERACTOR_BUTTON_UP, ev.xbutton.state) ; } } _dxfSendInteractorData (globals, globals->CrntInteractor, 0) ; } } } break ; case VisibilityNotify: PRINT(("VisibilityNotify")) ; VISIBILITY = ev.xvisibility.state ; break ; case Expose: PRINT (("Expose")) ; doRedraw = TRUE ; break ; case EnterNotify: /* we only receive this event from 8-bit windows */ PRINT (("EnterNotify")) ; XInstallColormap (dpy, CLRMAP) ; XFlush(dpy) ; break ; case LeaveNotify: /* we only receive this event from 8-bit windows */ PRINT (("LeaveNotify")) ; XUninstallColormap (dpy, CLRMAP) ; XFlush(dpy) ; break ; case DestroyNotify: PRINT (("DestroyNotify")) ; if(ev.xdestroywindow.window == TOPLEVEL) break; GL_WINDOW = FALSE; _tdmCleanupChild(globals) ; goto done ; break ; default: PRINT(("ignored event %d", ev.type)) ; break ; } } if (OBJECT_TAG != DXGetObjectTag(OBJECT) || CAMERA_TAG != DXGetObjectTag((dxObject)CAMERA)) SAVE_BUF_VALID = FALSE ; #if defined(DXD_HW_WINDOW_DESTRUCTION_CHECK) if (GL_WINDOW) #endif if (doRedraw) { /* * If the window needs to be refreshed, lets try to do it from * the saved buffer, or if that fails, redraw. */ PRINT(("refreshing image")) ; /* #if defined(sgi) if (GL_WINDOW) zclear(); #endif */ #if 0 if (CAMERA) #endif { /* otherwise, redo final approximation pass */ if (! _dxfTryRestoreBuffer(LWIN)) { PRINT(("no backing store, regenerating image")); #if 0 _tdmClearWindow(LWIN) ; #endif if(!(_dxfDraw (globals, OBJECT, CAMERA, 1))) goto error; if ( _dxfTrySaveBuffer(LWIN)) { SAVEBUFOBJECTTAG = OBJECT_TAG; SAVEBUFCAMERATAG = CAMERA_TAG; } /* * Redraw any defined interactor echos. The echos can't * be saved by _dxfTrySaveBuffer() since they are updated * more frequently than once per rendering pass. */ _dxfRedrawInteractorEchos(INTERACTOR_DATA) ; } } /* tell the UI that we're ready */ /* * #X was * if ((fd == -1) && PARENT_WINDOW) */ if ((fd == -1) && DXUI) _dxfConnectUI(LWIN) ; /* XXX do we still need this ? TJM YYY I'm not sure for the UI case, but I don't think so otherwise. It causes unnecessary event looping in external UI cases. I've changed it to ONLY do it if its the DX UI. GDA */ /* hack to force client messages through immediately */ if (DXUI) _dxfSendClientMessage (dpy, XWINID, POKE_CONNECTION, 0) ; } done: if (_tdmXerror) goto error ; EXIT(("OK")); if (fd != -1) DEBUG_MARKER("_dxfProcessEvents EXIT"); return OK ; error: _tdmXerror = 0 ; EXIT(("ERROR")); if (fd != -1) DEBUG_MARKER("_dxfProcessEvents EXIT"); return ERROR ; } #if 0 typedef struct argbS { char a, b, g, r; } argbT,*argbP; void *_dxfOutputRGB(WinP win, Field i) { DEFWINDATA(win); int x, y, n, r, g, b; int w, h; RGBColor *pixels; RGBColor *from; ENTRY(("_dxfOutputRGB(0x%x, 0x%x)", win, i)); /* the next two can be static as they are only set once */ /* (all subsequent child processes will merely read them) */ static int firsttime = 1; static unsigned char gamma[256]; if (!i) { /* no image received for rendering */ DXSetError (ERROR_UNEXPECTED, "#13500" ) ; EXIT(("no image")); return NULL ; } /* increment reference count here, decrement in _dxfEndSWRenderPass() */ DXReference((dxObject)i) ; if (DXGetObjectClass ((dxObject)(i)) != CLASS_FIELD) { /* invalid image received */ DXSetError (ERROR_BAD_CLASS, "#13510") ; EXIT(("invalid image")); return NULL ; } if (! DXGetImageSize (i, &w, &h)) { /* could not get image size */ DXSetError (ERROR_INTERNAL, "#13520"); EXIT(("could not get image size")); return NULL ; } pixels = DXGetPixels(i) ; if (! pixels) { DXWarning ("#5170") ; /* no pixels found in image */ EXIT(("no pixles")); return NULL ; } n = PIXW * PIXH * sizeof(argbT); if (n != SW_BUF_SIZE) { if (SW_BUF) tdmFree(SW_BUF) ; SW_BUF = (void *) NULL; SW_BUF = (void *) tdmAllocateLocal(n); if (!SW_BUF) { SW_BUF_SIZE = 0; EXIT(("malloc failed")); return NULL; } else SW_BUF_SIZE = n; } /* create the gamma ramp */ if (firsttime) { /* create the map -- code adapted from BuildXColorMap in display.c */ int i; for (i=0; i<256; i++) gamma[i] = sqrt(i/256.0)*256.0; firsttime = 0; } /* work around an sgi compiler bug */ #define CLAMP(p) (p=(p<0?0:p), p=(p>255?255:p)) /* convert from XY to linear index */ #define INDX(x,y) (y*w + x) for (y=0; y double buffer")) ; _dxf_DOUBLE_BUFFER_MODE(PORT_CTX) ; BUFFER_MODE = DoubleBufferMode ; } } else /* mode == SingleBufferMode */ { if (BUFFER_MODE == DoubleBufferMode) /* needs changing? */ { /* * If we're going from double to single buffer mode, * clear the back buffer first to keep junk from showing * when buffer becomes visible. */ PRINT (("double buffer -> single buffer")) ; _tdmClearWindow(win) ; _dxf_SINGLE_BUFFER_MODE(PORT_CTX) ; BUFFER_MODE = SingleBufferMode ; } } EXIT(("")); } static void _tdmClearWindow (WinP win) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_tdmClearWindow (0x%x)",win)); _dxf_CLEAR_AREA (PORT_CTX, 0, PIXW - 1 , 0, PIXH - 1) ; EXIT(("")); } int _dxfTrySaveBuffer (WinP win) { XEvent xev ; XVisibilityEvent *xvis = (XVisibilityEvent *) &xev ; int camw, camh ; DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_dxfTrySaveBuffer (0x%x)", win)); /* loop all Visibility Events to determine visibility state */ while (XCheckTypedWindowEvent (DPY, XWINID, VisibilityNotify, &xev)) VISIBILITY = xvis->state ; /* if we already have a buffer, leave now */ if (SAVE_BUF_VALID) goto done ; if (CAMERA) { if (! DXGetCameraResolution(CAMERA, &camw, &camh)) /* unable to get camera resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13530") ; } else { /* assume we have been given an image */ if (! DXGetImageSize (OBJECT, &camw, &camh)) /* unable to get image resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13540") ; } /* read the window */ if (! _dxf_READ_APPROX_BACKSTORE(win, camw, camh)) { /* can't read saveunder */ DXWarning("#13550") ; SAVE_BUF_VALID = FALSE ; goto done ; } /* check to see if we are obscured */ if (VISIBILITY != VisibilityUnobscured) SAVE_BUF_VALID = FALSE ; else { /* check for Exposures and invalidate result if present */ if (XCheckTypedWindowEvent(DPY, XWINID, Expose, &xev)) { XPutBackEvent(DPY, &xev) ; SAVE_BUF_VALID = FALSE ; goto done ; } else SAVE_BUF_VALID = TRUE ; } /* give access to direct interactors */ _dxfSetInteractorImage (INTERACTOR_DATA, camw, camh, SAVE_BUF) ; /* * In some cases the backing store may be simply filled with * black pixels (i.e. Evans and Sutherland). In this case * we want the interactors to access this memory (previous line) * but we do not want to use the backing store for redraws. This * is a temporary solution to E&S glReadPixel performance probs. */ if (_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(), SF_INVALIDATE_BACKSTORE)) { SAVE_BUF_VALID = FALSE ; } done: if (_tdmXerror) goto error ; EXIT(("")); return 1; error: _tdmXerror = 0 ; EXIT(("ERROR")); return 0; } int _dxfTryRestoreBuffer (WinP win) { int camw, camh ; DEFWINDATA(win); DEFPORT(PORT_HANDLE) ; ENTRY(("_dxfTryRestoreBuffer (0x%x)",win)); /* check buffer status */ if (! SAVE_BUF_VALID) goto error ; if (CAMERA) { if (! DXGetCameraResolution(CAMERA, &camw, &camh)) /* unable to get camera resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13530") ; } else { /* assume we have been given an image */ if (! DXGetImageSize (OBJECT, &camw, &camh)) /* unable to get image resolution */ DXErrorGoto (ERROR_INVALID_DATA, "#13540") ; } /* check for presence of buffer and size */ if (! SAVE_BUF || (SAVE_BUF_SIZE != camw * camh)) goto error ; if (camw < PIXW) _dxf_CLEAR_AREA (PORT_CTX, camw, PIXW - 1, 0, PIXH - 1) ; if (camh < PIXH) _dxf_CLEAR_AREA (PORT_CTX, 0, PIXW - 1, 0, PIXH - (camh+1)) ; PRINT(("writing from backing store")); _dxf_WRITE_APPROX_BACKSTORE (win, camw, camh) ; #if defined(solaris) _dxf_SWAP_BUFFERS(PORT_CTX, XWINID); #endif done: /* If we restored from a (partialially) invalid buffer, make sure we * still refresh. */ #if 0 if (! SAVE_BUF_VALID ) goto error ; #endif EXIT(("OK")); return OK ; error: _tdmXerror = 0 ; EXIT(("ERROR")); return ERROR ; } static void _tdmCleanupChild (tdmChildGlobalP globals) { DEFGLOBALDATA(globals) ; Window tmpParentWindow = PARENT_WINDOW; Display *tmpDpy = DPY; ENTRY(("_tdmCleanupChild (0x%x)", globals)); if (globals->cacheId) { /* * DXRemove cache entry for this instance. This will cause * _dxfEndRenderModule() to be invoked as a side effect, since it is * registered as the callback for the cache deletion. */ PRINT(("cacheId exists, deleting cache entry")) ; DXSetCacheEntry (0, CACHE_PERMANENT, globals->cacheId, 0, 0) ; } EXIT(("")); } int _dxfConvertWinName(char *winName) { int i ; /* ENTRY(("_dxfConvertWinName(\"%s\")",winName)); */ for (i = strlen(winName)-1 ; i >= 0 ; i--) if (!isdigit(winName[i])) break; if (i == -1) { /* no pound signs, all digits */ /* EXIT(("0")); */ return 0 ; /* #X was * } else if (winName[i] == '#' && (i !=0 && winName[i-1] == '#')) { */ } else if ((winName[i] == '#' || winName[i] == 'X') && (i !=0 && winName[i-1] == '#')) { /* 2 pound signs */ /* EXIT(("fill in this value")); */ return atoi(&winName[i+1]) ; } else { /* EXIT(("0")); */ return 0 ; } } /* * #X follows */ int _dxfUIType(char *winName) { int i ; for (i = strlen(winName)-1 ; i >= 0 ; i--) if (!isdigit(winName[i])) break; if (i > 0 && winName[i] == '#' && i !=0 && winName[i-1] == '#') return DXD_DXUI; else if (i > 0 && winName[i] == 'X' && i !=0 && winName[i-1] == '#') return DXD_EXTERNALUI; else return DXD_NOUI; } /* #X end */ static Window _getTopLevelShell (Display *dpy, Window w) { /* * Find the top level shell widget by walking up the window hierarchy. * * NOTE: This routine WILL NOT WORK if the Local allocator is not * malloc! It calls XQueryTree() which uses malloc to allocate the * children array! */ unsigned int numChild ; Window root, parent, *childList ; ENTRY(("_getTopLevelShell (0x%x, 0x%x)", dpy, w)); while (XQueryTree (dpy, w, &root, &parent, &childList, &numChild)) { XFree((char *)childList) ; if (parent != root) w = parent ; else { EXIT(("w = 0x%x",w)) ; return w ; } } EXIT(("XQueryTree failed")) ; return 0 ; } extern Field DXMakeImageFormat(int w, int h, char *format); Field _dxfCaptureHardwareImage(tdmChildGlobalP globals) { DEFGLOBALDATA(globals) ; DEFPORT(PORT_HANDLE) ; Field image = NULL; Array colors; image = DXMakeImageFormat(PIXW, PIXH, "BYTE"); if (! image) goto error; colors = (Array)DXGetComponentValue(image, "colors"); if (! colors) goto error; if (! _dxf_READ_IMAGE(LWIN, DXGetArrayData(colors))) goto error; return image; error: DXDelete((dxObject)image); return NULL; } void _dxfSetCurrentView(WinP win, float *to, float *from, float *up, float fov, float width) { DEFWINDATA(win); CURRENT_TO[0] = to[0]; CURRENT_TO[1] = to[1]; CURRENT_TO[2] = to[2]; CURRENT_FROM[0] = from[0]; CURRENT_FROM[1] = from[1]; CURRENT_FROM[2] = from[2]; CURRENT_UP[0] = up[0]; CURRENT_UP[1] = up[1]; CURRENT_UP[2] = up[2]; CURRENT_FOV = fov; CURRENT_WIDTH = width; } /* *=================================================================== * END OF FILE * $Source: /home/gda/dxcvs/dx/src/exec/hwrender/hwWindow.c,v $ *=================================================================== */ #undef tdmWindow_c