From 35c3510ea7cd09a1715c27a75909e80b6826a5c6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 14 Sep 2017 17:03:53 -0400 Subject: [PATCH] Finished the implementation of Cairo 2D graphics (yay!). Specifically, fixed the initial background, display of text, reinstated supercolor values, and fixed the backing store coordinates. --- graphics/cairo_new/grTCairo1.c | 1392 +++++++++++++++++++++++++++++++ graphics/cairo_new/grTCairo2.c | 214 +++++ graphics/cairo_new/grTCairo3.c | 648 ++++++++++++++ graphics/cairo_new/grTCairo4.c | 137 +++ graphics/cairo_new/grTCairo5.c | 210 +++++ graphics/cairo_orig/grTCairo1.c | 1374 ++++++++++++++++++++++++++++++ graphics/cairo_orig/grTCairo2.c | 213 +++++ graphics/cairo_orig/grTCairo3.c | 647 ++++++++++++++ graphics/cairo_orig/grTCairo4.c | 138 +++ graphics/cairo_orig/grTCairo5.c | 211 +++++ graphics/grMain.c | 2 + graphics/grTCairo1.c | 133 ++- graphics/grTCairo2.c | 43 +- graphics/grTCairo3.c | 238 +++--- graphics/grTCairo4.c | 1 + graphics/grTCairo5.c | 17 +- graphics/grTCairoInt.h | 18 +- graphics/grTOGL3.c.test | 812 ------------------ graphics/grTkCommon.c | 1 + windows/windMove.c | 1 + windows/windows.h | 9 +- 21 files changed, 5468 insertions(+), 991 deletions(-) create mode 100644 graphics/cairo_new/grTCairo1.c create mode 100644 graphics/cairo_new/grTCairo2.c create mode 100644 graphics/cairo_new/grTCairo3.c create mode 100644 graphics/cairo_new/grTCairo4.c create mode 100644 graphics/cairo_new/grTCairo5.c create mode 100644 graphics/cairo_orig/grTCairo1.c create mode 100644 graphics/cairo_orig/grTCairo2.c create mode 100644 graphics/cairo_orig/grTCairo3.c create mode 100644 graphics/cairo_orig/grTCairo4.c create mode 100644 graphics/cairo_orig/grTCairo5.c delete mode 100644 graphics/grTOGL3.c.test diff --git a/graphics/cairo_new/grTCairo1.c b/graphics/cairo_new/grTCairo1.c new file mode 100644 index 00000000..37a870e7 --- /dev/null +++ b/graphics/cairo_new/grTCairo1.c @@ -0,0 +1,1392 @@ +/* grTCairo1.c + * + * Copyright (C) 2017 Open Circuit Design + * + * This file contains primitive functions for Cairo running under + * an X window system in a Tcl/Tk interpreter environment + * + * Written by Chuan Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/main.h" +#include "utils/magic.h" +#include "utils/malloc.h" +#include "utils/magsgtty.h" +#include "utils/geometry.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "textio/textio.h" +#include "textio/txcommands.h" +#include "utils/signals.h" +#include "utils/utils.h" +#include "tiles/tile.h" +#include "utils/hash.h" +#include "database/database.h" +#include "drc/drc.h" +#include "utils/macros.h" +#include "graphics/grTCairoInt.h" +#include "utils/paths.h" +#include "graphics/grTkCommon.h" + +uint8_t **grTCairoStipples; +HashTable grTCairoWindowTable; +XVisualInfo *grVisualInfo; + +TCAIRO_CURRENT tcairoCurrent = {(Tk_Font)0, 0, 0, 0, 0, + (Tk_Window)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 GrTCairoClose(), GrTCairoFlush(); +extern void GrTCairoDelete(), GrTCairoConfigure(), GrTCairoRaise(), GrTCairoLower(); +extern void GrTCairoLock(), GrTCairoUnlock(), GrTCairoIconUpdate(); +extern bool GrTCairoInit(); +extern bool GrTCairoEventPending(), GrTCairoCreate(), grtcairoGetCursorPos(); +extern int GrTCairoWindowId(); +extern char *GrTkWindowName(); /* Use routine from grTkCommon.c */ + +extern void tcairoSetProjection(); + +/*--------------------------------------------------------- + * grtcairoSetWMandC: + * This is a local routine that resets the value of the current + * write alpha (mask) and color, if necessary. + * + * Results: None. + * + * Side Effects: None. + * + * Errors: None. + *--------------------------------------------------------- + */ + +void +grtcairoSetWMandC (mask, c) +int mask; /* New value for write mask */ +int c; /* New value for current color */ +{ + static int oldColor = -1; + static int oldMask = -1; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + int lr, lb, lg; + float fr, fb, fg, aval; + + if (mask == -65) mask = 127; /* All planes */ + if (mask == oldMask && c == oldColor) return; + + GR_TCAIRO_FLUSH_BATCH(); + + GrGetColor(c, &lr, &lg, &lb); + + fr = ((float)lr / 255); + fg = ((float)lg / 255); + fb = ((float)lb / 255); + aval = ((float)mask / 127.0); + + cairo_set_source_rgba(tcairodata->context, fr, fg, fb, aval); + + oldColor = c; + oldMask = mask; +} + + +/*--------------------------------------------------------- + * grtcairoSetLineStyle: + * This local routine sets the current line style. + * + * Results: None. + * + * Side Effects: + * A new line style is output to the display. + * + *--------------------------------------------------------- + */ + +void +grtcairoSetLineStyle (style) +int style; /* New stipple pattern for lines. */ +{ + // unimplemented for cairo +} + + +/*--------------------------------------------------------- + * grtcairoSetSPattern: + * tcairoSetSPattern associates a stipple pattern with a given + * stipple number. This is a local routine called from + * grStyle.c . + * + * Results: None. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +cairo_pattern_t **stipplePatterns; + +void +grtcairoSetSPattern (sttable, numstipples) +int **sttable; /* The table of patterns */ +int numstipples; /* Number of stipples */ +{ + int i, j, k, n; + uint8_t *pdata; + + stipplePatterns = (cairo_pattern_t **)mallocMagic(sizeof(cairo_pattern_t *) * numstipples); + + grTCairoStipples = (uint8_t **)mallocMagic(numstipples * sizeof(uint8_t *)); + for (k = 0; k < numstipples; k++) + { + pdata = (uint8_t *)mallocMagic(128 * sizeof(uint8_t)); + n = 0; + + /* expand magic's default 8x8 stipple to 32x32 */ + + for (i = 0; i < 32; i++) { + for (j = 0; j < 4; j++) { + pdata[n++] = (uint8_t)sttable[k][i % 8]; + } + } + + grTCairoStipples[k] = pdata; + stipplePatterns[k] = cairo_pattern_create_for_surface(cairo_image_surface_create_for_data(pdata, CAIRO_FORMAT_A1, 32, 32, + cairo_format_stride_for_width(CAIRO_FORMAT_A1, 32))); + } +} + + +/*--------------------------------------------------------- + * grtcairoSetStipple: + * 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. + *--------------------------------------------------------- + */ + +cairo_pattern_t *currentStipple; + +void +grtcairoSetStipple (stipple) +int stipple; /* The stipple number to be used. */ +{ + static int oldStip = -1; + if (stipple == oldStip) return; + oldStip = stipple; + GR_TCAIRO_FLUSH_BATCH(); + if (stipple == 0 || stipple > grNumStipples) { + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); + } else { + if (stipplePatterns[stipple] == (cairo_pattern_t *)NULL) MainExit(1); + cairo_pattern_set_extend(stipplePatterns[stipple], CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(stipplePatterns[stipple], CAIRO_FILTER_NEAREST); + currentStipple = stipplePatterns[stipple]; + } +} + + +/*------------------------------------------------------------------------ + * GrTCairoInit: + * GrTCairoInit initializes the graphics display and clears its screen. + * Files must have been previously opened with GrSetDisplay(); + * + * Results: TRUE if successful. + * + * Notes: When 3D rendering is compiled in, we search for a double-buffered + * configuration first, because it generates the smoothest graphics, + * and fall back on a single-buffered configuration if necessary. + * For normal, 2D-only rendering, we look for a single-buffered + * configuration first because we don't use the back buffer, so a + * double-buffered configuration just wastes space. + *------------------------------------------------------------------------ + */ + +bool +GrTCairoInit () +{ + bool rstatus; + + tcairoCurrent.window = Tk_MainWindow(magicinterp); + if (tcairoCurrent.window == NULL) + { + TxError("No Top-Level Tk window available. . . is Tk running?\n"); + return FALSE; + } + + tcairoCurrent.windowid = Tk_WindowId(tcairoCurrent.window); + grXdpy = Tk_Display(tcairoCurrent.window); + tcairoCurrent.depth = Tk_Depth(tcairoCurrent.window); + + grXscrn = DefaultScreen(grXdpy); + + XVisualInfo grtemplate; + int gritems; + grtemplate.screen = grXscrn; + grtemplate.depth = 0; + grVisualInfo = XGetVisualInfo(grXdpy, VisualScreenMask, &grtemplate, &gritems); + + if (!grVisualInfo) + { + TxError("No suitable visual!\n"); + return FALSE; + } + + grXscrn = grVisualInfo->screen; + tcairoCurrent.depth = grVisualInfo->depth; + + /* Use OpenGL names for colormap and dstyle file types */ + grCMapType = "OpenGL"; + grDStyleType = "OpenGL"; + + /* Globally-accessed variables */ + grNumBitPlanes = tcairoCurrent.depth; + grBitPlaneMask = (1 << tcairoCurrent.depth) - 1; + + HashInit(&grTCairoWindowTable, 8, HT_WORDKEYS); + + return grTkLoadFont(); +} + +/*--------------------------------------------------------- + * GrTCairoClose: + * + * Results: None. + * + * Side Effects: + *--------------------------------------------------------- + */ + +void +GrTCairoClose () +{ + if (grXdpy == NULL) return; + if (grVisualInfo != NULL) XFree(grVisualInfo); + + grTkFreeFonts(); + /* Pop down Tk window but let Tcl/Tk */ + /* do XCloseDisplay() */ +} + + +/*--------------------------------------------------------- + * GrTCairoFlush: + * 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 +GrTCairoFlush () +{ + GR_TCAIRO_FLUSH_BATCH(); +} + +/* + *--------------------------------------------------------- + */ + +#define grTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n)) + +/* + *--------------------------------------------------------- + * Set the Cairo projection matrix for a window + *--------------------------------------------------------- + */ + +void +tcairoSetProjection(llx, lly, width, height) +int llx, lly, width, height; +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + /* Note that offscreen-drawing comes from the Tk Image */ + /* routines in tkCommon.c and does not have an associated */ + /* surface and context, so we need to make them. */ + + if (tcairodata == NULL) { + tcairodata = (TCairoData *)mallocMagic(sizeof(TCairoData)); + tcairodata->surface = cairo_xlib_surface_create(grXdpy, + tcairoCurrent.windowid, grVisualInfo->visual, + width, height); + tcairodata->context = cairo_create(tcairodata->surface); + tcairodata->backing_context = (ClientData)NULL; + tcairodata->backing_surface = (ClientData)NULL; + tcairoCurrent.mw->w_grdata2 = (ClientData)tcairodata; + + cairo_set_line_width(tcairodata->context, 1.0); + cairo_set_source_rgb(tcairodata->context, 0, 0, 0); + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); + } + + cairo_identity_matrix(tcairodata->context); + cairo_translate(tcairodata->context, 0, height); + cairo_scale(tcairodata->context, 1.0, -1.0); +} + + +/* + * --------------------------------------------------------------------------- + * + * TCairoEventProc --- + * + * Tk Event Handler + * + * Results: + * None. + * + * Side Effects: + * Calls functions in response to X11 events. + * + * --------------------------------------------------------------------------- + */ + +void +TCairoEventProc(clientData, xevent) +ClientData clientData; +XEvent *xevent; +{ + TxInputEvent *event; + HashEntry *entry; + Tk_Window tkwind = (Tk_Window)clientData; + Window wind; + MagWindow *mw; + unsigned char LocRedirect = TxInputRedirect; + + XKeyPressedEvent *KeyPressedEvent = (XKeyPressedEvent *) xevent; + KeySym keysym; + int nbytes; + + /* Keys and Buttons: Determine expansion of macros or redirect + * keys to the terminal or console. + */ + + switch (xevent->type) + { + case ButtonPress: + { + XButtonEvent *ButtonEvent = (XButtonEvent *) xevent; + int txbutton; + + switch (ButtonEvent->button) { + case Button1: + txbutton = TX_LEFT_BUTTON; + keysym = XK_Pointer_Button1; + break; + case Button2: + txbutton = TX_MIDDLE_BUTTON; + keysym = XK_Pointer_Button2; + break; + case Button3: + txbutton = TX_RIGHT_BUTTON; + keysym = XK_Pointer_Button3; + break; + case Button4: + txbutton = TX_BUTTON_4; + keysym = XK_Pointer_Button4; + break; + case Button5: + txbutton = TX_BUTTON_5; + keysym = XK_Pointer_Button5; + break; + } + nbytes = 0; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + if (mw && (mw->w_flags & WIND_SCROLLBARS)) + if (WindButtonInFrame(mw, ButtonEvent->x, + grXtransY(mw, ButtonEvent->y), + txbutton)) + break; + + goto keys_and_buttons; + } + break; + case KeyPress: + { + int keywstate, keymod, idx, idxmax; + char inChar[10]; + Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); + + nbytes = XLookupString(KeyPressedEvent, inChar, sizeof(inChar), + &keysym, NULL); + + if (IsModifierKey(keysym)) break; /* Don't handle modifiers */ + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + +keys_and_buttons: + + keymod = (LockMask | ControlMask | ShiftMask) + & KeyPressedEvent->state; +#ifdef __APPLE__ + if (KeyPressedEvent->state & (Mod1Mask | Mod2Mask | + Mod3Mask | Mod4Mask | Mod5Mask)) + keymod |= Mod1Mask; +#else + keymod |= (Mod1Mask & KeyPressedEvent->state); +#endif + + if (nbytes == 0) /* No ASCII equivalent */ + { + keywstate = (keymod << 16) | (keysym & 0xffff); + } + else if (!strncmp(XKeysymToString(keysym), "KP_", 3)) + { + /* keypad key (special case---would like to */ + /* differentiate between shift-KP-# and # itself) */ + keymod &= ~ShiftMask; + keywstate = (keymod << 16) | (keysym & 0xffff); + nbytes = 0; + } + else /* ASCII-valued character */ + { + if (!(keymod & (LockMask | Mod1Mask))) { + if (!(keymod & ControlMask)) + keymod &= ~ShiftMask; + else if (!(keymod & ShiftMask)) + keymod &= ~ControlMask; + } + } + + idxmax = (nbytes == 0) ? 1 : nbytes; + for (idx = 0; idx < idxmax; idx++) + { + if (inChar[idx] == 3) /* Ctrl-C interrupt */ + { + if (SigInterruptPending) + MainExit(0); /* double Ctrl-C */ + else + sigOnInterrupt(0); /* Set InterruptPending */ + break; + } + else if (nbytes > 0) + { + if ((keymod & ControlMask) && (inChar[idx] < 32)) + inChar[idx] += 'A' - 1; + + keywstate = (keymod << 16) | ((int)inChar[idx] & 0xff); + } + + /* Allow buttons to bypass the console and be */ + /* treated as macros. */ + + if (LocRedirect == TX_INPUT_REDIRECTED) + { + switch (keysym) + { + case XK_Pointer_Button1: + case XK_Pointer_Button2: + case XK_Pointer_Button3: + case XK_Pointer_Button4: + case XK_Pointer_Button5: + LocRedirect = TX_INPUT_NORMAL;; + break; + } + } + + if ((LocRedirect == TX_INPUT_REDIRECTED) && TxTkConsole) + { + Tcl_SavedResult state; + static char outstr[] = "::tkcon::Insert .text \"x\" "; + + switch (keysym) + { + case XK_Return: + TxSetPoint(KeyPressedEvent->x, + grXtransY(mw, KeyPressedEvent->y), + mw->w_wid); + TxInputRedirect = TX_INPUT_PROCESSING; + Tcl_EvalEx(consoleinterp, "::tkcon::Eval .text", + 19, 0); + TxInputRedirect = TX_INPUT_NORMAL; + TxSetPrompt('%'); + + Tcl_SaveResult(magicinterp, &state); + Tcl_EvalEx(magicinterp, "history event 0", 15, 0); + MacroDefine(mw->w_client, (int)'.', + Tcl_GetStringResult(magicinterp), NULL, + FALSE); + Tcl_RestoreResult(magicinterp, &state); + break; + case XK_Up: + Tcl_EvalEx(consoleinterp, "::tkcon::Event -1", + 17, 0); + break; + case XK_Down: + Tcl_EvalEx(consoleinterp, "::tkcon::Event 1", + 16, 0); + break; + case XK_Left: + Tcl_EvalEx(consoleinterp, ".text mark set insert " + "insert-1c ; .text see insert", 50, 0); + break; + case XK_Right: + Tcl_EvalEx(consoleinterp, ".text mark set insert " + "insert+1c ; .text see insert", 50, 0); + break; + case XK_BackSpace: case XK_Delete: + Tcl_EvalEx(consoleinterp, ".text delete insert-1c ;" + ".text see insert", 40, 0); + break; + case XK_quotedbl: case XK_backslash: case XK_bracketleft: + outstr[23] = '\\'; + outstr[24] = inChar[idx]; + outstr[25] = '\"'; + Tcl_EvalEx(consoleinterp, outstr, 26, 0); + outstr[24] = '\"'; + outstr[25] = '\0'; + default: + outstr[23] = inChar[idx]; + Tcl_EvalEx(consoleinterp, outstr, 25, 0); + break; + } + } + else if (LocRedirect == TX_INPUT_REDIRECTED) { + int tl; + if (TxBuffer == NULL) + { + TxBuffer = Tcl_Alloc(2); + *TxBuffer = '\0'; + tl = 0; + } + else + { + tl = strlen(TxBuffer); + TxBuffer = Tcl_Realloc(TxBuffer, tl + 2); + } + if (keysym == XK_BackSpace || keysym == XK_Delete) + { + if (tl >= 0) + { + if (tl > 0) + { + *(TxBuffer + tl - 1) = '\0'; + TxPrintf("\b"); + } + TxPrintf(" \b"); + TxFlushOut(); + } + } + else if (keysym == XK_Return) + { + *(TxBuffer + tl) = '\n'; + *(TxBuffer + tl + 1) = '\0'; + if (tl != 0) MacroDefine(mw->w_client, + XK_period, TxBuffer, NULL, FALSE); + TxInputRedirect = TX_INPUT_NORMAL; + TxSetPoint(KeyPressedEvent->x, + grXtransY(mw, KeyPressedEvent->y), + mw->w_wid); + TxPrintf("\n"); + TxFlushOut(); + Tcl_NotifyChannel(Tcl_GetStdChannel(TCL_STDIN), + TCL_READABLE); + } + else + { + *(TxBuffer + tl) = *(inChar + idx); + *(TxBuffer + tl + 1) = '\0'; + TxPrintf("%c", *(inChar + idx)); + TxFlushOut(); + } + } + else + { + bool iMacro; + char *macroDef; + + macroDef = MacroRetrieve(mw->w_client, keywstate, &iMacro); + + /* Special handling: An imacro beginning with ':' */ + /* sets the prompt to ':' and moves to the next char. */ + + if (macroDef != NULL && *macroDef == ':' && iMacro) + { + if (TxTkConsole) + TxSetPrompt(':'); + else + { + TxPrintf("\b\b: "); + TxFlushOut(); + } + memmove(macroDef, macroDef + 1, strlen(macroDef + 1) + 1); + } + + macroDef = MacroSubstitute(macroDef, "%W", Tk_PathName(tkwind)); + + if (macroDef == NULL) + { + if (keysym != XK_Return) + { + char *vis = MacroName(keywstate); + TxError("Unknown macro or short command: '%s'\n", vis); + + freeMagic(vis); + } + /* Print Carriage Return & Put back Tcl/Tk prompt */ + TxParseString("", NULL, NULL); + } + else + { + int sl = strlen(macroDef); + + if (iMacro) + { + /* Echo macro to interpreter, then redirect keys */ + + if (TxTkConsole) + { + char *outstring = Tcl_Alloc(sl + 20); + sprintf(outstring, ".text insert end \"%s\"", + macroDef); + Tcl_EvalEx(consoleinterp, outstring, -1, 0); + Tcl_Free(outstring); + } + else + { + TxBuffer = Tcl_Alloc(sl + 1); + strcpy(TxBuffer, macroDef); + TxPrintf("%s", macroDef); + TxFlushOut(); + } + TxInputRedirect = TX_INPUT_REDIRECTED; + } + else + { + /* TxParseString is defined by tcltk/tclmagic.c + * and calls Tcl_Eval() + */ + + TxSetPoint(KeyPressedEvent->x, + grXtransY(mw, KeyPressedEvent->y), + mw->w_wid); + TxParseString(macroDef, NULL, NULL); + } + freeMagic(macroDef); + } + } + } + } + break; + case ConfigureNotify: + { + XConfigureEvent *ConfigureEvent = (XConfigureEvent*) xevent; + Rect screenRect; + int width, height; + bool result, need_resize; + + width = ConfigureEvent->width; + height = ConfigureEvent->height; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + screenRect.r_xbot = ConfigureEvent->x; + screenRect.r_xtop = ConfigureEvent->x + width; + screenRect.r_ytop = grTransYs(ConfigureEvent->y); + screenRect.r_ybot = grTransYs(ConfigureEvent->y + height); + + need_resize = (screenRect.r_xbot != mw->w_screenArea.r_xbot || + screenRect.r_xtop != mw->w_screenArea.r_xtop || + screenRect.r_ybot != mw->w_screenArea.r_ybot || + screenRect.r_ytop != mw->w_screenArea.r_ytop); + + /* Redraw the window */ + + WindReframe(mw, &screenRect, FALSE, FALSE); + WindRedisplay(mw); + if (need_resize) (*GrCreateBackingStorePtr)(mw); + } + break; + case VisibilityNotify: + { + XVisibilityEvent *VisEvent = (XVisibilityEvent*) xevent; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + switch (VisEvent->state) + { + case VisibilityUnobscured: + mw->w_flags &= ~WIND_OBSCURED; + if (mw->w_backingStore == (ClientData)NULL) + { + (*GrCreateBackingStorePtr)(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: + { + XExposeEvent *ExposeEvent = (XExposeEvent*) xevent; + Rect screenRect; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + 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; + (*GrGetBackingStorePtr)(mw, &screenRect); + WindScreenToSurface(mw, &screenRect, &surface); + DBWHLRedrawPrepWindow(mw, &surface); + WindDrawBorder(mw, &screenRect); + } + else + WindAreaChanged(mw, &screenRect); + WindUpdate(); + } + break; + + case MapNotify: + case UnmapNotify: + case DestroyNotify: /* Do nothing */ + break; + + default: + TxError("Tk Event: Unknown (%d)\n", xevent->type); + TxFlush(); + break; + } +} + + + +/*--------------------------------------------------------- + * cairoSetDisplay: + * This routine sets the appropriate parameters so that + * Magic will work with the X display. + * + * Under Xlib, all input events (mouse and keyboard) are + * sent to one queue which has to be polled to discover + * whether there is any input or not. To fit the Magic + * interrupt-driven input model, a helper process is + * spawned which reads and blocks on the event queue, + * sending SIGIO's to Magic when it detects input. The + * input read in the helper process is then sent to Magic + * via a communication pipe. + * + * Results: success / fail + * + * Side Effects: Sets up the pipe. + *--------------------------------------------------------- + */ + +bool +cairoSetDisplay (dispType, outFileName, mouseFileName) +char *dispType; +char *outFileName; +char *mouseFileName; +{ + char *planecount; + char *fullname; + FILE* f; + bool execFailed = FALSE; + int x, y, width, height; + + WindPackageType = WIND_X_WINDOWS; /* to be changed? */ + TxInputRedirect = TX_INPUT_NORMAL; + + grCursorType = "color"; + WindScrollBarWidth = 14; + + /* Set up the procedure values in the indirection table. */ + + GrPixelCorrect = 0; + + GrLockPtr = GrTCairoLock; + GrUnlockPtr = GrTCairoUnlock; + GrInitPtr = GrTCairoInit; + GrClosePtr = GrTCairoClose; + GrSetCMapPtr = GrTCairoSetCMap; + + GrEnableTabletPtr = GrTCairoEnableTablet; + GrDisableTabletPtr = GrTCairoDisableTablet; + GrSetCursorPtr = GrTCairoSetCursor; + GrTextSizePtr = GrTCairoTextSize; + GrDrawGlyphPtr = GrTCairoDrawGlyph; + GrReadPixelPtr = GrTCairoReadPixel; + GrFlushPtr = GrTCairoFlush; + + GrCreateWindowPtr = GrTCairoCreate; + GrDeleteWindowPtr = GrTCairoDelete; + GrConfigureWindowPtr = GrTCairoConfigure; + GrOverWindowPtr = GrTCairoRaise; + GrUnderWindowPtr = GrTCairoLower; + GrUpdateIconPtr = GrTCairoIconUpdate; + GrEventPendingPtr = GrTCairoEventPending; + GrWindowIdPtr = GrTCairoWindowId; + GrWindowNamePtr = GrTkWindowName; /* from grTkCommon.c */ + GrGetCursorPosPtr = grtcairoGetCursorPos; + GrGetCursorRootPosPtr = grtcairoGetCursorRootPos; + + /* local indirections */ + grSetSPatternPtr = grtcairoSetSPattern; + grPutTextPtr = grtcairoPutText; +#ifdef VECTOR_FONTS + grFontTextPtr = grtcairoFontText; +#endif + grDefineCursorPtr = grTkDefineCursor; + grFreeCursorPtr = grTkFreeCursors; + GrBitBltPtr = GrTCairoBitBlt; + grDrawGridPtr = grtcairoDrawGrid; + grDrawLinePtr = grtcairoDrawLine; + grSetWMandCPtr = grtcairoSetWMandC; + grFillRectPtr = grtcairoFillRect; + grSetStipplePtr = grtcairoSetStipple; + grSetLineStylePtr = grtcairoSetLineStyle; + grSetCharSizePtr = grtcairoSetCharSize; + grFillPolygonPtr = grtcairoFillPolygon; + GrFreeBackingStorePtr = grtcairoFreeBackingStore; + GrCreateBackingStorePtr = grtcairoCreateBackingStore; + GrGetBackingStorePtr = grtcairoGetBackingStore; + GrPutBackingStorePtr = grtcairoPutBackingStore; + GrScrollBackingStorePtr = grtcairoScrollBackingStore; + + if (execFailed) { + TxError("Execution failed!\n"); + return FALSE; + } + + if (!GrTCairoInit()) { + return FALSE; + }; + + Tk_GetVRootGeometry(Tk_MainWindow(magicinterp), &x, &y, &width, &height); + GrScreenRect.r_xbot = x; + GrScreenRect.r_ybot = y; + GrScreenRect.r_xtop = width + x; + GrScreenRect.r_ytop = height + y; + + return Tk_MainWindow(magicinterp) ? TRUE : FALSE; +} + +extern void MakeWindowCommand(); + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoCreate -- + * Create a new window under the X window system. + * Bind X window to Magic Window w. + * + * Results: + * Success/Fail + * + * Side Effects: + * Window created, window ID send to Xhelper. + * + * ---------------------------------------------------------------------------- + */ + +bool +GrTCairoCreate(w, name) +MagWindow *w; +char *name; +{ + Tk_Window tkwind, tktop; + Window wind; + static int WindowNumber = 0; + HashEntry *entry; + char *windowplace; + char windowname[10]; + int x = w->w_frameArea.r_xbot; + int y = grTransYs(w->w_frameArea.r_ytop); + int width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot; + int height = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot; + unsigned long attribmask = CWBackPixel | CWBorderPixel | CWColormap; + XSetWindowAttributes grAttributes; + + WindSeparateRedisplay(w); + + sprintf(windowname, ".magic%d", WindowNumber + 1); + if (windowplace = XGetDefault(grXdpy, "magic", windowname)) + { + XParseGeometry(windowplace, &x, &y, + (unsigned int *)&width, (unsigned int *)&height); + w->w_frameArea.r_xbot = x; + w->w_frameArea.r_xtop = x + width; + w->w_frameArea.r_ytop = grTransYs(y); + w->w_frameArea.r_ybot = grTransYs(y + height); + WindReframe(w, &(w->w_frameArea), FALSE, FALSE); + } + + grAttributes.colormap = XCreateColormap(grXdpy, RootWindow(grXdpy, grXscrn), + grVisualInfo->visual, AllocNone); + grAttributes.background_pixel = WhitePixel(grXdpy, grXscrn); + grAttributes.border_pixel = BlackPixel(grXdpy, grXscrn); + + if (tktop = Tk_MainWindow(magicinterp)) + { + if (!WindowNumber) + { + /* To do: deal with grVisualInfo---destroy and recreate top */ + /* frame if necessary */ + + if (Tk_WindowId(tktop) == 0) + { + Tk_SetWindowVisual(tktop, grVisualInfo->visual, + tcairoCurrent.depth, grAttributes.colormap); + } + else + { + /* The Top-level window has already been mapped. We can't mess */ + /* with it's visual. If the title is "wish", we'll assume that */ + /* nobody else is claiming it, and unmap it. */ + + if (!strcmp(Tk_Name(tktop), "wish")) Tk_UnmapWindow(tktop); + } + } + } + else + return 0; /* failure */ + + /* Last parameter "" indicates a top-level window in the space of */ + /* the parent. */ + + if (name == NULL) + tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, windowname, ""); + else + tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, name, NULL); + + /* TxError("Creating window named \"%s\", tkwind = 0x%x\n", + windowname, tkwind); TxFlush(); */ + + if (tkwind != 0) + { + bool result; + TCairoData *tcairodata; + + GrTCairoFlush(); + + tcairoCurrent.window = tkwind; + tcairoCurrent.mw = w; + + tcairodata = (TCairoData *)mallocMagic(sizeof(TCairoData)); + tcairodata->backing_context = NULL; + tcairodata->backing_surface = NULL; + + w->w_grdata = (ClientData) tkwind; + w->w_grdata2 = (ClientData) tcairodata; + + entry = HashFind(&grTCairoWindowTable, (char *)tkwind); + HashSetValue(entry, w); + + /* ensure that the visual is what we wanted, if possible to change */ + + Tk_SetWindowVisual(tkwind, grVisualInfo->visual, tcairoCurrent.depth, + grAttributes.colormap); + + /* map the window, if necessary */ + + Tk_MapWindow(tkwind); + + /* use x, y, width, height to size and position the window */ + + Tk_GeometryRequest(tkwind, width, height); + /* Tk_MoveResizeWindow(tkwind, x, y, width, height); */ + + wind = Tk_WindowId(tkwind); + tcairoCurrent.windowid = wind; + tcairodata->surface = cairo_xlib_surface_create(grXdpy, + tcairoCurrent.windowid, grVisualInfo->visual, + Tk_Width(tcairoCurrent.window), + Tk_Height(tcairoCurrent.window)); + tcairodata->context = cairo_create(tcairodata->surface); + + cairo_set_line_width(tcairodata->context, 1.0); + cairo_set_source_rgb(tcairodata->context, 0, 0, 0); + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); + + Tk_DefineCursor(tkwind, tcairoCurrent.cursor); + GrTCairoIconUpdate(w, w->w_caption); + + WindowNumber++; + + /* execute all Tk events up to current */ + + while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0); + + /* set up Tk event handler to start processing */ + + Tk_CreateEventHandler(tkwind, ExposureMask | StructureNotifyMask + | ButtonPressMask | KeyPressMask | VisibilityChangeMask, + (Tk_EventProc *)TCairoEventProc, (ClientData) tkwind); + + /* set up commands to be passed expressly to this window */ + + MakeWindowCommand((name == NULL) ? windowname : name, w); + + return (WindowNumber == 1) ? grtcairoLoadFont() : 1; + } + else + { + TxError("Could not open new Tk window\n"); + } + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoDelete -- + * Destroy a Tk/Cairo window. + * + * Results: + * None. + * + * Side Effects: + * Window destroyed. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoDelete(w) +MagWindow *w; +{ + Tk_Window xw; + HashEntry *entry; + + xw = (Tk_Window) w->w_grdata; + entry = HashLookOnly(&grTCairoWindowTable, (char *)xw); + HashSetValue(entry, NULL); + + Tcl_DeleteCommand(magicinterp, Tk_PathName(xw)); + Tk_DestroyWindow(xw); +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoConfigure -- + * Resize/ Move an existing X window. + * + * Results: + * None. + * + * Side Effects: + * Window reconfigured to w->w_frameArea. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoConfigure(w) +MagWindow *w; +{ + TCairoData *tcairodata; + int width, height; + + if (w->w_flags & WIND_OFFSCREEN) return; + + width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot; + height = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot; + Tk_MoveResizeWindow((Tk_Window)w->w_grdata, + w->w_frameArea.r_xbot, grTransYs(w->w_frameArea.r_ytop), + width, height); + tcairodata = (TCairoData *)w->w_grdata2; + cairo_xlib_surface_set_size(tcairodata->surface, width, height); +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoRaise -- + * Raise a window to the top of the screen such that nothing + * obscures it. + * + * Results: + * None. + * + * Side Effects: + * Window raised. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoRaise(w) +MagWindow *w; +{ + Tk_Window tkwind; + + if (w->w_flags & WIND_OFFSCREEN) return; + + tkwind = (Tk_Window)w->w_grdata; + Tk_RestackWindow(tkwind, Above, NULL); +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoLower -- + * Lower a window below all other Tk windows. + * obscures it. + * + * Results: + * None. + * + * Side Effects: + * Window lowered. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoLower(w) +MagWindow *w; +{ + Tk_Window tkwind; + + if (w->w_flags & WIND_OFFSCREEN) return; + + tkwind = (Tk_Window)w->w_grdata; + Tk_RestackWindow(tkwind, Below, NULL); +} + + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoLock -- + * Lock a window and set global variables "tcairoCurrent.window" + * and "tcairoCurrent.mw" to reference the locked window. + * + * Results: + * None. + * + * Side Effects: + * Window locked. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoLock(w, flag) +MagWindow *w; +bool flag; +{ + Window wind; + + grSimpleLock(w, flag); + if ( w != GR_LOCK_SCREEN ) + { + tcairoCurrent.mw = w; + + if (w->w_flags & WIND_OFFSCREEN) + { + tcairoCurrent.window = (Tk_Window) NULL; + tcairoCurrent.windowid = (Pixmap) w->w_grdata; + } + else + { + tcairoCurrent.window = (Tk_Window) w->w_grdata; + tcairoCurrent.windowid = Tk_WindowId(tcairoCurrent.window); + } + + tcairoSetProjection(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); + } +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoUnlock -- + * Unlock a window, flushing stuff out to the display. + * + * Results: + * None. + * + * Side Effects: + * Window unlocked. + * Display update. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoUnlock(w) +MagWindow *w; +{ + GrTCairoFlush(); + grSimpleUnlock(w); +} + + +/* + *------------------------------------------------------------------------- + * GrTCairoEventPending -- + * check for pending graphics events. + * Here we use the X11 check for window events, because Tcl/Tk doesn't + * allows peeking into its event queue without executing whatever is + * in the queue. + * + * Results: + * TRUE if an event is waiting in the event queue. + * + * Side effects: + * None, hopefully (put back the event!) + * + *------------------------------------------------------------------------- + */ + +bool +GrTCairoEventPending() +{ + Window wind = tcairoCurrent.windowid; + XEvent genEvent; + bool retval; + + XSync(grXdpy, FALSE); /* Necessary, or it won't catch mouse/key events */ + retval = XCheckWindowEvent(grXdpy, wind, ExposureMask + | StructureNotifyMask | ButtonPressMask + | KeyPressMask, &genEvent); + if (retval) XPutBackEvent(grXdpy, &genEvent); + return retval; +} + +/* + *------------------------------------------------------------------------- + * + * GrTCairoIconUpdate -- updates the icon text with the window script + * + * Results: none + * + * Side Effects: changes the icon text + * + *------------------------------------------------------------------------- + */ + +void +GrTCairoIconUpdate(w, text) /* See Blt code */ +MagWindow *w; +char *text; +{ + Tk_Window tkwind; + Window wind; + XClassHint class; + char *brack; + + if (w->w_flags & WIND_OFFSCREEN) return; + + tkwind = (Tk_Window)(w->w_grdata); + if (tkwind == NULL) { + tkwind = Tk_MainWindow(magicinterp); + if (tkwind == NULL) return; + } + wind = Tk_WindowId(tkwind); + if (wind == 0) return; + + class.res_name = "magic"; + class.res_class = "magic"; + + XSetClassHint( grXdpy, wind, &class); + if (text) + { + 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); + } +} + +/* + *------------------------------------------------------------------------- + * GrTCairoWindowId -- + * Get magic's ID number from the indicated MagWindow structure + * + * Results: + * The window ID number. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +int +GrTCairoWindowId(tkname) +char *tkname; +{ + Tk_Window tkwind; + MagWindow *mw; + HashEntry *entry; + int id = 0; + + tkwind = Tk_NameToWindow(magicinterp, tkname, Tk_MainWindow(magicinterp)); + if (tkwind != NULL) + { + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + if (mw) { + id = mw->w_wid; + } + } + return id; +} diff --git a/graphics/cairo_new/grTCairo2.c b/graphics/cairo_new/grTCairo2.c new file mode 100644 index 00000000..11b98974 --- /dev/null +++ b/graphics/cairo_new/grTCairo2.c @@ -0,0 +1,214 @@ +/* grTCairo2.c - + * + * Copyright 2017 Open Circuit Design + * + * This file contains additional functions to manipulate an X + * color display. Included here are rectangle drawing and color map + * loading. + * + * Written by Chuan Chen + */ + +#include +char *getenv(); + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "graphics/glyphs.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "grTCairoInt.h" + +#include "textio/txcommands.h" + +extern char *DBWStyleType; +extern Display *grXdpy; + +extern cairo_pattern_t *currentStipple; + +/*--------------------------------------------------------- + * GrTCairoSetCMap -- + * + * Cairo uses RGB values as read from the colormap file, + * directly, so there is no need to install colors into a + * colormap. Therefore, this is a null routine. + * + * Results: None. + * + * Side Effects: None. + * + *--------------------------------------------------------- + */ + +void +GrTCairoSetCMap () +{ +} + +Rect grtcairoLines[TCAIRO_BATCH_SIZE]; +int grtcairoNbLines = 0; +TCairoRect grtcairoRects[TCAIRO_BATCH_SIZE]; +int grtcairoNbRects = 0; +Rect grtcairoDiagonal[TCAIRO_BATCH_SIZE]; +int grtcairoNbDiagonal = 0; + +/*--------------------------------------------------------- + * grtcairoDrawLines: + * This routine draws a batch of lines. + * + * Results: None. + * + * Side Effects: + * Draw a bunch of lines. + *--------------------------------------------------------- + */ + +void +grtcairoDrawLines(lines, nb) +Rect lines[]; +int nb; +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + int i; + for (i = 0; i < nb; i++) + { + cairo_move_to(tcairodata->context, lines[i].r_ll.p_x, lines[i].r_ll.p_y); + cairo_line_to(tcairodata->context, lines[i].r_ur.p_x, lines[i].r_ur.p_y); + } + // cairo_set_source_rgba(tcairodata->context, r, g, b, a); + // cairo_set_line_width(tcairodata->context, width); + cairo_stroke(tcairodata->context); +} + +/*--------------------------------------------------------- + * grtcairoDrawLine: + * This routine draws a line. + * + * Results: None. + * + * Side Effects: + * Draw a line for (x1, y1) to (x2, y2) inclusive. + *--------------------------------------------------------- + */ + +void +grtcairoDrawLine (x1, y1, x2, y2) +int x1, y1; /* Screen coordinates of first point. */ +int x2, y2; /* Screen coordinates of second point. */ +{ + /* Treat straight and diagonal lines separately. */ + /* (Done for OpenGL; possibly not necessary for Cairo) */ + + if ((x1 == x2) || (y1 == y2)) + { + if (grtcairoNbLines == TCAIRO_BATCH_SIZE) GR_TCAIRO_FLUSH_LINES(); + grtcairoLines[grtcairoNbLines].r_ll.p_x = x1; + grtcairoLines[grtcairoNbLines].r_ll.p_y = y1; + grtcairoLines[grtcairoNbLines].r_ur.p_x = x2; + grtcairoLines[grtcairoNbLines].r_ur.p_y = y2; + grtcairoNbLines++; + } + else + { + if (grtcairoNbDiagonal == TCAIRO_BATCH_SIZE) GR_TCAIRO_FLUSH_DIAGONAL(); + grtcairoDiagonal[grtcairoNbDiagonal].r_ll.p_x = x1; + grtcairoDiagonal[grtcairoNbDiagonal].r_ll.p_y = y1; + grtcairoDiagonal[grtcairoNbDiagonal].r_ur.p_x = x2; + grtcairoDiagonal[grtcairoNbDiagonal].r_ur.p_y = y2; + grtcairoNbDiagonal++; + } +} + +/*--------------------------------------------------------- + * grtcairoFillRects: + * This routine draws a bunch of solid rectangles. + * + * Results: None. + * + * Side Effects: + * Drawing. + *--------------------------------------------------------- + */ + +void +grtcairoFillRects(rects, nb) +TCairoRect rects[]; +int nb; +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + int i; + + for (i = 0; i < nb; i++) + { + cairo_rectangle(tcairodata->context, + rects[i].r_ll.p_x, rects[i].r_ll.p_y, + rects[i].r_ur.p_x-rects[i].r_ll.p_x, rects[i].r_ur.p_y-rects[i].r_ll.p_y); + // TxPrintf("%d %d %d %d \n", rects[i].r_ll.p_x, rects[i].r_ll.p_y, rects[i].r_ur.p_x-rects[i].r_ll.p_x, rects[i].r_ur.p_y-rects[i].r_ll.p_y); + } + cairo_clip(tcairodata->context); + cairo_mask(tcairodata->context, currentStipple); +} + +/*--------------------------------------------------------- + * grtcairoFillRect: + * This routine draws a solid rectangle. + * + * Results: None. + * + * Side Effects: + * Drawing. + *--------------------------------------------------------- + */ + +void +grtcairoFillRect(r) +Rect *r; /* Address of a rectangle in screen + * coordinates. + */ +{ + if (grtcairoNbRects == TCAIRO_BATCH_SIZE) GR_TCAIRO_FLUSH_RECTS(); + grtcairoRects[grtcairoNbRects].r_ll.p_x = r->r_ll.p_x; + grtcairoRects[grtcairoNbRects].r_ll.p_y = r->r_ll.p_y; + + grtcairoRects[grtcairoNbRects].r_ur.p_x = r->r_ur.p_x; + grtcairoRects[grtcairoNbRects].r_ur.p_y = r->r_ur.p_y; + + grtcairoRects[grtcairoNbRects].r_ul.p_x = r->r_ll.p_x; + grtcairoRects[grtcairoNbRects].r_ul.p_y = r->r_ur.p_y; + + grtcairoRects[grtcairoNbRects].r_lr.p_x = r->r_ur.p_x; + grtcairoRects[grtcairoNbRects].r_lr.p_y = r->r_ll.p_y; + + grtcairoNbRects++; +} + +/*--------------------------------------------------------- + * grtcairoFillPolygon: + * This routine draws a solid (convex) polygon + * + * Results: None. + * + * Side Effects: + * Drawing. + *--------------------------------------------------------- + */ + +void +grtcairoFillPolygon(tp, np) +Point *tp; +int np; +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + int i; + cairo_move_to(tcairodata->context, tp[0].p_x, tp[0].p_y); + for (i = 1; i < np; i++) + cairo_line_to(tcairodata->context, tp[i].p_x, tp[i].p_y); + cairo_close_path(tcairodata->context); + cairo_fill(tcairodata->context); +} + diff --git a/graphics/cairo_new/grTCairo3.c b/graphics/cairo_new/grTCairo3.c new file mode 100644 index 00000000..f9f5d33c --- /dev/null +++ b/graphics/cairo_new/grTCairo3.c @@ -0,0 +1,648 @@ +/* grTCairo3.c - + * + * Copyright 2017 Open Circuit Design + * + * This file contains additional functions to manipulate an X window system + * color display. Included here are device-dependent routines to draw and + * erase text and draw a grid. + * + * Written by Chuan Chen + */ + +#include +#include + +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "utils/geometry.h" +#include "utils/malloc.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "dbwind/dbwind.h" +#include "textio/textio.h" +#include "utils/signals.h" +#include "utils/utils.h" +#include "utils/hash.h" +#include "graphics/grTCairoInt.h" +#include "graphics/grTkCommon.h" +#include "database/fonts.h" + +extern Display *grXdpy; + +static GC grXcopyGC = (GC)NULL; + +/* locals */ + + +/*--------------------------------------------------------- + * grtcairoDrawGrid: + * grxDrawGrid adds a grid to the grid layer, using the current + * write mask and color. + * + * Results: + * TRUE is returned normally. However, if the grid gets too small + * to be useful, then nothing is drawn and FALSE is returned. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +bool +grtcairoDrawGrid (prect, outline, clip) +Rect *prect; /* A rectangle that forms the template + * for the grid. Note: in order to maintain + * precision for the grid, the rectangle + * coordinates are specified in units of + * screen coordinates multiplied by SUBPIXEL. + */ +int outline; /* the outline style */ +Rect *clip; /* a clipping rectangle */ +{ + int xsize, ysize; + int x, y; + int xstart, ystart; + int snum, low, hi, shifted; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + xsize = prect->r_xtop - prect->r_xbot; + ysize = prect->r_ytop - prect->r_ybot; + if (!xsize || !ysize || GRID_TOO_SMALL(xsize, ysize)) + return FALSE; + + xstart = prect->r_xbot % xsize; + while (xstart < clip->r_xbot << SUBPIXELBITS) xstart += xsize; + ystart = prect->r_ybot % ysize; + while (ystart < clip->r_ybot << SUBPIXELBITS) ystart += ysize; + + snum = 0; + low = clip->r_ybot; + hi = clip->r_ytop; + for (x = xstart; x < (clip->r_xtop + 1) << SUBPIXELBITS; x += xsize) + { + shifted = x >> SUBPIXELBITS; + cairo_move_to(tcairodata->context, shifted, low); + cairo_line_to(tcairodata->context, shifted, hi); + snum++; + } + + snum = 0; + low = clip->r_xbot; + hi = clip->r_xtop; + for (y = ystart; y < (clip->r_ytop + 1) << SUBPIXELBITS; y += ysize) + { + shifted = y >> SUBPIXELBITS; + cairo_move_to(tcairodata->context, low, shifted); + cairo_line_to(tcairodata->context, hi, shifted); + snum++; + } + cairo_stroke(tcairodata->context); + return TRUE; +} + + +/*--------------------------------------------------------- + * grtcairoLoadFont + * This local routine loads the default ("toy API") + * font for Cairo. + * + * Results: Success/Failure + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +bool +grtcairoLoadFont() +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + cairo_select_font_face(tcairodata->context, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + return TRUE; +} + + +/*--------------------------------------------------------- + * grtcairoSetCharSize: + * This local routine sets the character size in the display, + * if necessary. + * + * Results: None. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +void +grtcairoSetCharSize (size) +int size; /* Width of characters, in pixels (6 or 8). */ +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + tcairoCurrent.fontSize = size; + cairo_set_font_size(tcairodata->context, size * 4 + 10); + switch (size) + { + case GR_TEXT_DEFAULT: + case GR_TEXT_SMALL: + tcairoCurrent.font = grSmallFont; + break; + case GR_TEXT_MEDIUM: + tcairoCurrent.font = grMediumFont; + break; + case GR_TEXT_LARGE: + tcairoCurrent.font = grLargeFont; + break; + case GR_TEXT_XLARGE: + tcairoCurrent.font = grXLargeFont; + break; + default: + TxError("%s%d\n", "grtcairoSetCharSize: Unknown character size ", + size ); + break; + } +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoTextSize -- + * + * Determine the size of a text string. + * + * Results: + * None. + * + * Side effects: + * A rectangle is filled in that is the size of the text in pixels. + * The origin (0, 0) of this rectangle is located on the baseline + * at the far left side of the string. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoTextSize(text, size, r) +char *text; +int size; +Rect *r; +{ + Tk_FontMetrics overall; + Tk_Font font; + int width; + + switch (size) { + case GR_TEXT_DEFAULT: + case GR_TEXT_SMALL: + font = grSmallFont; + break; + case GR_TEXT_MEDIUM: + font = grMediumFont; + break; + case GR_TEXT_LARGE: + font = grLargeFont; + break; + case GR_TEXT_XLARGE: + font = grXLargeFont; + break; + default: + TxError("%s%d\n", "GrTCairoTextSize: Unknown character size ", + size ); + break; + } + if (font == NULL) return; + Tk_GetFontMetrics(font, &overall); + width = Tk_TextWidth(font, text, strlen(text)); + /* Hack alert! Tk_TextWidth returns values too small! */ + width = width + (width >> 4); + r->r_ytop = overall.ascent; + r->r_ybot = -overall.descent; + r->r_xtop = width; + r->r_xbot = 0; +} + +/* Cairo backing store functions (now removed from the X11-based ones) */ + +void +grtcairoFreeBackingStore(MagWindow *window) +{ + TCairoData *tcairodata; + Pixmap pmap = (Pixmap)window->w_backingStore; + if (pmap == (Pixmap)NULL) return; + XFreePixmap(grXdpy, pmap); + window->w_backingStore = (ClientData)NULL; + + tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + /* To do: destroy cairo surface and context */ + tcairodata->backing_surface = NULL; + tcairodata->backing_context = NULL; +} + +void +grtcairoCreateBackingStore(MagWindow *w) +{ + Pixmap pmap; + TCairoData *tcairodata; + Tk_Window tkwind = (Tk_Window)w->w_grdata; + Window wind; + unsigned int width, height; + GC gc; + XGCValues gcValues; + int grDepth; + + /* Deferred */ + if (tkwind == NULL) return; + + wind = (Window)Tk_WindowId(tkwind); + + /* ignore all windows other than layout */ + if (w->w_client != DBWclientID) return; + + /* deferred */ + if (wind == (Window)NULL) return; + + width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; + height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; + + if (w->w_backingStore != (ClientData)NULL) grtcairoFreeBackingStore(w); + + if (grXcopyGC == (GC)NULL) + { + gcValues.graphics_exposures = FALSE; + grXcopyGC = XCreateGC(grXdpy, wind, GCGraphicsExposures, &gcValues); + } + + grDepth = Tk_Depth((Tk_Window)w->w_grdata); + + pmap = XCreatePixmap(grXdpy, wind, width, height, grDepth); + w->w_backingStore = (ClientData)pmap; + + tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + tcairodata->backing_surface = cairo_xlib_surface_create(grXdpy, pmap, + DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width, height); + tcairodata->backing_context = cairo_create(tcairodata->backing_surface); +} + +bool +grtcairoGetBackingStore(MagWindow *w, Rect *area) +{ + unsigned int width, height; + int xbot, ybot; + Rect r; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + if (w->w_backingStore == (ClientData)0) return FALSE; + + GEO_EXPAND(area, 1, &r); + GeoClip(&r, &(w->w_screenArea)); + + width = r.r_xtop - r.r_xbot; + height = r.r_ytop - r.r_ybot; + + xbot = r.r_xbot; + ybot = r.r_ybot; + + Window root_return; + int x_return, y_return; + unsigned int width_return, height_return; + unsigned int border_width_return; + unsigned int depth_return; + + Pixmap pmap; + pmap = (Pixmap)w->w_backingStore; + if (pmap == (Pixmap)NULL) + return FALSE; + + cairo_set_source_surface(tcairodata->context, tcairodata->backing_surface, 0, 0); + cairo_rectangle(tcairodata->context, xbot, ybot, width, height); + cairo_set_operator(tcairodata->context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->context); + + return TRUE; +} + + +bool +grtcairoScrollBackingStore(MagWindow *w, Point *shift) +{ + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + Pixmap pmap; + unsigned int width, height; + int xorigin, yorigin, xshift, yshift; + + pmap = (Pixmap)w->w_backingStore; + if (pmap == (Pixmap)NULL) + { + TxPrintf("grx11ScrollBackingStore %d %d failure\n", + shift->p_x, shift->p_y); + return FALSE; + } + + width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; + height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; + xorigin = 0; + yorigin = 0; + xshift = shift->p_x; + yshift = -shift->p_y; + + if (xshift > 0) + width -= xshift; + else if (xshift < 0) + { + width += xshift; + xorigin = -xshift; + xshift = 0; + } + if (yshift > 0) + height -= yshift; + else if (yshift < 0) + { + height += yshift; + yorigin = -yshift; + yshift = 0; + } + + /* TxPrintf("grx11ScrollBackingStore %d %d\n", shift->p_x, shift->p_y); */ + + cairo_set_source_surface(tcairodata->context, tcairodata->backing_surface, + xshift, yshift); + cairo_rectangle(tcairodata->context, xshift, yshift, width, height); + cairo_set_operator(tcairodata->context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->context); + + return TRUE; +} + +void +grtcairoPutBackingStore(MagWindow *w, Rect *area) +{ + unsigned int width, height; + int ybot, xbot; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + if (w->w_backingStore == (ClientData)0) return; + + width = area->r_xtop - area->r_xbot; + height = area->r_ytop - area->r_ybot; + + ybot = area->r_ybot; + xbot = area->r_xbot; + + if (xbot < 0) { + width -= xbot; + xbot = 0; + } + + if (ybot < 0) { + height -= ybot; + ybot = 0; + } + + cairo_set_source_surface(tcairodata->backing_context, tcairodata->surface, + 0.0, 0.0); + cairo_rectangle(tcairodata->backing_context, xbot, ybot, width, height); + cairo_set_operator(tcairodata->backing_context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->backing_context); + + // cairo_surface_flush(tcairodata->backing_surface); + // w->w_backingStore = (ClientData) cairo_image_surface_get_data(tcairodata->backing_surface); + // cairo_surface_mark_dirty(tcairodata->backing_surface); +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoReadPixel -- + * + * Read one pixel from the screen. + * + * Results: + * An integer containing the pixel's color. + * + * Side effects: + * none. + * + * ---------------------------------------------------------------------------- + */ + +int +GrTCairoReadPixel (w, x, y) +MagWindow *w; +int x, y; /* the location of a pixel in screen coords */ +{ + return 0; /* (unimplemented) */ +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoBitBlt -- + * + * Copy information in bit block transfers. + * + * Results: + * None. + * + * Side effects: + * changes the screen. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoBitBlt(r, p) +Rect *r; +Point *p; +{ + // (unimplemented) +} + +#ifdef VECTOR_FONTS + +/* + *---------------------------------------------------------------------- + * Draw a text character + * This routine is similar to grtcairoFillPolygon() + *---------------------------------------------------------------------- + */ + +void +grtcairoDrawCharacter(clist, tc, pixsize) +FontChar *clist; +unsigned char tc; +int pixsize; +{ + Point *tp; + int np, nptotal; + int i, j; + static int maxnp = 0; + FontChar *ccur; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + if (pixsize < 5) return; /* Label too small to be useful */ + + //should we be using cairo_show_glyphs?? + for (ccur = clist; ccur != NULL; ccur = ccur->fc_next) { + tp = ccur->fc_points; + np = ccur->fc_numpoints; + cairo_move_to(tcairodata->context, tp[0].p_x, tp[0].p_y); + for (i = 1; i < np; i++, j += 3) { + cairo_line_to(tcairodata->context, tp[0].p_x, tp[0].p_y); + } + } + cairo_fill(tcairodata->context); +} + +/*--------------------------------------------------------- + * grtcairoFontText: + * + * This routine draws text from font vectors using the + * font vector routines in DBlabel.c. Text is clipped + * to the clipping rectangle. + * + * For speed, should we be transferring the font + * vectors into cairo glyphs? + * + *--------------------------------------------------------- + */ + +void +grtcairoFontText(text, font, size, rotate, pos, clip, obscure) +char *text; /* The text to be drawn */ +int font; /* Font to use from fontList */ +int size; /* Pixel size of the font */ +int rotate; /* Text rotation */ +Point *pos; /* Text base position */ +Rect *clip; /* Clipping area */ +LinkedRect *obscure; /* List of obscuring areas */ +{ + char *tptr; + Point *coffset; /* vector to next character */ + Rect *cbbox; + float fsize; + FontChar *clist; + int cheight, baseline; + float tmp; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + cairo_save(tcairodata->context); + cairo_translate(tcairodata->context, pos->p_x, pos->p_y); + cairo_rotate(tcairodata->context, ((double)rotate) / 360 * 2 * M_PI); + + /* Get label size */ + cbbox = &DBFontList[font]->mf_extents; + + fsize = (uint8_t)size / (uint8_t)cbbox->r_ytop; + cairo_scale(tcairodata->context, fsize, fsize); + + /* Adjust to baseline */ + baseline = 0; + for (tptr = text; *tptr != '\0'; tptr++) + { + DBFontChar(font, *tptr, NULL, NULL, &cbbox); + if (cbbox->r_ybot < baseline) + baseline = cbbox->r_ybot; + } + cairo_translate(tcairodata->context, 0, -baseline); + + for (tptr = text; *tptr != '\0'; tptr++) + { + DBFontChar(font, *tptr, &clist, &coffset, NULL); + grtcairoDrawCharacter(clist, *tptr, size); + cairo_translate(tcairodata->context, coffset->p_x, coffset->p_y); + } + cairo_restore(tcairodata->context); +} + +#endif /* VECTOR_FONTS */ + +/*--------------------------------------------------------- + * grtcairoPutText: + * (modified on SunPutText) + * + * This routine puts a chunk of text on the screen in the current + * color, size, etc. The caller must ensure that it fits on + * the screen -- no clipping is done except to the obscuring rectangle + * list and the clip rectangle. + * + * Results: + * none. + * + * Side Effects: + * The text is drawn on the screen. + * + *--------------------------------------------------------- + */ + +void +grtcairoPutText (text, pos, clip, obscure) +char *text; /* The text to be drawn. */ +Point *pos; /* A point located at the leftmost point of + * the baseline for this string. + */ +Rect *clip; /* A rectangle to clip against */ +LinkedRect *obscure; /* A list of obscuring rectangles */ + +{ + Rect location; + Rect overlap; + Rect textrect; + LinkedRect *ob; + void grTCairoGeoSub(); + int i; + float tscale; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + GrTCairoTextSize(text, tcairoCurrent.fontSize, &textrect); + + location.r_xbot = pos->p_x + textrect.r_xbot; + location.r_xtop = pos->p_x + textrect.r_xtop; + location.r_ybot = pos->p_y + textrect.r_ybot; + location.r_ytop = pos->p_y + textrect.r_ytop; + + /* erase parts of the bitmap that are obscured */ + for (ob = obscure; ob != NULL; ob = ob->r_next) + { + if (GEO_TOUCH(&ob->r_r, &location)) + { + overlap = location; + GeoClip(&overlap, &ob->r_r); + grTCairoGeoSub(&location, &overlap); + } + } + + overlap = location; + GeoClip(&overlap, clip); + + /* copy the text to the color screen */ + if ((overlap.r_xbot < overlap.r_xtop) && (overlap.r_ybot <= overlap.r_ytop)) + { + cairo_rectangle(tcairodata->context, overlap.r_xbot, + overlap.r_ybot, overlap.r_xtop - overlap.r_xbot, + overlap.r_ytop - overlap.r_ybot); + cairo_clip(tcairodata->context); + cairo_move_to(tcairodata->context, location.r_xbot, location.r_ybot); + cairo_show_text(tcairodata->context, text); + cairo_fill(tcairodata->context); + } +} + + +/* grTCairoGeoSub: + * return the tallest sub-rectangle of r not obscured by area + * area must be within r. + */ + +void +grTCairoGeoSub(r, area) +Rect *r; /* Rectangle to be subtracted from. */ +Rect *area; /* Area to be subtracted. */ + +{ + if (r->r_xbot == area->r_xbot) r->r_xbot = area->r_xtop; + else if (r->r_xtop == area->r_xtop) r->r_xtop = area->r_xbot; + else if (r->r_ybot <= area->r_ybot) r->r_ybot = area->r_ytop; + else if (r->r_ytop == area->r_ytop) r->r_ytop = area->r_ybot; + else + r->r_xtop = area->r_xbot; +} diff --git a/graphics/cairo_new/grTCairo4.c b/graphics/cairo_new/grTCairo4.c new file mode 100644 index 00000000..10b8eba8 --- /dev/null +++ b/graphics/cairo_new/grTCairo4.c @@ -0,0 +1,137 @@ +/* grTCairo4.c - + * + * Copyright 2017 Open Circuit Design + * + * This file contains functions to manage the graphics tablet associated + * with the X display. + * + * Written by Chuan Chen + */ + +#include +#include +#include +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "utils/magsgtty.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "graphics/grTkCommon.h" +#include "textio/txcommands.h" +#include "grTCairoInt.h" + +extern Display *grXdpy; + + +/*--------------------------------------------------------- + * GrTCairoDisableTablet: + * Turns off the cursor. + * + * Results: None. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +void +GrTCairoDisableTablet () +{ + /* (Unimplemented) */ +} + + +/*--------------------------------------------------------- + * GrTCairoEnableTablet: + * This routine enables the graphics tablet. + * + * Results: + * None. + * + * Side Effects: + * Simply turn on the crosshair. + *--------------------------------------------------------- + */ + +void +GrTCairoEnableTablet () +{ + /* (Unimplemented) */ +} + + +/* + * ---------------------------------------------------------------------------- + * grtcairoGetCursorPos: + * Read the cursor position in magic coordinates. + * + * Results: + * TRUE is returned if the coordinates were succesfully read, FALSE + * otherwise. + * + * Side effects: + * The parameter is filled in with the cursor position, in the form of + * a point in screen coordinates. + * ---------------------------------------------------------------------------- + */ + +bool +grtcairoGetCursorPos (mw, p) + MagWindow *mw; /* window for which result is given */ + Point *p; /* point to be filled in with screen coordinates */ +{ + int x, y, x1, y1; + unsigned int buttons; + Window win1, win2; + + if (mw == (MagWindow *)NULL) mw = tcairoCurrent.mw; + + XQueryPointer(grXdpy, Tk_WindowId((Tk_Window)(mw->w_grdata)), + &win1, &win2, &x1, &y1, + &x, &y, &buttons); + + p->p_x = x; + p->p_y = grXtransY(mw, y); + + return TRUE; +} + +/* + * ---------------------------------------------------------------------------- + * grtcairoGetCursorRootPos: + * Read the cursor position in sreen root coordinates. + * + * Results: + * TRUE is returned if the coordinates were succesfully read, FALSE + * otherwise. + * + * Side effects: + * The parameter is filled in with the cursor position, in the form of + * a point in screen coordinates. + * ---------------------------------------------------------------------------- + */ + +bool +grtcairoGetCursorRootPos (mw, p) + MagWindow *mw; /* window for which result is given */ + Point *p; /* point to be filled in with screen coordinates */ +{ + int x, y, x1, y1; + unsigned int buttons; + Window win1, win2; + + if (mw == (MagWindow *)NULL) mw = tcairoCurrent.mw; + + XQueryPointer(grXdpy, Tk_WindowId((Tk_Window)(mw->w_grdata)), + &win1, &win2, &x1, &y1, + &x, &y, &buttons); + + p->p_x = x1; + p->p_y = y1; + + return TRUE; +} diff --git a/graphics/cairo_new/grTCairo5.c b/graphics/cairo_new/grTCairo5.c new file mode 100644 index 00000000..464b9b72 --- /dev/null +++ b/graphics/cairo_new/grTCairo5.c @@ -0,0 +1,210 @@ +/* grTCairo5.c - + * + * Copyright 2017 Open Circuit Design + * + * Manipulate the programable cursor on the graphics display. + * + * Written by Chuan Chen + */ + +#include +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "utils/styles.h" +#include "utils/hash.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "graphics/glyphs.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "grTkCommon.h" +#include "grTCairoInt.h" + +extern Display *grXdpy; +extern int grXscrn; +extern HashTable grTCairoWindowTable; + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoDrawGlyph -- + * + * Draw one glyph on the display. + * + * Results: + * None. + * + * Side effects: + * Draws pixels. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoDrawGlyph (gl, p) +GrGlyph *gl; /* A single glyph */ +Point *p; /* screen pos of lower left corner */ +{ + Rect bBox; + bool anyObscure; + LinkedRect *ob; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + GR_CHECK_LOCK(); + + /* We're going to change the graphics state without affecting */ + /* the standard color and mask saved values, so we had better */ + /* flush all rects & lines first. */ + GR_TCAIRO_FLUSH_BATCH(); + + bBox.r_ll = *p; + bBox.r_xtop = p->p_x + gl->gr_xsize - 1; + bBox.r_ytop = p->p_y + gl->gr_ysize - 1; + + anyObscure = FALSE; + for (ob = grCurObscure; ob != NULL; ob = ob->r_next) { + if (GEO_TOUCH( &(ob->r_r), &bBox)) { + anyObscure = TRUE; + break; + } + } + if ((!anyObscure) && (GEO_SURROUND(&grCurClip, &bBox)) ) { + int *pixelp, x, y, thisp, lastp; + int color, red, green, blue, mask; + + /* no clipping, try to go quickly */ + pixelp = gl->gr_pixels; + thisp = -1; + for (y = 0; y < gl->gr_ysize; y++) { + int x1, y1; + + y1 = bBox.r_ybot + y; + for (x = 0; x < gl->gr_xsize; x++) { + lastp = thisp; + thisp = *pixelp++; + if (thisp != 0) + { + /* Note: mask has traditionally been 0-127 */ + if (thisp != lastp) { + if (lastp != -1) { + cairo_fill(tcairodata->context); + } + mask = GrStyleTable[thisp].mask << 1; + color = GrStyleTable[thisp].color; + GrGetColor(color, &red, &green, &blue); + cairo_set_source_rgba(tcairodata->context, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); + } + x1 = bBox.r_xbot + x; + cairo_rectangle(tcairodata->context, x1, y1, 1, 1); + } + } + } + if (lastp != -1) { + cairo_fill(tcairodata->context); + } + } else { + /* do pixel by pixel clipping */ + int y, yloc; + + yloc = bBox.r_ybot; + for (y = 0; y < gl->gr_ysize; y++) { + int startx, endx; + if ( (yloc <= grCurClip.r_ytop) && (yloc >= grCurClip.r_ybot) ) { + int laststartx; + laststartx = bBox.r_xbot - 1; + for (startx = bBox.r_xbot; startx <= bBox.r_xtop; + startx = endx + 1) { + int *pixelp; + + startx = MAX(startx, grCurClip.r_xbot); + endx = MIN(bBox.r_xtop, grCurClip.r_xtop); + + if (anyObscure) { + for (ob = grCurObscure; ob != NULL; ob = ob->r_next) { + if ( (ob->r_r.r_ybot <= yloc) && + (ob->r_r.r_ytop >= yloc) ) { + if (ob->r_r.r_xbot <= startx) + startx = MAX(startx, ob->r_r.r_xtop + 1); + else if (ob->r_r.r_xbot <= endx) + endx = MIN(endx, ob->r_r.r_xbot - 1); + } + } + } + + /* stop if we aren't advancing */ + if (startx == laststartx) break; + laststartx = startx; + if (startx > endx) continue; + + /* draw a section of this scan line */ + pixelp = &( gl->gr_pixels[y * gl->gr_xsize + + (startx - bBox.r_xbot)]); + for ( ; startx <= endx; startx++) { + int color, red, green, blue, mask; + if (*pixelp != 0) + { + mask = GrStyleTable[*pixelp].mask << 1; + color = GrStyleTable[*pixelp].color; + GrGetColor(color, &red, &green, &blue); + cairo_set_source_rgba(tcairodata->context, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); + + cairo_rectangle(tcairodata->context, startx, yloc, 1, 1); + cairo_fill(tcairodata->context); + } + pixelp++; + } + startx = endx + 1; + } + } + yloc++; + } + } +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoSetCursor: + * + * Make the cursor be a new pattern, as defined in the display styles file. + * + * Results: + * None. + * + * Side effects: + * When the cursor is turned back on it will take on the new pattern. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoSetCursor(cursorNum) +int cursorNum; /* The cursor number as defined in the display + * styles file. + */ +{ + HashEntry *entry; + HashSearch hs; + Tk_Window tkwind; + + if (cursorNum >= MAX_CURSORS) + { + TxError("No such cursor!\n"); + return; + } + + tcairoCurrent.cursor = grCursors[cursorNum]; + + HashStartSearch(&hs); + while (entry = HashNext(&grTCairoWindowTable, &hs)) + { + if (HashGetValue(entry)) + { + tkwind = (Tk_Window)entry->h_key.h_ptr; + Tk_DefineCursor(tkwind, tcairoCurrent.cursor); + } + } +} diff --git a/graphics/cairo_orig/grTCairo1.c b/graphics/cairo_orig/grTCairo1.c new file mode 100644 index 00000000..b632b984 --- /dev/null +++ b/graphics/cairo_orig/grTCairo1.c @@ -0,0 +1,1374 @@ +/* grTCairo1.c + * + * Copyright (C) 2017 Open Circuit Design + * + * This file contains primitive functions for Cairo running under + * an X window system in a Tcl/Tk interpreter environment + * + * Written by Chuan Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/main.h" +#include "utils/magic.h" +#include "utils/malloc.h" +#include "utils/magsgtty.h" +#include "utils/geometry.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "textio/textio.h" +#include "textio/txcommands.h" +#include "utils/signals.h" +#include "utils/utils.h" +#include "tiles/tile.h" +#include "utils/hash.h" +#include "database/database.h" +#include "drc/drc.h" +#include "utils/macros.h" +#include "graphics/grTCairoInt.h" +#include "utils/paths.h" +#include "graphics/grTkCommon.h" + +uint8_t **grTCairoStipples; +HashTable grTCairoWindowTable; +cairo_surface_t *grCairoSurface; +cairo_t *grCairoContext; +XVisualInfo *grVisualInfo; + +TCAIRO_CURRENT tcairoCurrent = {(Tk_Font)0, 0, 0, 0, 0, + (Tk_Window)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 GrTCairoClose(), GrTCairoFlush(); +extern void GrTCairoDelete(), GrTCairoConfigure(), GrTCairoRaise(), GrTCairoLower(); +extern void GrTCairoLock(), GrTCairoUnlock(), GrTCairoIconUpdate(); +extern bool GrTCairoInit(); +extern bool GrTCairoEventPending(), GrTCairoCreate(), grtcairoGetCursorPos(); +extern int GrTCairoWindowId(); +extern char *GrTkWindowName(); + +extern void tcairoSetProjection(); + +/*--------------------------------------------------------- + * grtcairoSetWMandC: + * This is a local routine that resets the value of the current + * write alpha (mask) and color, if necessary. + * + * Results: None. + * + * Side Effects: None. + * + * Errors: None. + *--------------------------------------------------------- + */ + +void +grtcairoSetWMandC (mask, c) +int mask; /* New value for write mask */ +int c; /* New value for current color */ +{ + static int oldColor = -1; + static int oldMask = -1; + + int lr, lb, lg; + float fr, fb, fg, aval; + + if (mask == -65) mask = 127; /* All planes */ + if (mask == oldMask && c == oldColor) return; + + GR_TCAIRO_FLUSH_BATCH(); + + GrGetColor(c, &lr, &lg, &lb); + + fr = ((float)lr / 255); + fg = ((float)lg / 255); + fb = ((float)lb / 255); + aval = ((float)mask / 127.0); + + cairo_set_source_rgba(grCairoContext, fr, fg, fb, aval); + + oldColor = c; + oldMask = mask; +} + + +/*--------------------------------------------------------- + * grtcairoSetLineStyle: + * This local routine sets the current line style. + * + * Results: None. + * + * Side Effects: + * A new line style is output to the display. + * + *--------------------------------------------------------- + */ + +void +grtcairoSetLineStyle (style) +int style; /* New stipple pattern for lines. */ +{ + // unimplemented for cairo +} + + +/*--------------------------------------------------------- + * grtcairoSetSPattern: + * tcairoSetSPattern associates a stipple pattern with a given + * stipple number. This is a local routine called from + * grStyle.c . + * + * Results: None. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +cairo_pattern_t **stipplePatterns; + +void +grtcairoSetSPattern (sttable, numstipples) +int **sttable; /* The table of patterns */ +int numstipples; /* Number of stipples */ +{ + int i, j, k, n; + uint8_t *pdata; + + stipplePatterns = (cairo_pattern_t **)mallocMagic(sizeof(cairo_pattern_t *) * numstipples); + + grTCairoStipples = (uint8_t **)mallocMagic(numstipples * sizeof(uint8_t *)); + for (k = 0; k < numstipples; k++) + { + pdata = (uint8_t *)mallocMagic(128 * sizeof(uint8_t)); + n = 0; + + /* expand magic's default 8x8 stipple to 32x32 */ + + for (i = 0; i < 32; i++) { + for (j = 0; j < 4; j++) { + pdata[n++] = (uint8_t)sttable[k][i % 8]; + } + } + + grTCairoStipples[k] = pdata; + stipplePatterns[k] = cairo_pattern_create_for_surface(cairo_image_surface_create_for_data(pdata, CAIRO_FORMAT_A1, 32, 32, + cairo_format_stride_for_width(CAIRO_FORMAT_A1, 32))); + } +} + + +/*--------------------------------------------------------- + * grtcairoSetStipple: + * 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. + *--------------------------------------------------------- + */ + +cairo_pattern_t *currentStipple; + +void +grtcairoSetStipple (stipple) +int stipple; /* The stipple number to be used. */ +{ + static int oldStip = -1; + if (stipple == oldStip) return; + oldStip = stipple; + GR_TCAIRO_FLUSH_BATCH(); + if (stipple == 0 || stipple > grNumStipples) { + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); + } else { + if (stipplePatterns[stipple] == (cairo_pattern_t *)NULL) MainExit(1); + cairo_pattern_set_extend(stipplePatterns[stipple], CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(stipplePatterns[stipple], CAIRO_FILTER_NEAREST); + currentStipple = stipplePatterns[stipple]; + } +} + + +/*------------------------------------------------------------------------ + * GrTCairoInit: + * GrTCairoInit initializes the graphics display and clears its screen. + * Files must have been previously opened with GrSetDisplay(); + * + * Results: TRUE if successful. + * + * Notes: When 3D rendering is compiled in, we search for a double-buffered + * configuration first, because it generates the smoothest graphics, + * and fall back on a single-buffered configuration if necessary. + * For normal, 2D-only rendering, we look for a single-buffered + * configuration first because we don't use the back buffer, so a + * double-buffered configuration just wastes space. + *------------------------------------------------------------------------ + */ + +bool +GrTCairoInit () +{ + bool rstatus; + + tcairoCurrent.window = Tk_MainWindow(magicinterp); // XDefaultRootWindow(grXdpy) ?? + if (tcairoCurrent.window == NULL) + { + TxError("No Top-Level Tk window available. . . is Tk running?\n"); + return FALSE; + } + + tcairoCurrent.windowid = Tk_WindowId(tcairoCurrent.window); + grXdpy = Tk_Display(tcairoCurrent.window); + tcairoCurrent.depth = Tk_Depth(tcairoCurrent.window); + + grXscrn = DefaultScreen(grXdpy); + + XVisualInfo grtemplate; + int gritems; + grtemplate.screen = grXscrn; + grtemplate.depth = 0; + grVisualInfo = XGetVisualInfo(grXdpy, VisualScreenMask, &grtemplate, &gritems); + + if (!grVisualInfo) + { + TxError("No suitable visual!\n"); + return FALSE; + } + + grXscrn = grVisualInfo->screen; + tcairoCurrent.depth = grVisualInfo->depth; + + grCairoSurface = cairo_xlib_surface_create(grXdpy, tcairoCurrent.windowid, grVisualInfo->visual, Tk_Width(tcairoCurrent.window), Tk_Height(tcairoCurrent.window)); + grCairoContext = cairo_create(grCairoSurface); + + cairo_set_line_width(grCairoContext, 1.0); + cairo_set_source_rgb(grCairoContext, 0, 0, 0); + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); + + /* Use OpenGL names for colormap and dstyle file types */ + grCMapType = "OpenGL"; + grDStyleType = "OpenGL"; + + /* Globally-accessed variables */ + grNumBitPlanes = tcairoCurrent.depth; + grBitPlaneMask = (1 << tcairoCurrent.depth) - 1; + + HashInit(&grTCairoWindowTable, 8, HT_WORDKEYS); + + return grTkLoadFont(); +} + +/*--------------------------------------------------------- + * GrTCairoClose: + * + * Results: None. + * + * Side Effects: + *--------------------------------------------------------- + */ + +void +GrTCairoClose () +{ + if (grXdpy == NULL) return; + if (grVisualInfo != NULL) XFree(grVisualInfo); + + grTkFreeFonts(); + /* Pop down Tk window but let Tcl/Tk */ + /* do XCloseDisplay() */ +} + + +/*--------------------------------------------------------- + * GrTCairoFlush: + * 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 +GrTCairoFlush () +{ + GR_TCAIRO_FLUSH_BATCH(); +} + +/* + *--------------------------------------------------------- + */ + +#define grTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n)) + +/* + *--------------------------------------------------------- + * Set the Cairo projection matrix for a window + *--------------------------------------------------------- + */ + +void +tcairoSetProjection(llx, lly, width, height) +int llx, lly, width, height; +{ + grCairoSurface = cairo_xlib_surface_create(grXdpy, tcairoCurrent.windowid, grVisualInfo->visual, width, height); + grCairoContext = cairo_create(grCairoSurface); + + cairo_identity_matrix(grCairoContext); + cairo_translate(grCairoContext, 0, height); + cairo_scale(grCairoContext, 1.0, -1.0); +} + + +/* + * --------------------------------------------------------------------------- + * + * TCairoEventProc --- + * + * Tk Event Handler + * + * Results: + * None. + * + * Side Effects: + * Calls functions in response to X11 events. + * + * --------------------------------------------------------------------------- + */ + +void +TCairoEventProc(clientData, xevent) +ClientData clientData; +XEvent *xevent; +{ + TxInputEvent *event; + HashEntry *entry; + Tk_Window tkwind = (Tk_Window)clientData; + Window wind; + MagWindow *mw; + unsigned char LocRedirect = TxInputRedirect; + + XKeyPressedEvent *KeyPressedEvent = (XKeyPressedEvent *) xevent; + KeySym keysym; + int nbytes; + + /* Keys and Buttons: Determine expansion of macros or redirect + * keys to the terminal or console. + */ + + switch (xevent->type) + { + case ButtonPress: + { + XButtonEvent *ButtonEvent = (XButtonEvent *) xevent; + int txbutton; + + switch (ButtonEvent->button) { + case Button1: + txbutton = TX_LEFT_BUTTON; + keysym = XK_Pointer_Button1; + break; + case Button2: + txbutton = TX_MIDDLE_BUTTON; + keysym = XK_Pointer_Button2; + break; + case Button3: + txbutton = TX_RIGHT_BUTTON; + keysym = XK_Pointer_Button3; + break; + case Button4: + txbutton = TX_BUTTON_4; + keysym = XK_Pointer_Button4; + break; + case Button5: + txbutton = TX_BUTTON_5; + keysym = XK_Pointer_Button5; + break; + } + nbytes = 0; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + if (mw && (mw->w_flags & WIND_SCROLLBARS)) + if (WindButtonInFrame(mw, ButtonEvent->x, + grXtransY(mw, ButtonEvent->y), + txbutton)) + break; + + goto keys_and_buttons; + } + break; + case KeyPress: + { + int keywstate, keymod, idx, idxmax; + char inChar[10]; + Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); + + nbytes = XLookupString(KeyPressedEvent, inChar, sizeof(inChar), + &keysym, NULL); + + if (IsModifierKey(keysym)) break; /* Don't handle modifiers */ + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + +keys_and_buttons: + + keymod = (LockMask | ControlMask | ShiftMask) + & KeyPressedEvent->state; +#ifdef __APPLE__ + if (KeyPressedEvent->state & (Mod1Mask | Mod2Mask | + Mod3Mask | Mod4Mask | Mod5Mask)) + keymod |= Mod1Mask; +#else + keymod |= (Mod1Mask & KeyPressedEvent->state); +#endif + + if (nbytes == 0) /* No ASCII equivalent */ + { + keywstate = (keymod << 16) | (keysym & 0xffff); + } + else if (!strncmp(XKeysymToString(keysym), "KP_", 3)) + { + /* keypad key (special case---would like to */ + /* differentiate between shift-KP-# and # itself) */ + keymod &= ~ShiftMask; + keywstate = (keymod << 16) | (keysym & 0xffff); + nbytes = 0; + } + else /* ASCII-valued character */ + { + if (!(keymod & (LockMask | Mod1Mask))) { + if (!(keymod & ControlMask)) + keymod &= ~ShiftMask; + else if (!(keymod & ShiftMask)) + keymod &= ~ControlMask; + } + } + + idxmax = (nbytes == 0) ? 1 : nbytes; + for (idx = 0; idx < idxmax; idx++) + { + if (inChar[idx] == 3) /* Ctrl-C interrupt */ + { + if (SigInterruptPending) + MainExit(0); /* double Ctrl-C */ + else + sigOnInterrupt(0); /* Set InterruptPending */ + break; + } + else if (nbytes > 0) + { + if ((keymod & ControlMask) && (inChar[idx] < 32)) + inChar[idx] += 'A' - 1; + + keywstate = (keymod << 16) | ((int)inChar[idx] & 0xff); + } + + /* Allow buttons to bypass the console and be */ + /* treated as macros. */ + + if (LocRedirect == TX_INPUT_REDIRECTED) + { + switch (keysym) + { + case XK_Pointer_Button1: + case XK_Pointer_Button2: + case XK_Pointer_Button3: + case XK_Pointer_Button4: + case XK_Pointer_Button5: + LocRedirect = TX_INPUT_NORMAL;; + break; + } + } + + if ((LocRedirect == TX_INPUT_REDIRECTED) && TxTkConsole) + { + Tcl_SavedResult state; + static char outstr[] = "::tkcon::Insert .text \"x\" "; + + switch (keysym) + { + case XK_Return: + TxSetPoint(KeyPressedEvent->x, + grXtransY(mw, KeyPressedEvent->y), + mw->w_wid); + TxInputRedirect = TX_INPUT_PROCESSING; + Tcl_EvalEx(consoleinterp, "::tkcon::Eval .text", + 19, 0); + TxInputRedirect = TX_INPUT_NORMAL; + TxSetPrompt('%'); + + Tcl_SaveResult(magicinterp, &state); + Tcl_EvalEx(magicinterp, "history event 0", 15, 0); + MacroDefine(mw->w_client, (int)'.', + Tcl_GetStringResult(magicinterp), NULL, + FALSE); + Tcl_RestoreResult(magicinterp, &state); + break; + case XK_Up: + Tcl_EvalEx(consoleinterp, "::tkcon::Event -1", + 17, 0); + break; + case XK_Down: + Tcl_EvalEx(consoleinterp, "::tkcon::Event 1", + 16, 0); + break; + case XK_Left: + Tcl_EvalEx(consoleinterp, ".text mark set insert " + "insert-1c ; .text see insert", 50, 0); + break; + case XK_Right: + Tcl_EvalEx(consoleinterp, ".text mark set insert " + "insert+1c ; .text see insert", 50, 0); + break; + case XK_BackSpace: case XK_Delete: + Tcl_EvalEx(consoleinterp, ".text delete insert-1c ;" + ".text see insert", 40, 0); + break; + case XK_quotedbl: case XK_backslash: case XK_bracketleft: + outstr[23] = '\\'; + outstr[24] = inChar[idx]; + outstr[25] = '\"'; + Tcl_EvalEx(consoleinterp, outstr, 26, 0); + outstr[24] = '\"'; + outstr[25] = '\0'; + default: + outstr[23] = inChar[idx]; + Tcl_EvalEx(consoleinterp, outstr, 25, 0); + break; + } + } + else if (LocRedirect == TX_INPUT_REDIRECTED) { + int tl; + if (TxBuffer == NULL) + { + TxBuffer = Tcl_Alloc(2); + *TxBuffer = '\0'; + tl = 0; + } + else + { + tl = strlen(TxBuffer); + TxBuffer = Tcl_Realloc(TxBuffer, tl + 2); + } + if (keysym == XK_BackSpace || keysym == XK_Delete) + { + if (tl >= 0) + { + if (tl > 0) + { + *(TxBuffer + tl - 1) = '\0'; + TxPrintf("\b"); + } + TxPrintf(" \b"); + TxFlushOut(); + } + } + else if (keysym == XK_Return) + { + *(TxBuffer + tl) = '\n'; + *(TxBuffer + tl + 1) = '\0'; + if (tl != 0) MacroDefine(mw->w_client, + XK_period, TxBuffer, NULL, FALSE); + TxInputRedirect = TX_INPUT_NORMAL; + TxSetPoint(KeyPressedEvent->x, + grXtransY(mw, KeyPressedEvent->y), + mw->w_wid); + TxPrintf("\n"); + TxFlushOut(); + Tcl_NotifyChannel(Tcl_GetStdChannel(TCL_STDIN), + TCL_READABLE); + } + else + { + *(TxBuffer + tl) = *(inChar + idx); + *(TxBuffer + tl + 1) = '\0'; + TxPrintf("%c", *(inChar + idx)); + TxFlushOut(); + } + } + else + { + bool iMacro; + char *macroDef; + + macroDef = MacroRetrieve(mw->w_client, keywstate, &iMacro); + + /* Special handling: An imacro beginning with ':' */ + /* sets the prompt to ':' and moves to the next char. */ + + if (macroDef != NULL && *macroDef == ':' && iMacro) + { + if (TxTkConsole) + TxSetPrompt(':'); + else + { + TxPrintf("\b\b: "); + TxFlushOut(); + } + memmove(macroDef, macroDef + 1, strlen(macroDef + 1) + 1); + } + + macroDef = MacroSubstitute(macroDef, "%W", Tk_PathName(tkwind)); + + if (macroDef == NULL) + { + if (keysym != XK_Return) + { + char *vis = MacroName(keywstate); + TxError("Unknown macro or short command: '%s'\n", vis); + + freeMagic(vis); + } + /* Print Carriage Return & Put back Tcl/Tk prompt */ + TxParseString("", NULL, NULL); + } + else + { + int sl = strlen(macroDef); + + if (iMacro) + { + /* Echo macro to interpreter, then redirect keys */ + + if (TxTkConsole) + { + char *outstring = Tcl_Alloc(sl + 20); + sprintf(outstring, ".text insert end \"%s\"", + macroDef); + Tcl_EvalEx(consoleinterp, outstring, -1, 0); + Tcl_Free(outstring); + } + else + { + TxBuffer = Tcl_Alloc(sl + 1); + strcpy(TxBuffer, macroDef); + TxPrintf("%s", macroDef); + TxFlushOut(); + } + TxInputRedirect = TX_INPUT_REDIRECTED; + } + else + { + /* TxParseString is defined by tcltk/tclmagic.c + * and calls Tcl_Eval() + */ + + TxSetPoint(KeyPressedEvent->x, + grXtransY(mw, KeyPressedEvent->y), + mw->w_wid); + TxParseString(macroDef, NULL, NULL); + } + freeMagic(macroDef); + } + } + } + } + break; + case ConfigureNotify: + { + XConfigureEvent *ConfigureEvent = (XConfigureEvent*) xevent; + Rect screenRect; + int width, height; + bool result, need_resize; + + width = ConfigureEvent->width; + height = ConfigureEvent->height; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + screenRect.r_xbot = ConfigureEvent->x; + screenRect.r_xtop = ConfigureEvent->x + width; + screenRect.r_ytop = grTransYs(ConfigureEvent->y); + screenRect.r_ybot = grTransYs(ConfigureEvent->y + height); + + need_resize = (screenRect.r_xbot != mw->w_screenArea.r_xbot || + screenRect.r_xtop != mw->w_screenArea.r_xtop || + screenRect.r_ybot != mw->w_screenArea.r_ybot || + screenRect.r_ytop != mw->w_screenArea.r_ytop); + + /* Redraw the window */ + + WindReframe(mw, &screenRect, FALSE, FALSE); + WindRedisplay(mw); + if (need_resize) (*GrCreateBackingStorePtr)(mw); + } + break; + case VisibilityNotify: + { + XVisibilityEvent *VisEvent = (XVisibilityEvent*) xevent; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + switch (VisEvent->state) + { + case VisibilityUnobscured: + mw->w_flags &= ~WIND_OBSCURED; + if (mw->w_backingStore == (ClientData)NULL) + { + (*GrCreateBackingStorePtr)(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: + { + XExposeEvent *ExposeEvent = (XExposeEvent*) xevent; + Rect screenRect; + + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + + 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; + (*GrGetBackingStorePtr)(mw, &screenRect); + WindScreenToSurface(mw, &screenRect, &surface); + DBWHLRedrawPrepWindow(mw, &surface); + WindDrawBorder(mw, &screenRect); + } + else + WindAreaChanged(mw, &screenRect); + WindUpdate(); + } + break; + + case MapNotify: + case UnmapNotify: + case DestroyNotify: /* Do nothing */ + break; + + default: + TxError("Tk Event: Unknown (%d)\n", xevent->type); + TxFlush(); + break; + } +} + + + +/*--------------------------------------------------------- + * cairoSetDisplay: + * This routine sets the appropriate parameters so that + * Magic will work with the X display. + * + * Under Xlib, all input events (mouse and keyboard) are + * sent to one queue which has to be polled to discover + * whether there is any input or not. To fit the Magic + * interrupt-driven input model, a helper process is + * spawned which reads and blocks on the event queue, + * sending SIGIO's to Magic when it detects input. The + * input read in the helper process is then sent to Magic + * via a communication pipe. + * + * Results: success / fail + * + * Side Effects: Sets up the pipe. + *--------------------------------------------------------- + */ + +bool +cairoSetDisplay (dispType, outFileName, mouseFileName) +char *dispType; +char *outFileName; +char *mouseFileName; +{ + char *planecount; + char *fullname; + FILE* f; + bool execFailed = FALSE; + int x, y, width, height; + + WindPackageType = WIND_X_WINDOWS; /* to be changed? */ + TxInputRedirect = TX_INPUT_NORMAL; + + grCursorType = "color"; + WindScrollBarWidth = 14; + + /* Set up the procedure values in the indirection table. */ + + GrPixelCorrect = 0; + + GrLockPtr = GrTCairoLock; + GrUnlockPtr = GrTCairoUnlock; + GrInitPtr = GrTCairoInit; + GrClosePtr = GrTCairoClose; + GrSetCMapPtr = GrTCairoSetCMap; + + GrEnableTabletPtr = GrTCairoEnableTablet; + GrDisableTabletPtr = GrTCairoDisableTablet; + GrSetCursorPtr = GrTCairoSetCursor; + GrTextSizePtr = GrTCairoTextSize; + GrDrawGlyphPtr = GrTCairoDrawGlyph; + GrReadPixelPtr = GrTCairoReadPixel; + GrFlushPtr = GrTCairoFlush; + + GrCreateWindowPtr = GrTCairoCreate; + GrDeleteWindowPtr = GrTCairoDelete; + GrConfigureWindowPtr = GrTCairoConfigure; + GrOverWindowPtr = GrTCairoRaise; + GrUnderWindowPtr = GrTCairoLower; + GrUpdateIconPtr = GrTCairoIconUpdate; + GrEventPendingPtr = GrTCairoEventPending; + GrWindowIdPtr = GrTCairoWindowId; + GrWindowNamePtr = GrTkWindowName; /* from grTkCommon.c */ + GrGetCursorPosPtr = grtcairoGetCursorPos; + GrGetCursorRootPosPtr = grtcairoGetCursorRootPos; + + /* local indirections */ + grSetSPatternPtr = grtcairoSetSPattern; + grPutTextPtr = grtcairoPutText; +#ifdef VECTOR_FONTS + grFontTextPtr = grtcairoFontText; +#endif + grDefineCursorPtr = grTkDefineCursor; + grFreeCursorPtr = grTkFreeCursors; + GrBitBltPtr = GrTCairoBitBlt; + grDrawGridPtr = grtcairoDrawGrid; + grDrawLinePtr = grtcairoDrawLine; + grSetWMandCPtr = grtcairoSetWMandC; + grFillRectPtr = grtcairoFillRect; + grSetStipplePtr = grtcairoSetStipple; + grSetLineStylePtr = grtcairoSetLineStyle; + grSetCharSizePtr = grtcairoSetCharSize; + grFillPolygonPtr = grtcairoFillPolygon; + /* + #ifdef X11_BACKING_STORE + GrFreeBackingStorePtr = grtkFreeBackingStore; + GrCreateBackingStorePtr = grtkCreateBackingStore; + GrGetBackingStorePtr = grtkGetBackingStore; + GrPutBackingStorePtr = grtkPutBackingStore; + GrScrollBackingStorePtr = grtkScrollBackingStore; + #else + */ + GrFreeBackingStorePtr = grtcairoFreeBackingStore; + GrCreateBackingStorePtr = grtcairoCreateBackingStore; + GrGetBackingStorePtr = grtcairoGetBackingStore; + GrPutBackingStorePtr = grtcairoPutBackingStore; + GrScrollBackingStorePtr = grtcairoScrollBackingStore; +//#endif + + if (execFailed) { + TxError("Execution failed!\n"); + return FALSE; + } + + if (!GrTCairoInit()) { + return FALSE; + }; + + Tk_GetVRootGeometry(Tk_MainWindow(magicinterp), &x, &y, &width, &height); + GrScreenRect.r_xbot = x; + GrScreenRect.r_ybot = y; + GrScreenRect.r_xtop = width + x; + GrScreenRect.r_ytop = height + y; + + return Tk_MainWindow(magicinterp) ? TRUE : FALSE; +} + +extern void MakeWindowCommand(); + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoCreate -- + * Create a new window under the X window system. + * Bind X window to Magic Window w. + * + * Results: + * Success/Fail + * + * Side Effects: + * Window created, window ID send to Xhelper. + * + * ---------------------------------------------------------------------------- + */ + +bool +GrTCairoCreate(w, name) +MagWindow *w; +char *name; +{ + Tk_Window tkwind, tktop; + Window wind; + static int WindowNumber = 0; + HashEntry *entry; + char *windowplace; + char windowname[10]; + int x = w->w_frameArea.r_xbot; + int y = grTransYs(w->w_frameArea.r_ytop); + int width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot; + int height = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot; + unsigned long attribmask = CWBackPixel | CWBorderPixel | CWColormap; + XSetWindowAttributes grAttributes; + + WindSeparateRedisplay(w); + + sprintf(windowname, ".magic%d", WindowNumber + 1); + if (windowplace = XGetDefault(grXdpy, "magic", windowname)) + { + XParseGeometry(windowplace, &x, &y, + (unsigned int *)&width, (unsigned int *)&height); + w->w_frameArea.r_xbot = x; + w->w_frameArea.r_xtop = x + width; + w->w_frameArea.r_ytop = grTransYs(y); + w->w_frameArea.r_ybot = grTransYs(y + height); + WindReframe(w, &(w->w_frameArea), FALSE, FALSE); + } + + grAttributes.colormap = XCreateColormap(grXdpy, RootWindow(grXdpy, grXscrn), + grVisualInfo->visual, AllocNone); + grAttributes.background_pixel = WhitePixel(grXdpy, grXscrn); + grAttributes.border_pixel = BlackPixel(grXdpy, grXscrn); + + if (tktop = Tk_MainWindow(magicinterp)) + { + if (!WindowNumber) + { + /* To do: deal with grVisualInfo---destroy and recreate top */ + /* frame if necessary */ + + if (Tk_WindowId(tktop) == 0) + { + Tk_SetWindowVisual(tktop, grVisualInfo->visual, + tcairoCurrent.depth, grAttributes.colormap); + } + else + { + /* The Top-level window has already been mapped. We can't mess */ + /* with it's visual. If the title is "wish", we'll assume that */ + /* nobody else is claiming it, and unmap it. */ + + if (!strcmp(Tk_Name(tktop), "wish")) Tk_UnmapWindow(tktop); + } + } + } + else + return 0; /* failure */ + + /* Last parameter "" indicates a top-level window in the space of */ + /* the parent. */ + + if (name == NULL) + tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, windowname, ""); + else + tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, name, NULL); + + /* TxError("Creating window named \"%s\", tkwind = 0x%x\n", + windowname, tkwind); TxFlush(); */ + + if (tkwind != 0) + { + bool result; + + GrTCairoFlush(); + + tcairoCurrent.window = tkwind; + tcairoCurrent.mw = w; + + w->w_grdata = (ClientData) tkwind; + + entry = HashFind(&grTCairoWindowTable, (char *)tkwind); + HashSetValue(entry, w); + + /* ensure that the visual is what we wanted, if possible to change */ + + Tk_SetWindowVisual(tkwind, grVisualInfo->visual, tcairoCurrent.depth, + grAttributes.colormap); + + /* map the window, if necessary */ + + Tk_MapWindow(tkwind); + + /* use x, y, width, height to size and position the window */ + + Tk_GeometryRequest(tkwind, width, height); + /* Tk_MoveResizeWindow(tkwind, x, y, width, height); */ + + wind = Tk_WindowId(tkwind); + tcairoCurrent.windowid = wind; + grCairoSurface = cairo_xlib_surface_create(grXdpy, tcairoCurrent.windowid, grVisualInfo->visual, Tk_Width(tcairoCurrent.window), Tk_Height(tcairoCurrent.window)); + grCairoContext = cairo_create(grCairoSurface); + + Tk_DefineCursor(tkwind, tcairoCurrent.cursor); + GrTCairoIconUpdate(w, w->w_caption); + + WindowNumber++; + + /* execute all Tk events up to current */ + + while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0); + + /* set up Tk event handler to start processing */ + + Tk_CreateEventHandler(tkwind, ExposureMask | StructureNotifyMask + | ButtonPressMask | KeyPressMask | VisibilityChangeMask, + (Tk_EventProc *)TCairoEventProc, (ClientData) tkwind); + + /* set up commands to be passed expressly to this window */ + + MakeWindowCommand((name == NULL) ? windowname : name, w); + + return (WindowNumber == 1) ? grtcairoLoadFont() : 1; + } + else + { + TxError("Could not open new Tk window\n"); + } + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoDelete -- + * Destroy a Tk/Cairo window. + * + * Results: + * None. + * + * Side Effects: + * Window destroyed. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoDelete(w) +MagWindow *w; +{ + Tk_Window xw; + HashEntry *entry; + + xw = (Tk_Window) w->w_grdata; + entry = HashLookOnly(&grTCairoWindowTable, (char *)xw); + HashSetValue(entry, NULL); + + Tcl_DeleteCommand(magicinterp, Tk_PathName(xw)); + Tk_DestroyWindow(xw); +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoConfigure -- + * Resize/ Move an existing X window. + * + * Results: + * None. + * + * Side Effects: + * Window reconfigured to w->w_frameArea. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoConfigure(w) +MagWindow *w; +{ + if (w->w_flags & WIND_OFFSCREEN) return; + + Tk_MoveResizeWindow((Tk_Window)w->w_grdata, + w->w_frameArea.r_xbot, grTransYs(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); +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoRaise -- + * Raise a window to the top of the screen such that nothing + * obscures it. + * + * Results: + * None. + * + * Side Effects: + * Window raised. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoRaise(w) +MagWindow *w; +{ + Tk_Window tkwind; + + if (w->w_flags & WIND_OFFSCREEN) return; + + tkwind = (Tk_Window)w->w_grdata; + Tk_RestackWindow(tkwind, Above, NULL); +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoLower -- + * Lower a window below all other Tk windows. + * obscures it. + * + * Results: + * None. + * + * Side Effects: + * Window lowered. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoLower(w) +MagWindow *w; +{ + Tk_Window tkwind; + + if (w->w_flags & WIND_OFFSCREEN) return; + + tkwind = (Tk_Window)w->w_grdata; + Tk_RestackWindow(tkwind, Below, NULL); +} + + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoLock -- + * Lock a window and set global variables "tcairoCurrent.window" + * and "tcairoCurrent.mw" to reference the locked window. + * + * Results: + * None. + * + * Side Effects: + * Window locked. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoLock(w, flag) +MagWindow *w; +bool flag; +{ + Window wind; + + grSimpleLock(w, flag); + if ( w != GR_LOCK_SCREEN ) + { + tcairoCurrent.mw = w; + + if (w->w_flags & WIND_OFFSCREEN) + { + tcairoCurrent.window = (Tk_Window) NULL; + tcairoCurrent.windowid = (Pixmap) w->w_grdata; + } + else + { + tcairoCurrent.window = (Tk_Window) w->w_grdata; + tcairoCurrent.windowid = Tk_WindowId(tcairoCurrent.window); + } + + tcairoSetProjection(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); + } +} + +/* + * ---------------------------------------------------------------------------- + * + * GrTCairoUnlock -- + * Unlock a window, flushing stuff out to the display. + * + * Results: + * None. + * + * Side Effects: + * Window unlocked. + * Display update. + * + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoUnlock(w) +MagWindow *w; +{ + /* GR_TCairo_FLUSH_BATCH(); */ + GrTCairoFlush(); + grSimpleUnlock(w); +} + + +/* + *------------------------------------------------------------------------- + * GrTCairoEventPending -- + * check for pending graphics events. + * Here we use the X11 check for window events, because Tcl/Tk doesn't + * allows peeking into its event queue without executing whatever is + * in the queue. + * + * Results: + * TRUE if an event is waiting in the event queue. + * + * Side effects: + * None, hopefully (put back the event!) + * + *------------------------------------------------------------------------- + */ + +bool +GrTCairoEventPending() +{ + Window wind = tcairoCurrent.windowid; + XEvent genEvent; + bool retval; + + XSync(grXdpy, FALSE); /* Necessary, or it won't catch mouse/key events */ + retval = XCheckWindowEvent(grXdpy, wind, ExposureMask + | StructureNotifyMask | ButtonPressMask + | KeyPressMask, &genEvent); + if (retval) XPutBackEvent(grXdpy, &genEvent); + return retval; +} + +/* + *------------------------------------------------------------------------- + * + * GrTCairoIconUpdate -- updates the icon text with the window script + * + * Results: none + * + * Side Effects: changes the icon text + * + *------------------------------------------------------------------------- + */ + +void +GrTCairoIconUpdate(w, text) /* See Blt code */ +MagWindow *w; +char *text; +{ + Tk_Window tkwind; + Window wind; + XClassHint class; + char *brack; + + if (w->w_flags & WIND_OFFSCREEN) return; + + tkwind = (Tk_Window)(w->w_grdata); + if (tkwind == NULL) { + tkwind = Tk_MainWindow(magicinterp); + if (tkwind == NULL) return; + } + wind = Tk_WindowId(tkwind); + if (wind == 0) return; + + class.res_name = "magic"; + class.res_class = "magic"; + + XSetClassHint( grXdpy, wind, &class); + if (text) + { + 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); + } +} + +/* + *------------------------------------------------------------------------- + * GrTCairoWindowId -- + * Get magic's ID number from the indicated MagWindow structure + * + * Results: + * The window ID number. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +int +GrTCairoWindowId(tkname) +char *tkname; +{ + Tk_Window tkwind; + MagWindow *mw; + HashEntry *entry; + int id = 0; + + tkwind = Tk_NameToWindow(magicinterp, tkname, Tk_MainWindow(magicinterp)); + if (tkwind != NULL) + { + entry = HashLookOnly(&grTCairoWindowTable, (char *)tkwind); + mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0; + if (mw) { + id = mw->w_wid; + } + } + return id; +} diff --git a/graphics/cairo_orig/grTCairo2.c b/graphics/cairo_orig/grTCairo2.c new file mode 100644 index 00000000..d1c37fd3 --- /dev/null +++ b/graphics/cairo_orig/grTCairo2.c @@ -0,0 +1,213 @@ +/* grTCairo2.c - + * + * Copyright 2017 Open Circuit Design + * + * This file contains additional functions to manipulate an X + * color display. Included here are rectangle drawing and color map + * loading. + * + * Written by Chuan Chen + */ + +#include +char *getenv(); + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "graphics/glyphs.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "grTCairoInt.h" + +#include "textio/txcommands.h" + +extern char *DBWStyleType; +extern Display *grXdpy; + +extern cairo_t *grCairoContext; +extern cairo_surface_t *grCairoSurface; +extern cairo_pattern_t *currentStipple; + +/*--------------------------------------------------------- + * GrTCairoSetCMap -- + * + * Cairo uses RGB values as read from the colormap file, + * directly, so there is no need to install colors into a + * colormap. Therefore, this is a null routine. + * + * Results: None. + * + * Side Effects: None. + * + *--------------------------------------------------------- + */ + +void +GrTCairoSetCMap () +{ +} + +Rect grtcairoLines[TCAIRO_BATCH_SIZE]; +int grtcairoNbLines = 0; +TCairoRect grtcairoRects[TCAIRO_BATCH_SIZE]; +int grtcairoNbRects = 0; +Rect grtcairoDiagonal[TCAIRO_BATCH_SIZE]; +int grtcairoNbDiagonal = 0; + +/*--------------------------------------------------------- + * grtcairoDrawLines: + * This routine draws a batch of lines. + * + * Results: None. + * + * Side Effects: + * Draw a bunch of lines. + *--------------------------------------------------------- + */ + +void +grtcairoDrawLines(lines, nb) +Rect lines[]; +int nb; +{ + int i; + for (i = 0; i < nb; i++) + { + cairo_move_to(grCairoContext, lines[i].r_ll.p_x, lines[i].r_ll.p_y); + cairo_line_to(grCairoContext, lines[i].r_ur.p_x, lines[i].r_ur.p_y); + } + // cairo_set_source_rgba(grCairoContext, r, g, b, a); + // cairo_set_line_width(grCairoContext, width); + cairo_stroke(grCairoContext); +} + +/*--------------------------------------------------------- + * grtcairoDrawLine: + * This routine draws a line. + * + * Results: None. + * + * Side Effects: + * Draw a line for (x1, y1) to (x2, y2) inclusive. + *--------------------------------------------------------- + */ + +void +grtcairoDrawLine (x1, y1, x2, y2) +int x1, y1; /* Screen coordinates of first point. */ +int x2, y2; /* Screen coordinates of second point. */ +{ + /* Treat straight and diagonal lines separately. */ + /* (Done for OpenGL; possibly not necessary for Cairo) */ + + if ((x1 == x2) || (y1 == y2)) + { + if (grtcairoNbLines == TCAIRO_BATCH_SIZE) GR_TCAIRO_FLUSH_LINES(); + grtcairoLines[grtcairoNbLines].r_ll.p_x = x1; + grtcairoLines[grtcairoNbLines].r_ll.p_y = y1; + grtcairoLines[grtcairoNbLines].r_ur.p_x = x2; + grtcairoLines[grtcairoNbLines].r_ur.p_y = y2; + grtcairoNbLines++; + } + else + { + if (grtcairoNbDiagonal == TCAIRO_BATCH_SIZE) GR_TCAIRO_FLUSH_DIAGONAL(); + grtcairoDiagonal[grtcairoNbDiagonal].r_ll.p_x = x1; + grtcairoDiagonal[grtcairoNbDiagonal].r_ll.p_y = y1; + grtcairoDiagonal[grtcairoNbDiagonal].r_ur.p_x = x2; + grtcairoDiagonal[grtcairoNbDiagonal].r_ur.p_y = y2; + grtcairoNbDiagonal++; + } +} + +/*--------------------------------------------------------- + * grtcairoFillRects: + * This routine draws a bunch of solid rectangles. + * + * Results: None. + * + * Side Effects: + * Drawing. + *--------------------------------------------------------- + */ + +void +grtcairoFillRects(rects, nb) +TCairoRect rects[]; +int nb; +{ + int i; + + for (i = 0; i < nb; i++) + { + cairo_rectangle(grCairoContext, + rects[i].r_ll.p_x, rects[i].r_ll.p_y, + rects[i].r_ur.p_x-rects[i].r_ll.p_x, rects[i].r_ur.p_y-rects[i].r_ll.p_y); + // TxPrintf("%d %d %d %d \n", rects[i].r_ll.p_x, rects[i].r_ll.p_y, rects[i].r_ur.p_x-rects[i].r_ll.p_x, rects[i].r_ur.p_y-rects[i].r_ll.p_y); + } + cairo_clip(grCairoContext); + cairo_mask(grCairoContext, currentStipple); +} + +/*--------------------------------------------------------- + * grtcairoFillRect: + * This routine draws a solid rectangle. + * + * Results: None. + * + * Side Effects: + * Drawing. + *--------------------------------------------------------- + */ + +void +grtcairoFillRect(r) +Rect *r; /* Address of a rectangle in screen + * coordinates. + */ +{ + if (grtcairoNbRects == TCAIRO_BATCH_SIZE) GR_TCAIRO_FLUSH_RECTS(); + grtcairoRects[grtcairoNbRects].r_ll.p_x = r->r_ll.p_x; + grtcairoRects[grtcairoNbRects].r_ll.p_y = r->r_ll.p_y; + + grtcairoRects[grtcairoNbRects].r_ur.p_x = r->r_ur.p_x; + grtcairoRects[grtcairoNbRects].r_ur.p_y = r->r_ur.p_y; + + grtcairoRects[grtcairoNbRects].r_ul.p_x = r->r_ll.p_x; + grtcairoRects[grtcairoNbRects].r_ul.p_y = r->r_ur.p_y; + + grtcairoRects[grtcairoNbRects].r_lr.p_x = r->r_ur.p_x; + grtcairoRects[grtcairoNbRects].r_lr.p_y = r->r_ll.p_y; + + grtcairoNbRects++; +} + +/*--------------------------------------------------------- + * grtcairoFillPolygon: + * This routine draws a solid (convex) polygon + * + * Results: None. + * + * Side Effects: + * Drawing. + *--------------------------------------------------------- + */ + +void +grtcairoFillPolygon(tp, np) +Point *tp; +int np; +{ + int i; + cairo_move_to(grCairoContext, tp[0].p_x, tp[0].p_y); + for (i = 1; i < np; i++) + cairo_line_to(grCairoContext, tp[i].p_x, tp[i].p_y); + cairo_close_path(grCairoContext); + cairo_fill(grCairoContext); +} + diff --git a/graphics/cairo_orig/grTCairo3.c b/graphics/cairo_orig/grTCairo3.c new file mode 100644 index 00000000..dbea19af --- /dev/null +++ b/graphics/cairo_orig/grTCairo3.c @@ -0,0 +1,647 @@ +/* grTCairo3.c - + * + * Copyright 2017 Open Circuit Design + * + * This file contains additional functions to manipulate an X window system + * color display. Included here are device-dependent routines to draw and + * erase text and draw a grid. + * + * Written by Chuan Chen + */ + +#include +#include + +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "utils/geometry.h" +#include "utils/malloc.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "dbwind/dbwind.h" +#include "textio/textio.h" +#include "utils/signals.h" +#include "utils/utils.h" +#include "utils/hash.h" +#include "graphics/grTCairoInt.h" +#include "graphics/grTkCommon.h" +#include "database/fonts.h" + +extern Display *grXdpy; +extern cairo_t *grCairoContext; +extern cairo_surface_t *grCairoSurface; + +static GC grXcopyGC = (GC)NULL; + +/* locals */ + + +/*--------------------------------------------------------- + * grtcairoDrawGrid: + * grxDrawGrid adds a grid to the grid layer, using the current + * write mask and color. + * + * Results: + * TRUE is returned normally. However, if the grid gets too small + * to be useful, then nothing is drawn and FALSE is returned. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +bool +grtcairoDrawGrid (prect, outline, clip) +Rect *prect; /* A rectangle that forms the template + * for the grid. Note: in order to maintain + * precision for the grid, the rectangle + * coordinates are specified in units of + * screen coordinates multiplied by SUBPIXEL. + */ +int outline; /* the outline style */ +Rect *clip; /* a clipping rectangle */ +{ + int xsize, ysize; + int x, y; + int xstart, ystart; + int snum, low, hi, shifted; + + xsize = prect->r_xtop - prect->r_xbot; + ysize = prect->r_ytop - prect->r_ybot; + if (!xsize || !ysize || GRID_TOO_SMALL(xsize, ysize)) + return FALSE; + + xstart = prect->r_xbot % xsize; + while (xstart < clip->r_xbot << SUBPIXELBITS) xstart += xsize; + ystart = prect->r_ybot % ysize; + while (ystart < clip->r_ybot << SUBPIXELBITS) ystart += ysize; + + snum = 0; + low = clip->r_ybot; + hi = clip->r_ytop; + for (x = xstart; x < (clip->r_xtop + 1) << SUBPIXELBITS; x += xsize) + { + shifted = x >> SUBPIXELBITS; + cairo_move_to(grCairoContext, shifted, low); + cairo_line_to(grCairoContext, shifted, hi); + snum++; + } + + snum = 0; + low = clip->r_xbot; + hi = clip->r_xtop; + for (y = ystart; y < (clip->r_ytop + 1) << SUBPIXELBITS; y += ysize) + { + shifted = y >> SUBPIXELBITS; + cairo_move_to(grCairoContext, low, shifted); + cairo_line_to(grCairoContext, hi, shifted); + snum++; + } + cairo_stroke(grCairoContext); + return TRUE; +} + + +/*--------------------------------------------------------- + * grtcairoLoadFont + * This local routine loads the default ("toy API") + * font for Cairo. + * + * Results: Success/Failure + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +bool +grtcairoLoadFont() +{ + cairo_select_font_face(grCairoContext, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + return TRUE; +} + + +/*--------------------------------------------------------- + * grtcairoSetCharSize: + * This local routine sets the character size in the display, + * if necessary. + * + * Results: None. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +void +grtcairoSetCharSize (size) +int size; /* Width of characters, in pixels (6 or 8). */ +{ + tcairoCurrent.fontSize = size; + cairo_set_font_size(grCairoContext, size * 4 + 10); + switch (size) + { + case GR_TEXT_DEFAULT: + case GR_TEXT_SMALL: + tcairoCurrent.font = grSmallFont; + break; + case GR_TEXT_MEDIUM: + tcairoCurrent.font = grMediumFont; + break; + case GR_TEXT_LARGE: + tcairoCurrent.font = grLargeFont; + break; + case GR_TEXT_XLARGE: + tcairoCurrent.font = grXLargeFont; + break; + default: + TxError("%s%d\n", "grtcairoSetCharSize: Unknown character size ", + size ); + break; + } +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoTextSize -- + * + * Determine the size of a text string. + * + * Results: + * None. + * + * Side effects: + * A rectangle is filled in that is the size of the text in pixels. + * The origin (0, 0) of this rectangle is located on the baseline + * at the far left side of the string. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoTextSize(text, size, r) +char *text; +int size; +Rect *r; +{ + Tk_FontMetrics overall; + Tk_Font font; + int width; + + switch (size) { + case GR_TEXT_DEFAULT: + case GR_TEXT_SMALL: + font = grSmallFont; + break; + case GR_TEXT_MEDIUM: + font = grMediumFont; + break; + case GR_TEXT_LARGE: + font = grLargeFont; + break; + case GR_TEXT_XLARGE: + font = grXLargeFont; + break; + default: + TxError("%s%d\n", "GrTCairoTextSize: Unknown character size ", + size ); + break; + } + if (font == NULL) return; + Tk_GetFontMetrics(font, &overall); + width = Tk_TextWidth(font, text, strlen(text)); + /* Hack alert! Tk_TextWidth returns values too small! */ + width = width + (width >> 4); + r->r_ytop = overall.ascent; + r->r_ybot = -overall.descent; + r->r_xtop = width; + r->r_xbot = 0; +} + +/* Cairo backing store functions (now removed from the X11-based ones) */ + +void +grtcairoFreeBackingStore(MagWindow *window) +{ + Pixmap pmap = (Pixmap)window->w_backingStore; + if (pmap == (Pixmap)NULL) return; + XFreePixmap(grXdpy, pmap); + window->w_backingStore = (ClientData)NULL; +} + +void +grtcairoCreateBackingStore(MagWindow *w) +{ + Pixmap pmap; + Tk_Window tkwind = (Tk_Window)w->w_grdata; + Window wind; + unsigned int width, height; + GC gc; + XGCValues gcValues; + int grDepth; + + /* Deferred */ + if (tkwind == NULL) return; + + wind = (Window)Tk_WindowId(tkwind); + + /* ignore all windows other than layout */ + if (w->w_client != DBWclientID) return; + + /* deferred */ + if (wind == (Window)NULL) return; + + width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; + height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; + + if (w->w_backingStore != (ClientData)NULL) grtcairoFreeBackingStore(w); + + if (grXcopyGC == (GC)NULL) + { + gcValues.graphics_exposures = FALSE; + grXcopyGC = XCreateGC(grXdpy, wind, GCGraphicsExposures, &gcValues); + } + + grDepth = Tk_Depth((Tk_Window)w->w_grdata); + + pmap = XCreatePixmap(grXdpy, wind, width, height, grDepth); + w->w_backingStore = (ClientData)pmap; +} + +bool +grtcairoGetBackingStore(MagWindow *w, Rect *area) +{ + unsigned int width, height; + int xbot, ybot; + Rect r; + + if (w->w_backingStore == (ClientData)0) return FALSE; + + GEO_EXPAND(area, 1, &r); + GeoClip(&r, &(w->w_screenArea)); + + width = r.r_xtop - r.r_xbot; + height = r.r_ytop - r.r_ybot; + + xbot = r.r_xbot; + ybot = r.r_ybot; + + Window root_return; + int x_return, y_return; + unsigned int width_return, height_return; + unsigned int border_width_return; + unsigned int depth_return; + + Pixmap pmap; + pmap = (Pixmap)w->w_backingStore; + if (pmap == (Pixmap)NULL) + return FALSE; + + XGetGeometry(grXdpy, pmap, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); + + cairo_surface_t *backingStoreSurface; + backingStoreSurface = cairo_xlib_surface_create(grXdpy, pmap, DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width_return, height_return); + cairo_set_source_surface(grCairoContext, backingStoreSurface, 0, 0); + cairo_rectangle(grCairoContext, xbot, ybot, width, height); + cairo_set_operator(grCairoContext, CAIRO_OPERATOR_SOURCE); + cairo_fill(grCairoContext); + + return TRUE; +} + + +bool +grtcairoScrollBackingStore(MagWindow *w, Point *shift) +{ + // (copied from grX11su3.c) + Pixmap pmap; + unsigned int width, height; + int xorigin, yorigin, xshift, yshift; + + pmap = (Pixmap)w->w_backingStore; + if (pmap == (Pixmap)NULL) + { + TxPrintf("grx11ScrollBackingStore %d %d failure\n", + shift->p_x, shift->p_y); + return FALSE; + } + + width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; + height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; + xorigin = 0; + yorigin = 0; + xshift = shift->p_x; + yshift = -shift->p_y; + + if (xshift > 0) + width -= xshift; + else if (xshift < 0) + { + width += xshift; + xorigin = -xshift; + xshift = 0; + } + if (yshift > 0) + height -= yshift; + else if (yshift < 0) + { + height += yshift; + yorigin = -yshift; + yshift = 0; + } + + /* TxPrintf("grx11ScrollBackingStore %d %d\n", shift->p_x, shift->p_y); */ + + cairo_surface_t *backingStoreSurface; + backingStoreSurface = cairo_xlib_surface_create(grXdpy, pmap, DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width, height); + cairo_set_source_surface(grCairoContext, backingStoreSurface, xshift, yshift); + cairo_rectangle(grCairoContext, xshift, yshift, width, height); + cairo_set_operator(grCairoContext, CAIRO_OPERATOR_SOURCE); + cairo_fill(grCairoContext); + + return TRUE; +} + +void +grtcairoPutBackingStore(MagWindow *w, Rect *area) +{ + unsigned int width, height; + int ybot, xbot; + + if (w->w_backingStore == (ClientData)0) return; + + width = area->r_xtop - area->r_xbot; + height = area->r_ytop - area->r_ybot; + + ybot = area->r_ybot; + xbot = area->r_xbot; + + if (xbot < 0) { + width -= xbot; + xbot = 0; + } + + if (ybot < 0) { + height -= ybot; + ybot = 0; + } + + Window root_return; + int x_return, y_return; + unsigned int width_return, height_return; + unsigned int border_width_return; + unsigned int depth_return; + Pixmap pmap; + + pmap = (Pixmap)w->w_backingStore; + if (pmap == (Pixmap)NULL) + return; + XGetGeometry(grXdpy, pmap, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); + + cairo_surface_t *backingStoreSurface; + backingStoreSurface = cairo_xlib_surface_create(grXdpy, pmap, DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width, height); + cairo_t *tempContext = cairo_create(backingStoreSurface); + cairo_set_source_surface(tempContext, grCairoSurface, 0.0, 0.0); + cairo_rectangle(tempContext, xbot, ybot, width, height); + cairo_set_operator(tempContext, CAIRO_OPERATOR_SOURCE); + cairo_fill(tempContext); + + // cairo_surface_flush(backingStoreSurface); + // w->w_backingStore = (ClientData) cairo_image_surface_get_data(backingStoreSurface); + // cairo_surface_mark_dirty(backingStoreSurface); +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoReadPixel -- + * + * Read one pixel from the screen. + * + * Results: + * An integer containing the pixel's color. + * + * Side effects: + * none. + * + * ---------------------------------------------------------------------------- + */ + +int +GrTCairoReadPixel (w, x, y) +MagWindow *w; +int x, y; /* the location of a pixel in screen coords */ +{ + return 0; /* (unimplemented) */ +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoBitBlt -- + * + * Copy information in bit block transfers. + * + * Results: + * None. + * + * Side effects: + * changes the screen. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoBitBlt(r, p) +Rect *r; +Point *p; +{ + // (unimplemented) +} + +#ifdef VECTOR_FONTS + +/* + *---------------------------------------------------------------------- + * Draw a text character + * This routine is similar to grtcairoFillPolygon() + *---------------------------------------------------------------------- + */ + +void +grtcairoDrawCharacter(clist, tc, pixsize) +FontChar *clist; +unsigned char tc; +int pixsize; +{ + Point *tp; + int np, nptotal; + int i, j; + static int maxnp = 0; + FontChar *ccur; + + if (pixsize < 5) return; /* Label too small to be useful */ + + //should we be using cairo_show_glyphs?? + for (ccur = clist; ccur != NULL; ccur = ccur->fc_next) { + tp = ccur->fc_points; + np = ccur->fc_numpoints; + cairo_move_to(grCairoContext, tp[0].p_x, tp[0].p_y); + for (i = 1; i < np; i++, j += 3) { + cairo_line_to(grCairoContext, tp[0].p_x, tp[0].p_y); + } + } + cairo_fill(grCairoContext); +} + +/*--------------------------------------------------------- + * grtcairoFontText: + * + * This routine draws text from font vectors using the + * font vector routines in DBlabel.c. Text is clipped + * to the clipping rectangle. + * + * For speed, should we be transferring the font + * vectors into cairo glyphs? + * + *--------------------------------------------------------- + */ + +void +grtcairoFontText(text, font, size, rotate, pos, clip, obscure) +char *text; /* The text to be drawn */ +int font; /* Font to use from fontList */ +int size; /* Pixel size of the font */ +int rotate; /* Text rotation */ +Point *pos; /* Text base position */ +Rect *clip; /* Clipping area */ +LinkedRect *obscure; /* List of obscuring areas */ +{ + char *tptr; + Point *coffset; /* vector to next character */ + Rect *cbbox; + float fsize; + FontChar *clist; + int cheight, baseline; + float tmp; + + cairo_save(grCairoContext); + cairo_translate(grCairoContext, pos->p_x, pos->p_y); + cairo_rotate(grCairoContext, ((double)rotate) / 360 * 2 * M_PI); + + /* Get label size */ + cbbox = &DBFontList[font]->mf_extents; + + fsize = (uint8_t)size / (uint8_t)cbbox->r_ytop; + cairo_scale(grCairoContext, fsize, fsize); + + /* Adjust to baseline */ + baseline = 0; + for (tptr = text; *tptr != '\0'; tptr++) + { + DBFontChar(font, *tptr, NULL, NULL, &cbbox); + if (cbbox->r_ybot < baseline) + baseline = cbbox->r_ybot; + } + cairo_translate(grCairoContext, 0, -baseline); + + for (tptr = text; *tptr != '\0'; tptr++) + { + DBFontChar(font, *tptr, &clist, &coffset, NULL); + grtcairoDrawCharacter(clist, *tptr, size); + cairo_translate(grCairoContext, coffset->p_x, coffset->p_y); + } + cairo_restore(grCairoContext); +} + +#endif /* VECTOR_FONTS */ + +/*--------------------------------------------------------- + * grtcairoPutText: + * (modified on SunPutText) + * + * This routine puts a chunk of text on the screen in the current + * color, size, etc. The caller must ensure that it fits on + * the screen -- no clipping is done except to the obscuring rectangle + * list and the clip rectangle. + * + * Results: + * none. + * + * Side Effects: + * The text is drawn on the screen. + * + *--------------------------------------------------------- + */ + +void +grtcairoPutText (text, pos, clip, obscure) +char *text; /* The text to be drawn. */ +Point *pos; /* A point located at the leftmost point of + * the baseline for this string. + */ +Rect *clip; /* A rectangle to clip against */ +LinkedRect *obscure; /* A list of obscuring rectangles */ + +{ + Rect location; + Rect overlap; + Rect textrect; + LinkedRect *ob; + void grTCairoGeoSub(); + int i; + float tscale; + + GrTCairoTextSize(text, tcairoCurrent.fontSize, &textrect); + + location.r_xbot = pos->p_x + textrect.r_xbot; + location.r_xtop = pos->p_x + textrect.r_xtop; + location.r_ybot = pos->p_y + textrect.r_ybot; + location.r_ytop = pos->p_y + textrect.r_ytop; + + /* erase parts of the bitmap that are obscured */ + for (ob = obscure; ob != NULL; ob = ob->r_next) + { + if (GEO_TOUCH(&ob->r_r, &location)) + { + overlap = location; + GeoClip(&overlap, &ob->r_r); + grTCairoGeoSub(&location, &overlap); + } + } + + overlap = location; + GeoClip(&overlap, clip); + + /* copy the text to the color screen */ + if ((overlap.r_xbot < overlap.r_xtop) && (overlap.r_ybot <= overlap.r_ytop)) + { + cairo_rectangle(grCairoContext, overlap.r_xbot, overlap.r_ybot, overlap.r_xtop - overlap.r_xbot, overlap.r_ytop - overlap.r_ybot); + cairo_clip(grCairoContext); + cairo_move_to(grCairoContext, location.r_xbot, location.r_ybot); + cairo_show_text(grCairoContext, text); + cairo_fill(grCairoContext); + } +} + + +/* grTCairoGeoSub: + * return the tallest sub-rectangle of r not obscured by area + * area must be within r. + */ + +void +grTCairoGeoSub(r, area) +Rect *r; /* Rectangle to be subtracted from. */ +Rect *area; /* Area to be subtracted. */ + +{ + if (r->r_xbot == area->r_xbot) r->r_xbot = area->r_xtop; + else if (r->r_xtop == area->r_xtop) r->r_xtop = area->r_xbot; + else if (r->r_ybot <= area->r_ybot) r->r_ybot = area->r_ytop; + else if (r->r_ytop == area->r_ytop) r->r_ytop = area->r_ybot; + else + r->r_xtop = area->r_xbot; +} diff --git a/graphics/cairo_orig/grTCairo4.c b/graphics/cairo_orig/grTCairo4.c new file mode 100644 index 00000000..37c5e857 --- /dev/null +++ b/graphics/cairo_orig/grTCairo4.c @@ -0,0 +1,138 @@ +/* grTCairo4.c - + * + * Copyright 2017 Open Circuit Design + * + * This file contains functions to manage the graphics tablet associated + * with the X display. + * + * Written by Chuan Chen + */ + +#include +#include +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "utils/magsgtty.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "graphics/grTkCommon.h" +#include "textio/txcommands.h" +#include "grTCairoInt.h" + +extern Display *grXdpy; + + +/*--------------------------------------------------------- + * GrTCairoDisableTablet: + * Turns off the cursor. + * + * Results: None. + * + * Side Effects: None. + *--------------------------------------------------------- + */ + +void +GrTCairoDisableTablet () +{ + /* (Unimplemented) */ +} + + +/*--------------------------------------------------------- + * GrTCairoEnableTablet: + * This routine enables the graphics tablet. + * + * Results: + * None. + * + * Side Effects: + * Simply turn on the crosshair. + *--------------------------------------------------------- + */ + +void +GrTCairoEnableTablet () +{ + /* (Unimplemented) */ +} + + +/* + * ---------------------------------------------------------------------------- + * grtcairoGetCursorPos: + * Read the cursor position in magic coordinates. + * + * Results: + * TRUE is returned if the coordinates were succesfully read, FALSE + * otherwise. + * + * Side effects: + * The parameter is filled in with the cursor position, in the form of + * a point in screen coordinates. + * ---------------------------------------------------------------------------- + */ + +bool +grtcairoGetCursorPos (mw, p) + MagWindow *mw; /* window for which result is given */ + Point *p; /* point to be filled in with screen coordinates */ +{ + int x, y, x1, y1; + unsigned int buttons; + Window win1, win2; + + if (mw == (MagWindow *)NULL) mw = tcairoCurrent.mw; + + XQueryPointer(grXdpy, Tk_WindowId((Tk_Window)(mw->w_grdata)), + &win1, &win2, &x1, &y1, + &x, &y, &buttons); + + p->p_x = x; + p->p_y = grXtransY(mw, y); + + return TRUE; +} + +/* + * ---------------------------------------------------------------------------- + * grtcairoGetCursorRootPos: + * Read the cursor position in sreen root coordinates. + * + * Results: + * TRUE is returned if the coordinates were succesfully read, FALSE + * otherwise. + * + * Side effects: + * The parameter is filled in with the cursor position, in the form of + * a point in screen coordinates. + * ---------------------------------------------------------------------------- + */ + +bool +grtcairoGetCursorRootPos (mw, p) + MagWindow *mw; /* window for which result is given */ + Point *p; /* point to be filled in with screen coordinates */ +{ + int x, y, x1, y1; + unsigned int buttons; + Window win1, win2; + + if (mw == (MagWindow *)NULL) mw = tcairoCurrent.mw; + + XQueryPointer(grXdpy, Tk_WindowId((Tk_Window)(mw->w_grdata)), + &win1, &win2, &x1, &y1, + &x, &y, &buttons); + + p->p_x = x1; + p->p_y = y1; + + return TRUE; +} diff --git a/graphics/cairo_orig/grTCairo5.c b/graphics/cairo_orig/grTCairo5.c new file mode 100644 index 00000000..dc55060b --- /dev/null +++ b/graphics/cairo_orig/grTCairo5.c @@ -0,0 +1,211 @@ +/* grTCairo5.c - + * + * Copyright 2017 Open Circuit Design + * + * Manipulate the programable cursor on the graphics display. + * + * Written by Chuan Chen + */ + +#include +#include + +#include + +#include "tcltk/tclmagic.h" +#include "utils/magic.h" +#include "utils/styles.h" +#include "utils/hash.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "graphics/glyphs.h" +#include "windows/windows.h" +#include "graphics/graphics.h" +#include "graphics/graphicsInt.h" +#include "grTkCommon.h" +#include "grTCairoInt.h" + +extern Display *grXdpy; +extern int grXscrn; +extern HashTable grTCairoWindowTable; +extern cairo_t *grCairoContext; + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoDrawGlyph -- + * + * Draw one glyph on the display. + * + * Results: + * None. + * + * Side effects: + * Draws pixels. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoDrawGlyph (gl, p) +GrGlyph *gl; /* A single glyph */ +Point *p; /* screen pos of lower left corner */ +{ + Rect bBox; + bool anyObscure; + LinkedRect *ob; + + GR_CHECK_LOCK(); + + /* We're going to change the graphics state without affecting */ + /* the standard color and mask saved values, so we had better */ + /* flush all rects & lines first. */ + GR_TCAIRO_FLUSH_BATCH(); + + bBox.r_ll = *p; + bBox.r_xtop = p->p_x + gl->gr_xsize - 1; + bBox.r_ytop = p->p_y + gl->gr_ysize - 1; + + anyObscure = FALSE; + for (ob = grCurObscure; ob != NULL; ob = ob->r_next) { + if (GEO_TOUCH( &(ob->r_r), &bBox)) { + anyObscure = TRUE; + break; + } + } + if ((!anyObscure) && (GEO_SURROUND(&grCurClip, &bBox)) ) { + int *pixelp, x, y, thisp, lastp; + int color, red, green, blue, mask; + + /* no clipping, try to go quickly */ + pixelp = gl->gr_pixels; + thisp = -1; + for (y = 0; y < gl->gr_ysize; y++) { + int x1, y1; + + y1 = bBox.r_ybot + y; + for (x = 0; x < gl->gr_xsize; x++) { + lastp = thisp; + thisp = *pixelp++; + if (thisp != 0) + { + /* Note: mask has traditionally been 0-127 */ + if (thisp != lastp) { + if (lastp != -1) { + cairo_fill(grCairoContext); + //glEnd(); + } + mask = GrStyleTable[thisp].mask << 1; + color = GrStyleTable[thisp].color; + GrGetColor(color, &red, &green, &blue); + cairo_set_source_rgba(grCairoContext, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); + } + x1 = bBox.r_xbot + x; + cairo_rectangle(grCairoContext, x1, y1, 1, 1); + } + } + } + if (lastp != -1) { + cairo_fill(grCairoContext); + } + } else { + /* do pixel by pixel clipping */ + int y, yloc; + + yloc = bBox.r_ybot; + for (y = 0; y < gl->gr_ysize; y++) { + int startx, endx; + if ( (yloc <= grCurClip.r_ytop) && (yloc >= grCurClip.r_ybot) ) { + int laststartx; + laststartx = bBox.r_xbot - 1; + for (startx = bBox.r_xbot; startx <= bBox.r_xtop; + startx = endx + 1) { + int *pixelp; + + startx = MAX(startx, grCurClip.r_xbot); + endx = MIN(bBox.r_xtop, grCurClip.r_xtop); + + if (anyObscure) { + for (ob = grCurObscure; ob != NULL; ob = ob->r_next) { + if ( (ob->r_r.r_ybot <= yloc) && + (ob->r_r.r_ytop >= yloc) ) { + if (ob->r_r.r_xbot <= startx) + startx = MAX(startx, ob->r_r.r_xtop + 1); + else if (ob->r_r.r_xbot <= endx) + endx = MIN(endx, ob->r_r.r_xbot - 1); + } + } + } + + /* stop if we aren't advancing */ + if (startx == laststartx) break; + laststartx = startx; + if (startx > endx) continue; + + /* draw a section of this scan line */ + pixelp = &( gl->gr_pixels[y * gl->gr_xsize + + (startx - bBox.r_xbot)]); + for ( ; startx <= endx; startx++) { + int color, red, green, blue, mask; + if (*pixelp != 0) + { + mask = GrStyleTable[*pixelp].mask << 1; + color = GrStyleTable[*pixelp].color; + GrGetColor(color, &red, &green, &blue); + cairo_set_source_rgba(grCairoContext, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); + + cairo_rectangle(grCairoContext, startx, yloc, 1, 1); + cairo_fill(grCairoContext); + } + pixelp++; + } + startx = endx + 1; + } + } + yloc++; + } + } +} + + +/* + * ---------------------------------------------------------------------------- + * GrTCairoSetCursor: + * + * Make the cursor be a new pattern, as defined in the display styles file. + * + * Results: + * None. + * + * Side effects: + * When the cursor is turned back on it will take on the new pattern. + * ---------------------------------------------------------------------------- + */ + +void +GrTCairoSetCursor(cursorNum) +int cursorNum; /* The cursor number as defined in the display + * styles file. + */ +{ + HashEntry *entry; + HashSearch hs; + Tk_Window tkwind; + + if (cursorNum >= MAX_CURSORS) + { + TxError("No such cursor!\n"); + return; + } + + tcairoCurrent.cursor = grCursors[cursorNum]; + + HashStartSearch(&hs); + while (entry = HashNext(&grTCairoWindowTable, &hs)) + { + if (HashGetValue(entry)) + { + tkwind = (Tk_Window)entry->h_key.h_ptr; + Tk_DefineCursor(tkwind, tcairoCurrent.cursor); + } + } +} diff --git a/graphics/grMain.c b/graphics/grMain.c index 8f19d548..ad2c5b8b 100644 --- a/graphics/grMain.c +++ b/graphics/grMain.c @@ -110,6 +110,7 @@ static char *grDisplayTypes[] = { #endif #ifdef CAIRO "CAIRO", + "XR", #endif "NULL", NULL}; @@ -134,6 +135,7 @@ static bool (*(grInitProcs[]))() = { #endif #ifdef CAIRO cairoSetDisplay, + cairoSetDisplay, #endif nullSetDisplay, NULL}; diff --git a/graphics/grTCairo1.c b/graphics/grTCairo1.c index b632b984..e123b31b 100644 --- a/graphics/grTCairo1.c +++ b/graphics/grTCairo1.c @@ -47,8 +47,6 @@ uint8_t **grTCairoStipples; HashTable grTCairoWindowTable; -cairo_surface_t *grCairoSurface; -cairo_t *grCairoContext; XVisualInfo *grVisualInfo; TCAIRO_CURRENT tcairoCurrent = {(Tk_Font)0, 0, 0, 0, 0, @@ -70,9 +68,11 @@ extern void GrTCairoLock(), GrTCairoUnlock(), GrTCairoIconUpdate(); extern bool GrTCairoInit(); extern bool GrTCairoEventPending(), GrTCairoCreate(), grtcairoGetCursorPos(); extern int GrTCairoWindowId(); -extern char *GrTkWindowName(); +extern char *GrTkWindowName(); /* Use routine from grTkCommon.c */ extern void tcairoSetProjection(); + +extern int grCurColor; /*--------------------------------------------------------- * grtcairoSetWMandC: @@ -94,6 +94,7 @@ int c; /* New value for current color */ { static int oldColor = -1; static int oldMask = -1; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; int lr, lb, lg; float fr, fb, fg, aval; @@ -108,9 +109,21 @@ int c; /* New value for current color */ fr = ((float)lr / 255); fg = ((float)lg / 255); fb = ((float)lb / 255); - aval = ((float)mask / 127.0); - cairo_set_source_rgba(grCairoContext, fr, fg, fb, aval); + if (mask == 127) + { + aval = 1.0; + } + else + { + /* "Supercolor", to counter the gray background */ + fr = fr * 2 - 0.8; + fg = fg * 2 - 0.8; + fb = fb * 2 - 0.8; + aval = ((float)mask / 127.0); + } + + cairo_set_source_rgba(tcairodata->context, fr, fg, fb, aval); oldColor = c; oldMask = mask; @@ -176,8 +189,10 @@ int numstipples; /* Number of stipples */ } grTCairoStipples[k] = pdata; - stipplePatterns[k] = cairo_pattern_create_for_surface(cairo_image_surface_create_for_data(pdata, CAIRO_FORMAT_A1, 32, 32, - cairo_format_stride_for_width(CAIRO_FORMAT_A1, 32))); + stipplePatterns[k] = cairo_pattern_create_for_surface( + cairo_image_surface_create_for_data(pdata, + CAIRO_FORMAT_A1, 32, 32, + cairo_format_stride_for_width(CAIRO_FORMAT_A1, 32))); } } @@ -236,7 +251,7 @@ GrTCairoInit () { bool rstatus; - tcairoCurrent.window = Tk_MainWindow(magicinterp); // XDefaultRootWindow(grXdpy) ?? + tcairoCurrent.window = Tk_MainWindow(magicinterp); if (tcairoCurrent.window == NULL) { TxError("No Top-Level Tk window available. . . is Tk running?\n"); @@ -264,13 +279,6 @@ GrTCairoInit () grXscrn = grVisualInfo->screen; tcairoCurrent.depth = grVisualInfo->depth; - grCairoSurface = cairo_xlib_surface_create(grXdpy, tcairoCurrent.windowid, grVisualInfo->visual, Tk_Width(tcairoCurrent.window), Tk_Height(tcairoCurrent.window)); - grCairoContext = cairo_create(grCairoSurface); - - cairo_set_line_width(grCairoContext, 1.0); - cairo_set_source_rgb(grCairoContext, 0, 0, 0); - currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); - /* Use OpenGL names for colormap and dstyle file types */ grCMapType = "OpenGL"; grDStyleType = "OpenGL"; @@ -328,8 +336,6 @@ GrTCairoFlush () *--------------------------------------------------------- */ -#define grTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n)) - /* *--------------------------------------------------------- * Set the Cairo projection matrix for a window @@ -340,12 +346,31 @@ void tcairoSetProjection(llx, lly, width, height) int llx, lly, width, height; { - grCairoSurface = cairo_xlib_surface_create(grXdpy, tcairoCurrent.windowid, grVisualInfo->visual, width, height); - grCairoContext = cairo_create(grCairoSurface); + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; - cairo_identity_matrix(grCairoContext); - cairo_translate(grCairoContext, 0, height); - cairo_scale(grCairoContext, 1.0, -1.0); + /* Note that offscreen-drawing comes from the Tk Image */ + /* routines in tkCommon.c and does not have an associated */ + /* surface and context, so we need to make them. */ + + if (tcairodata == NULL) { + tcairodata = (TCairoData *)mallocMagic(sizeof(TCairoData)); + tcairodata->surface = cairo_xlib_surface_create(grXdpy, + tcairoCurrent.windowid, grVisualInfo->visual, + width, height); + tcairodata->context = cairo_create(tcairodata->surface); + tcairodata->backing_context = (ClientData)NULL; + tcairodata->backing_surface = (ClientData)NULL; + tcairoCurrent.mw->w_grdata2 = (ClientData)tcairodata; + + cairo_set_line_width(tcairodata->context, 1.0); + /* This should be pulled from STYLE_ERASEALL, not hard-coded */ + cairo_set_source_rgb(tcairodata->context, 0.8, 0.8, 0.8); + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); + } + + cairo_identity_matrix(tcairodata->context); + cairo_translate(tcairodata->context, 0, height); + cairo_scale(tcairodata->context, 1.0, -1.0); } @@ -719,6 +744,16 @@ keys_and_buttons: screenRect.r_ybot != mw->w_screenArea.r_ybot || screenRect.r_ytop != mw->w_screenArea.r_ytop); + /* Update Cairo surface */ + + if (need_resize) + { + TCairoData *tcairodata; + + tcairodata = (TCairoData *)mw->w_grdata2; + cairo_xlib_surface_set_size(tcairodata->surface, width, height); + } + /* Redraw the window */ WindReframe(mw, &screenRect, FALSE, FALSE); @@ -881,21 +916,11 @@ char *mouseFileName; grSetLineStylePtr = grtcairoSetLineStyle; grSetCharSizePtr = grtcairoSetCharSize; grFillPolygonPtr = grtcairoFillPolygon; - /* - #ifdef X11_BACKING_STORE - GrFreeBackingStorePtr = grtkFreeBackingStore; - GrCreateBackingStorePtr = grtkCreateBackingStore; - GrGetBackingStorePtr = grtkGetBackingStore; - GrPutBackingStorePtr = grtkPutBackingStore; - GrScrollBackingStorePtr = grtkScrollBackingStore; - #else - */ GrFreeBackingStorePtr = grtcairoFreeBackingStore; GrCreateBackingStorePtr = grtcairoCreateBackingStore; GrGetBackingStorePtr = grtcairoGetBackingStore; GrPutBackingStorePtr = grtcairoPutBackingStore; GrScrollBackingStorePtr = grtcairoScrollBackingStore; -//#endif if (execFailed) { TxError("Execution failed!\n"); @@ -1009,13 +1034,19 @@ char *name; if (tkwind != 0) { bool result; + TCairoData *tcairodata; GrTCairoFlush(); tcairoCurrent.window = tkwind; tcairoCurrent.mw = w; + tcairodata = (TCairoData *)mallocMagic(sizeof(TCairoData)); + tcairodata->backing_context = NULL; + tcairodata->backing_surface = NULL; + w->w_grdata = (ClientData) tkwind; + w->w_grdata2 = (ClientData) tcairodata; entry = HashFind(&grTCairoWindowTable, (char *)tkwind); HashSetValue(entry, w); @@ -1036,8 +1067,16 @@ char *name; wind = Tk_WindowId(tkwind); tcairoCurrent.windowid = wind; - grCairoSurface = cairo_xlib_surface_create(grXdpy, tcairoCurrent.windowid, grVisualInfo->visual, Tk_Width(tcairoCurrent.window), Tk_Height(tcairoCurrent.window)); - grCairoContext = cairo_create(grCairoSurface); + tcairodata->surface = cairo_xlib_surface_create(grXdpy, + tcairoCurrent.windowid, grVisualInfo->visual, + Tk_Width(tcairoCurrent.window), + Tk_Height(tcairoCurrent.window)); + tcairodata->context = cairo_create(tcairodata->surface); + + cairo_set_line_width(tcairodata->context, 1.0); + /* This should be pulled from STYLE_ERASEALL, not hard-coded */ + cairo_set_source_rgb(tcairodata->context, 0.8, 0.8, 0.8); + currentStipple = cairo_pattern_create_rgba(0, 0, 0, 1); Tk_DefineCursor(tkwind, tcairoCurrent.cursor); GrTCairoIconUpdate(w, w->w_caption); @@ -1089,11 +1128,24 @@ MagWindow *w; { Tk_Window xw; HashEntry *entry; + TCairoData *tcairodata; xw = (Tk_Window) w->w_grdata; entry = HashLookOnly(&grTCairoWindowTable, (char *)xw); HashSetValue(entry, NULL); + tcairodata = (TCairoData *)w->w_grdata2; + if (tcairodata->backing_surface != NULL) + cairo_destroy_surface(tcairodata->backing_surface); + if (tcairodata->backing_context != NULL) + cairo_destroy(tcairodata->backing_context); + if (tcairodata->surface != NULL) + cairo_destroy_surface(tcairodata->surface); + if (tcairodata->context != NULL) + cairo_destroy(tcairodata->context); + freeMagic(w->w_grdata2); + w->w_grdata2 = (ClientData)NULL; + Tcl_DeleteCommand(magicinterp, Tk_PathName(xw)); Tk_DestroyWindow(xw); } @@ -1117,12 +1169,18 @@ void GrTCairoConfigure(w) MagWindow *w; { + TCairoData *tcairodata; + int width, height; + if (w->w_flags & WIND_OFFSCREEN) return; + width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot; + height = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot; Tk_MoveResizeWindow((Tk_Window)w->w_grdata, - w->w_frameArea.r_xbot, grTransYs(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); + w->w_frameArea.r_xbot, grTransYs(w->w_frameArea.r_ytop), + width, height); + tcairodata = (TCairoData *)w->w_grdata2; + cairo_xlib_surface_set_size(tcairodata->surface, width, height); } /* @@ -1247,7 +1305,6 @@ void GrTCairoUnlock(w) MagWindow *w; { - /* GR_TCairo_FLUSH_BATCH(); */ GrTCairoFlush(); grSimpleUnlock(w); } diff --git a/graphics/grTCairo2.c b/graphics/grTCairo2.c index d1c37fd3..c63388f8 100644 --- a/graphics/grTCairo2.c +++ b/graphics/grTCairo2.c @@ -29,8 +29,6 @@ char *getenv(); extern char *DBWStyleType; extern Display *grXdpy; -extern cairo_t *grCairoContext; -extern cairo_surface_t *grCairoSurface; extern cairo_pattern_t *currentStipple; /*--------------------------------------------------------- @@ -75,15 +73,19 @@ grtcairoDrawLines(lines, nb) Rect lines[]; int nb; { + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; int i; + + cairo_save(tcairodata->context); for (i = 0; i < nb; i++) { - cairo_move_to(grCairoContext, lines[i].r_ll.p_x, lines[i].r_ll.p_y); - cairo_line_to(grCairoContext, lines[i].r_ur.p_x, lines[i].r_ur.p_y); + cairo_move_to(tcairodata->context, lines[i].r_ll.p_x, lines[i].r_ll.p_y); + cairo_line_to(tcairodata->context, lines[i].r_ur.p_x, lines[i].r_ur.p_y); } - // cairo_set_source_rgba(grCairoContext, r, g, b, a); - // cairo_set_line_width(grCairoContext, width); - cairo_stroke(grCairoContext); + // cairo_set_source_rgba(tcairodata->context, r, g, b, a); + // cairo_set_line_width(tcairodata->context, width); + cairo_stroke(tcairodata->context); + cairo_restore(tcairodata->context); } /*--------------------------------------------------------- @@ -141,17 +143,27 @@ grtcairoFillRects(rects, nb) TCairoRect rects[]; int nb; { + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; int i; + // Diagnostic + Display *disp = cairo_xlib_surface_get_display(tcairodata->surface); + Screen *screen = cairo_xlib_surface_get_screen(tcairodata->surface); + Drawable draw = cairo_xlib_surface_get_drawable(tcairodata->surface); + int w = cairo_xlib_surface_get_width(tcairodata->surface); + int h = cairo_xlib_surface_get_height(tcairodata->surface); + + cairo_save(tcairodata->context); for (i = 0; i < nb; i++) { - cairo_rectangle(grCairoContext, + cairo_rectangle(tcairodata->context, rects[i].r_ll.p_x, rects[i].r_ll.p_y, rects[i].r_ur.p_x-rects[i].r_ll.p_x, rects[i].r_ur.p_y-rects[i].r_ll.p_y); // TxPrintf("%d %d %d %d \n", rects[i].r_ll.p_x, rects[i].r_ll.p_y, rects[i].r_ur.p_x-rects[i].r_ll.p_x, rects[i].r_ur.p_y-rects[i].r_ll.p_y); } - cairo_clip(grCairoContext); - cairo_mask(grCairoContext, currentStipple); + cairo_clip(tcairodata->context); + cairo_mask(tcairodata->context, currentStipple); + cairo_restore(tcairodata->context); } /*--------------------------------------------------------- @@ -203,11 +215,14 @@ grtcairoFillPolygon(tp, np) Point *tp; int np; { + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; int i; - cairo_move_to(grCairoContext, tp[0].p_x, tp[0].p_y); + cairo_save(tcairodata->context); + cairo_move_to(tcairodata->context, tp[0].p_x, tp[0].p_y); for (i = 1; i < np; i++) - cairo_line_to(grCairoContext, tp[i].p_x, tp[i].p_y); - cairo_close_path(grCairoContext); - cairo_fill(grCairoContext); + cairo_line_to(tcairodata->context, tp[i].p_x, tp[i].p_y); + cairo_close_path(tcairodata->context); + cairo_fill(tcairodata->context); + cairo_restore(tcairodata->context); } diff --git a/graphics/grTCairo3.c b/graphics/grTCairo3.c index 57c61a44..474c44aa 100644 --- a/graphics/grTCairo3.c +++ b/graphics/grTCairo3.c @@ -33,8 +33,6 @@ #include "database/fonts.h" extern Display *grXdpy; -extern cairo_t *grCairoContext; -extern cairo_surface_t *grCairoSurface; static GC grXcopyGC = (GC)NULL; @@ -69,6 +67,7 @@ Rect *clip; /* a clipping rectangle */ int x, y; int xstart, ystart; int snum, low, hi, shifted; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; xsize = prect->r_xtop - prect->r_xbot; ysize = prect->r_ytop - prect->r_ybot; @@ -86,8 +85,8 @@ Rect *clip; /* a clipping rectangle */ for (x = xstart; x < (clip->r_xtop + 1) << SUBPIXELBITS; x += xsize) { shifted = x >> SUBPIXELBITS; - cairo_move_to(grCairoContext, shifted, low); - cairo_line_to(grCairoContext, shifted, hi); + cairo_move_to(tcairodata->context, (double)shifted, (double)low); + cairo_line_to(tcairodata->context, (double)shifted, (double)hi); snum++; } @@ -97,11 +96,11 @@ Rect *clip; /* a clipping rectangle */ for (y = ystart; y < (clip->r_ytop + 1) << SUBPIXELBITS; y += ysize) { shifted = y >> SUBPIXELBITS; - cairo_move_to(grCairoContext, low, shifted); - cairo_line_to(grCairoContext, hi, shifted); + cairo_move_to(tcairodata->context, (double)low, (double)shifted); + cairo_line_to(tcairodata->context, (double)hi, (double)shifted); snum++; } - cairo_stroke(grCairoContext); + cairo_stroke(tcairodata->context); return TRUE; } @@ -120,7 +119,8 @@ Rect *clip; /* a clipping rectangle */ bool grtcairoLoadFont() { - cairo_select_font_face(grCairoContext, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + cairo_select_font_face(tcairodata->context, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); return TRUE; } @@ -140,8 +140,9 @@ void grtcairoSetCharSize (size) int size; /* Width of characters, in pixels (6 or 8). */ { + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; tcairoCurrent.fontSize = size; - cairo_set_font_size(grCairoContext, size * 4 + 10); + cairo_set_font_size(tcairodata->context, size * 4 + 10); switch (size) { case GR_TEXT_DEFAULT: @@ -226,16 +227,24 @@ Rect *r; void grtcairoFreeBackingStore(MagWindow *window) { + TCairoData *tcairodata; Pixmap pmap = (Pixmap)window->w_backingStore; if (pmap == (Pixmap)NULL) return; XFreePixmap(grXdpy, pmap); window->w_backingStore = (ClientData)NULL; + + tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + cairo_surface_destroy(tcairodata->backing_surface); + cairo_destroy(tcairodata->backing_context); + tcairodata->backing_surface = NULL; + tcairodata->backing_context = NULL; } void grtcairoCreateBackingStore(MagWindow *w) { Pixmap pmap; + TCairoData *tcairodata; Tk_Window tkwind = (Tk_Window)w->w_grdata; Window wind; unsigned int width, height; @@ -269,45 +278,52 @@ grtcairoCreateBackingStore(MagWindow *w) pmap = XCreatePixmap(grXdpy, wind, width, height, grDepth); w->w_backingStore = (ClientData)pmap; + + tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; + + if (tcairodata->backing_surface != NULL) + { + cairo_surface_destroy(tcairodata->backing_surface); + cairo_destroy(tcairodata->backing_context); + } + tcairodata->backing_surface = cairo_xlib_surface_create(grXdpy, pmap, + DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width, height); + tcairodata->backing_context = cairo_create(tcairodata->backing_surface); + + cairo_identity_matrix(tcairodata->backing_context); } bool grtcairoGetBackingStore(MagWindow *w, Rect *area) { - unsigned int width, height; + unsigned int width, height, sheight; int xbot, ybot; Rect r; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; if (w->w_backingStore == (ClientData)0) return FALSE; GEO_EXPAND(area, 1, &r); GeoClip(&r, &(w->w_screenArea)); - width = r.r_xtop - r.r_xbot; - height = r.r_ytop - r.r_ybot; - xbot = r.r_xbot; ybot = r.r_ybot; + width = r.r_xtop - xbot; + height = r.r_ytop - ybot; + sheight = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; - Window root_return; - int x_return, y_return; - unsigned int width_return, height_return; - unsigned int border_width_return; - unsigned int depth_return; + // Fix Y orientation + ybot = sheight - height - ybot; - Pixmap pmap; - pmap = (Pixmap)w->w_backingStore; - if (pmap == (Pixmap)NULL) - return FALSE; - - XGetGeometry(grXdpy, pmap, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); - - cairo_surface_t *backingStoreSurface; - backingStoreSurface = cairo_xlib_surface_create(grXdpy, pmap, DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width_return, height_return); - cairo_set_source_surface(grCairoContext, backingStoreSurface, 0, 0); - cairo_rectangle(grCairoContext, xbot, ybot, width, height); - cairo_set_operator(grCairoContext, CAIRO_OPERATOR_SOURCE); - cairo_fill(grCairoContext); + cairo_save(tcairodata->context); + cairo_identity_matrix(tcairodata->context); + cairo_set_source_surface(tcairodata->context, tcairodata->backing_surface, + 0.0, 0.0); + cairo_rectangle(tcairodata->context, (double)xbot, (double)ybot, + (double)width, (double)height); + cairo_set_operator(tcairodata->context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->context); + cairo_restore(tcairodata->context); return TRUE; } @@ -316,7 +332,7 @@ grtcairoGetBackingStore(MagWindow *w, Rect *area) bool grtcairoScrollBackingStore(MagWindow *w, Point *shift) { - // (copied from grX11su3.c) + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; Pixmap pmap; unsigned int width, height; int xorigin, yorigin, xshift, yshift; @@ -324,7 +340,7 @@ grtcairoScrollBackingStore(MagWindow *w, Point *shift) pmap = (Pixmap)w->w_backingStore; if (pmap == (Pixmap)NULL) { - TxPrintf("grx11ScrollBackingStore %d %d failure\n", + TxPrintf("grtcairoScrollBackingStore %d %d failure\n", shift->p_x, shift->p_y); return FALSE; } @@ -336,82 +352,73 @@ grtcairoScrollBackingStore(MagWindow *w, Point *shift) xshift = shift->p_x; yshift = -shift->p_y; - if (xshift > 0) - width -= xshift; - else if (xshift < 0) - { - width += xshift; - xorigin = -xshift; - xshift = 0; - } + /* Important: Cairo does not watch where memory overlaps exist */ + /* when copying and will erase memory when yshift is positive. */ + if (yshift > 0) - height -= yshift; - else if (yshift < 0) { - height += yshift; - yorigin = -yshift; - yshift = 0; + /* Noting that the highlights will be redrawn anyway, use */ + /* the main window surface as an intermediary to copy. */ + + Rect area; + + cairo_save(tcairodata->context); + cairo_identity_matrix(tcairodata->context); + cairo_set_source_surface(tcairodata->context, + tcairodata->backing_surface, (double)xshift, (double)yshift); + cairo_rectangle(tcairodata->context, (double)xorigin, + (double)yorigin, (double)width, (double)height); + cairo_set_operator(tcairodata->context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->context); + cairo_restore(tcairodata->context); + + area.r_xbot = 0; + area.r_xtop = width; + area.r_ybot = 0; + area.r_ytop = height; + grtcairoPutBackingStore(w, &area); + } + else + { + cairo_save(tcairodata->backing_context); + cairo_set_source_surface(tcairodata->backing_context, + tcairodata->backing_surface, (double)xshift, (double)yshift); + cairo_rectangle(tcairodata->backing_context, (double)xorigin, + (double)yorigin, (double)width, (double)height); + cairo_set_operator(tcairodata->backing_context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->backing_context); + cairo_restore(tcairodata->backing_context); } - - /* TxPrintf("grx11ScrollBackingStore %d %d\n", shift->p_x, shift->p_y); */ - - cairo_surface_t *backingStoreSurface; - backingStoreSurface = cairo_xlib_surface_create(grXdpy, pmap, DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width, height); - cairo_set_source_surface(grCairoContext, backingStoreSurface, xshift, yshift); - cairo_rectangle(grCairoContext, xshift, yshift, width, height); - cairo_set_operator(grCairoContext, CAIRO_OPERATOR_SOURCE); - cairo_fill(grCairoContext); - return TRUE; } void grtcairoPutBackingStore(MagWindow *w, Rect *area) { - unsigned int width, height; + unsigned int width, height, sheight; int ybot, xbot; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; if (w->w_backingStore == (ClientData)0) return; - width = area->r_xtop - area->r_xbot; - height = area->r_ytop - area->r_ybot; - - ybot = area->r_ybot; xbot = area->r_xbot; + ybot = area->r_ybot; - if (xbot < 0) { - width -= xbot; - xbot = 0; - } + width = area->r_xtop - xbot; + height = area->r_ytop - ybot; + sheight = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; - if (ybot < 0) { - height -= ybot; - ybot = 0; - } + // Fix Y orientation + ybot = sheight - height - ybot; - Window root_return; - int x_return, y_return; - unsigned int width_return, height_return; - unsigned int border_width_return; - unsigned int depth_return; - Pixmap pmap; - - pmap = (Pixmap)w->w_backingStore; - if (pmap == (Pixmap)NULL) - return; - XGetGeometry(grXdpy, pmap, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); - - cairo_surface_t *backingStoreSurface; - backingStoreSurface = cairo_xlib_surface_create(grXdpy, pmap, DefaultVisual(grXdpy, DefaultScreen(grXdpy)), width, height); - cairo_t *tempContext = cairo_create(backingStoreSurface); - cairo_set_source_surface(tempContext, grCairoSurface, 0.0, 0.0); - cairo_rectangle(tempContext, xbot, ybot, width, height); - cairo_set_operator(tempContext, CAIRO_OPERATOR_SOURCE); - cairo_fill(tempContext); - - cairo_surface_flush(backingStoreSurface); - w->w_backingStore = (ClientData) cairo_image_surface_get_data(backingStoreSurface); - cairo_surface_mark_dirty(backingStoreSurface); + cairo_save(tcairodata->backing_context); + cairo_set_source_surface(tcairodata->backing_context, tcairodata->surface, + 0.0, 0.0); + cairo_rectangle(tcairodata->backing_context, (double)xbot, (double)ybot, + (double)width, (double)height); + cairo_set_operator(tcairodata->backing_context, CAIRO_OPERATOR_SOURCE); + cairo_fill(tcairodata->backing_context); + cairo_restore(tcairodata->backing_context); } @@ -478,9 +485,10 @@ int pixsize; { Point *tp; int np, nptotal; - int i, j; + int i; static int maxnp = 0; FontChar *ccur; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; if (pixsize < 5) return; /* Label too small to be useful */ @@ -488,12 +496,14 @@ int pixsize; for (ccur = clist; ccur != NULL; ccur = ccur->fc_next) { tp = ccur->fc_points; np = ccur->fc_numpoints; - cairo_move_to(grCairoContext, tp[0].p_x, tp[0].p_y); - for (i = 1; i < np; i++, j += 3) { - cairo_line_to(grCairoContext, tp[0].p_x, tp[0].p_y); + cairo_move_to(tcairodata->context, (double)tp[0].p_x, (double)tp[0].p_y); + for (i = 1; i < np; i++) { + cairo_line_to(tcairodata->context, (double)tp[i].p_x, + (double)tp[i].p_y); } + cairo_close_path(tcairodata->context); } - cairo_fill(grCairoContext); + cairo_fill(tcairodata->context); } /*--------------------------------------------------------- @@ -526,16 +536,18 @@ LinkedRect *obscure; /* List of obscuring areas */ FontChar *clist; int cheight, baseline; float tmp; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; - cairo_save(grCairoContext); - cairo_translate(grCairoContext, pos->p_x, pos->p_y); - cairo_rotate(grCairoContext, ((double)rotate) / 360 * 2 * M_PI); + cairo_save(tcairodata->context); + cairo_translate(tcairodata->context, (double)pos->p_x, (double)pos->p_y); + // cairo_scale(tcairodata->context, 1.0, -1.0); + cairo_rotate(tcairodata->context, ((double)rotate) / 360 * 2 * M_PI); /* Get label size */ cbbox = &DBFontList[font]->mf_extents; - fsize = (uint8_t)size / (uint8_t)cbbox->r_ytop; - cairo_scale(grCairoContext, fsize, fsize); + fsize = (float)size / (float)cbbox->r_ytop; + cairo_scale(tcairodata->context, (double)fsize, (double)fsize); /* Adjust to baseline */ baseline = 0; @@ -545,15 +557,16 @@ LinkedRect *obscure; /* List of obscuring areas */ if (cbbox->r_ybot < baseline) baseline = cbbox->r_ybot; } - cairo_translate(grCairoContext, 0, -baseline); + cairo_translate(tcairodata->context, 0.0, (double)(-baseline)); for (tptr = text; *tptr != '\0'; tptr++) { DBFontChar(font, *tptr, &clist, &coffset, NULL); grtcairoDrawCharacter(clist, *tptr, size); - cairo_translate(grCairoContext, coffset->p_x, coffset->p_y); + cairo_translate(tcairodata->context, (double)coffset->p_x, + (double)coffset->p_y); } - cairo_restore(grCairoContext); + cairo_restore(tcairodata->context); } #endif /* VECTOR_FONTS */ @@ -593,6 +606,7 @@ LinkedRect *obscure; /* A list of obscuring rectangles */ void grTCairoGeoSub(); int i; float tscale; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; GrTCairoTextSize(text, tcairoCurrent.fontSize, &textrect); @@ -615,14 +629,16 @@ LinkedRect *obscure; /* A list of obscuring rectangles */ overlap = location; GeoClip(&overlap, clip); - /* copy the text to the color screen */ if ((overlap.r_xbot < overlap.r_xtop) && (overlap.r_ybot <= overlap.r_ytop)) { - cairo_rectangle(grCairoContext, overlap.r_xbot, overlap.r_ybot, overlap.r_xtop - overlap.r_xbot, overlap.r_ytop - overlap.r_ybot); - cairo_clip(grCairoContext); - cairo_move_to(grCairoContext, location.r_xbot, location.r_ybot); - cairo_show_text(grCairoContext, text); - cairo_fill(grCairoContext); + cairo_save(tcairodata->context); + cairo_move_to(tcairodata->context, (double)location.r_xbot, + (double)location.r_ybot); + /* The cairo coordinate system is upside-down, so invert */ + cairo_scale(tcairodata->context, 1.0, -1.0); + cairo_show_text(tcairodata->context, text); + cairo_fill(tcairodata->context); + cairo_restore(tcairodata->context); } } diff --git a/graphics/grTCairo4.c b/graphics/grTCairo4.c index d290829a..10b8eba8 100644 --- a/graphics/grTCairo4.c +++ b/graphics/grTCairo4.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "tcltk/tclmagic.h" #include "utils/magic.h" diff --git a/graphics/grTCairo5.c b/graphics/grTCairo5.c index dc55060b..464b9b72 100644 --- a/graphics/grTCairo5.c +++ b/graphics/grTCairo5.c @@ -28,7 +28,6 @@ extern Display *grXdpy; extern int grXscrn; extern HashTable grTCairoWindowTable; -extern cairo_t *grCairoContext; /* @@ -53,6 +52,7 @@ Point *p; /* screen pos of lower left corner */ Rect bBox; bool anyObscure; LinkedRect *ob; + TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2; GR_CHECK_LOCK(); @@ -91,21 +91,20 @@ Point *p; /* screen pos of lower left corner */ /* Note: mask has traditionally been 0-127 */ if (thisp != lastp) { if (lastp != -1) { - cairo_fill(grCairoContext); - //glEnd(); + cairo_fill(tcairodata->context); } mask = GrStyleTable[thisp].mask << 1; color = GrStyleTable[thisp].color; GrGetColor(color, &red, &green, &blue); - cairo_set_source_rgba(grCairoContext, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); + cairo_set_source_rgba(tcairodata->context, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); } x1 = bBox.r_xbot + x; - cairo_rectangle(grCairoContext, x1, y1, 1, 1); + cairo_rectangle(tcairodata->context, x1, y1, 1, 1); } } } if (lastp != -1) { - cairo_fill(grCairoContext); + cairo_fill(tcairodata->context); } } else { /* do pixel by pixel clipping */ @@ -151,10 +150,10 @@ Point *p; /* screen pos of lower left corner */ mask = GrStyleTable[*pixelp].mask << 1; color = GrStyleTable[*pixelp].color; GrGetColor(color, &red, &green, &blue); - cairo_set_source_rgba(grCairoContext, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); + cairo_set_source_rgba(tcairodata->context, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0)); - cairo_rectangle(grCairoContext, startx, yloc, 1, 1); - cairo_fill(grCairoContext); + cairo_rectangle(tcairodata->context, startx, yloc, 1, 1); + cairo_fill(tcairodata->context); } pixelp++; } diff --git a/graphics/grTCairoInt.h b/graphics/grTCairoInt.h index 3a3a3c1a..f613ab06 100644 --- a/graphics/grTCairoInt.h +++ b/graphics/grTCairoInt.h @@ -19,6 +19,9 @@ #define TCAIRO_BATCH_SIZE 10000 +/* Inverted Y axis definition */ +#define grTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n)) + /* Current settings for X function parameters */ typedef struct { Tk_Font font; @@ -31,17 +34,22 @@ typedef struct { MagWindow *mw; } TCAIRO_CURRENT; -#ifdef Cairo_SERVER_SIDE_ONLY -typedef Rect TCairoRect; -#else +/* Per-window data held in MagWindow w->w_grdata2 */ + +typedef struct { + /* Window surface and context */ + cairo_t *context; + cairo_surface_t *surface; + /* Backing store surface and context */ + cairo_t *backing_context; + cairo_surface_t *backing_surface; +} TCairoData; /* Used for vertex arrays */ typedef struct { Point r_ll, r_ul, r_ur, r_lr; } TCairoRect; -#endif - extern TCAIRO_CURRENT tcairoCurrent; extern bool grtcairoGetCursorPos(); diff --git a/graphics/grTOGL3.c.test b/graphics/grTOGL3.c.test deleted file mode 100644 index 7358147b..00000000 --- a/graphics/grTOGL3.c.test +++ /dev/null @@ -1,812 +0,0 @@ -/* grTOGL3.c - - * - * Copyright 2003 Open Circuit Design, Inc., for MultiGiG Ltd. - * - * This file contains additional functions to manipulate an X window system - * color display. Included here are device-dependent routines to draw and - * erase text and draw a grid. - * - */ - -#include -#include - -#include -#include -#include - -#include "tcltk/tclmagic.h" -#include "utils/magic.h" -#include "utils/geometry.h" -#include "utils/malloc.h" -#include "windows/windows.h" -#include "graphics/graphics.h" -#include "graphics/graphicsInt.h" -#include "dbwind/dbwind.h" -#include "textio/textio.h" -#include "utils/signals.h" -#include "utils/utils.h" -#include "utils/hash.h" -#include "graphics/grTOGLInt.h" -#include "graphics/grTkCommon.h" -#include "database/fonts.h" - -extern Display *grXdpy; - -/* locals */ - -GLuint grXBases[4]; - - -/*--------------------------------------------------------- - * grtoglDrawGrid: - * grxDrawGrid adds a grid to the grid layer, using the current - * write mask and color. - * - * Results: - * TRUE is returned normally. However, if the grid gets too small - * to be useful, then nothing is drawn and FALSE is returned. - * - * Side Effects: None. - *--------------------------------------------------------- - */ - -bool -grtoglDrawGrid (prect, outline, clip) - Rect *prect; /* A rectangle that forms the template - * for the grid. Note: in order to maintain - * precision for the grid, the rectangle - * coordinates are specified in units of - * screen coordinates multiplied by SUBPIXEL. - */ - int outline; /* the outline style */ - Rect *clip; /* a clipping rectangle */ -{ - int xsize, ysize; - int x, y; - int xstart, ystart; - int snum, low, hi, shifted; - - xsize = prect->r_xtop - prect->r_xbot; - ysize = prect->r_ytop - prect->r_ybot; - if (!xsize || !ysize || GRID_TOO_SMALL(xsize, ysize)) - return FALSE; - - xstart = prect->r_xbot % xsize; - while (xstart < clip->r_xbot << SUBPIXELBITS) xstart += xsize; - ystart = prect->r_ybot % ysize; - while (ystart < clip->r_ybot << SUBPIXELBITS) ystart += ysize; - - grtoglSetLineStyle(outline); - - glBegin(GL_LINES); - - snum = 0; - low = clip->r_ybot; - hi = clip->r_ytop; - for (x = xstart; x < (clip->r_xtop+1) << SUBPIXELBITS; x += xsize) - { - shifted = x >> SUBPIXELBITS; - glVertex2i(shifted, low); - glVertex2i(shifted, hi); - snum++; - } - - snum = 0; - low = clip->r_xbot; - hi = clip->r_xtop; - for (y = ystart; y < (clip->r_ytop+1) << SUBPIXELBITS; y += ysize) - { - shifted = y >> SUBPIXELBITS; - glVertex2i(low, shifted); - glVertex2i(hi, shifted); - snum++; - } - glEnd(); - return TRUE; -} - - -/*--------------------------------------------------------- - * grtoglLoadFont - * This local routine transfers the X font bitmaps - * into OpenGL display lists for simple text - * rendering. - * - * Results: Success/Failure - * - * Side Effects: None. - *--------------------------------------------------------- - */ - -bool -grtoglLoadFont() -{ - Font id; - unsigned int i; - - for (i = 0; i < 4; i++) { - id = Tk_FontId(grTkFonts[i]); - - grXBases[i] = glGenLists(256); - if (grXBases[i] == 0) { - TxError("Out of display lists!\n"); - return FALSE; - } - glXUseXFont(id, 0, 256, grXBases[i]); - } - return TRUE; -} - - -/*--------------------------------------------------------- - * grtoglSetCharSize: - * This local routine sets the character size in the display, - * if necessary. - * - * Results: None. - * - * Side Effects: None. - *--------------------------------------------------------- - */ - -void -grtoglSetCharSize (size) - int size; /* Width of characters, in pixels (6 or 8). */ -{ - toglCurrent.fontSize = size; - switch (size) - { - case GR_TEXT_DEFAULT: - case GR_TEXT_SMALL: - toglCurrent.font = grSmallFont; - break; - case GR_TEXT_MEDIUM: - toglCurrent.font = grMediumFont; - break; - case GR_TEXT_LARGE: - toglCurrent.font = grLargeFont; - break; - case GR_TEXT_XLARGE: - toglCurrent.font = grXLargeFont; - break; - default: - TxError("%s%d\n", "grtoglSetCharSize: Unknown character size ", - size ); - break; - } -} - - -/* - * ---------------------------------------------------------------------------- - * GrTOGLTextSize -- - * - * Determine the size of a text string. - * - * Results: - * None. - * - * Side effects: - * A rectangle is filled in that is the size of the text in pixels. - * The origin (0, 0) of this rectangle is located on the baseline - * at the far left side of the string. - * ---------------------------------------------------------------------------- - */ - -void -GrTOGLTextSize(text, size, r) - char *text; - int size; - Rect *r; -{ - Tk_FontMetrics overall; - Tk_Font font; - int width; - - switch (size) { - case GR_TEXT_DEFAULT: - case GR_TEXT_SMALL: - font = grSmallFont; - break; - case GR_TEXT_MEDIUM: - font = grMediumFont; - break; - case GR_TEXT_LARGE: - font = grLargeFont; - break; - case GR_TEXT_XLARGE: - font = grXLargeFont; - break; - default: - TxError("%s%d\n", "GrTOGLTextSize: Unknown character size ", - size ); - break; - } - if (font == NULL) return; - Tk_GetFontMetrics(font, &overall); - width = Tk_TextWidth(font, text, strlen(text)); - /* Hack alert! Tk_TextWidth returns values too small! */ - width = width + (width >> 4); - r->r_ytop = overall.ascent; - r->r_ybot = -overall.descent; - r->r_xtop = width; - r->r_xbot = 0; -} - -/* OpenGL backing store functions (now removed from the X11-based ones) */ - -void -grtoglFreeBackingStore(MagWindow *window) -{ - if (window->w_backingStore == (ClientData)NULL) return; - freeMagic(window->w_backingStore); - window->w_backingStore = (ClientData)NULL; -} - -void -grtoglCreateBackingStore(MagWindow *w) -{ - unsigned int width, height; - - /* ignore all windows other than layout */ - if (w->w_client != DBWclientID) return; - - /* deferred */ - if (w->w_grdata == NULL) return; - - width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; - height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; - - if (w->w_backingStore != (ClientData)NULL) freeMagic(w->w_backingStore); - - w->w_backingStore = (ClientData)mallocMagic(width * height * 3); -} - -bool -grtoglGetBackingStore(MagWindow *w, Rect *area) -{ - unsigned int width, height; - int xbot, ybot; - int xoff, yoff; - Rect r; - - GEO_EXPAND(area, 1, &r); - GeoClip(&r, &(w->w_screenArea)); - - width = r.r_xtop - r.r_xbot; - height = r.r_ytop - r.r_ybot; - - xbot = r.r_xbot; - ybot = r.r_ybot; - - xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot; - yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop; - - glDrawBuffer(GL_FRONT); - glReadBuffer(GL_BACK); - glRasterPos2i((GLint)(xbot - xoff), (GLint)(ybot - yoff)); - glCopyPixels(xbot, ybot, width, height, GL_COLOR); - - return TRUE; -} - - -bool -grtoglxGetBackingStore(MagWindow *w, Rect *area) -{ - unsigned int width, height; - int ybot, y; - int xoff, yoff; - int swidth, sheight, srow; - int bpos; - Rect r; - - if ((GLvoid *)w->w_backingStore == NULL) - return FALSE; - - // Get width and height of the backing store - sheight = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; - swidth = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; - srow = swidth * 3; - - GEO_EXPAND(area, 1, &r); - GeoClip(&r, &(w->w_screenArea)); - - width = r.r_xtop - r.r_xbot; - height = r.r_ytop - r.r_ybot; - // ybot = grXtransY(w, r.r_ytop); - ybot = r.r_ybot; - - xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot; - yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop; - - bpos = ybot * srow + (3 * r.r_xbot); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glDrawBuffer(GL_FRONT); - for (y = ybot; y < ybot + height; y++) - { - // Remove next line once all math is correct. . . - if ((bpos + srow) > (srow * sheight)) break; - - glRasterPos2i((GLint)(r.r_xbot - xoff), (GLint)(y - yoff)); - glDrawPixels(width, 1, GL_RGB, GL_UNSIGNED_BYTE, - (const GLvoid *)(w->w_backingStore + bpos)); - bpos += srow; - } - - return TRUE; -} - -bool -grtoglScrollBackingStore(MagWindow *w, Point *shift) -{ - return TRUE; -} - -bool -grtoglxScrollBackingStore(MagWindow *w, Point *shift) -{ - unsigned int width, height; - int xorigin, yorigin, xshift, yshift, y, bpos, tpos, srow; - int swidth, sheight; - int memmax; - - if (w->w_backingStore == (ClientData)NULL) - return FALSE; - - swidth = width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; - sheight = height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; - srow = swidth * 3; - xorigin = 0; - yorigin = 0; - xshift = shift->p_x; - // yshift = -shift->p_y; - yshift = shift->p_y; - - if (xshift > 0) - width -= xshift; - else if (xshift < 0) - { - width += xshift; - xorigin = -xshift; - xshift = 0; - } - if (yshift > 0) - height -= yshift; - else if (yshift < 0) - { - height += yshift; - yorigin = -yshift; - yshift = 0; - } - - /* To do: shift data within the stream itself. . . */ - - /* Source stream position */ - bpos = yorigin * srow + 3 * xorigin; - /* Target stream position */ - tpos = yshift * srow + 3 * xshift; - - /* It's easier to do the whole memmove as a single block. */ - memmax = (width * height * 3) - ((tpos > bpos) ? tpos : bpos); - - - memmove((void *)(w->w_backingStore + tpos), - (void *)(w->w_backingStore + bpos), - memmax); - -// for (y = yorigin; y < yorigin + height; y++) -// { - // Remove next lines once all math is correct. . . -// if ((bpos + srow) > (srow * height)) break; -// if ((tpos + srow) > (srow * height)) break; - -// memmove((void *)(w->w_backingStore + tpos), -// (void *)(w->w_backingStore + bpos), width * 3); - -// if (y >= height) break; -// bpos += srow; -// tpos += srow; -// } - return TRUE; -} - -void -grtoglPutBackingStore(MagWindow *w, Rect *area) -{ - unsigned int width, height; - int ybot, xbot, xoff, yoff; - - width = area->r_xtop - area->r_xbot; - height = area->r_ytop - area->r_ybot; - - ybot = area->r_ybot; - xbot = area->r_xbot; - - xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot; - yoff = w->w_screenArea.r_ytop - w->w_allArea.r_ytop; - - glDrawBuffer(GL_BACK); - glReadBuffer(GL_FRONT); - glRasterPos2i((GLint)(xbot - xoff), (GLint)(ybot - yoff)); - glCopyPixels(xbot, ybot, width, height, GL_COLOR); -} - -void -grtoglxPutBackingStore(MagWindow *w, Rect *area) -{ - unsigned int width, height; - int y, ybot, xbot, xoff, yoff; - int swidth, sheight, srow; - int bpos; - - if ((GLvoid *)w->w_backingStore == NULL) return; - - if (w->w_flags & WIND_OBSCURED) - { - grtoglFreeBackingStore(w); - w->w_backingStore = (ClientData)NULL; - return; - } - - // Get width and height of the backing store area - - swidth = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot; - sheight = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot; - srow = swidth * 3; - - width = area->r_xtop - area->r_xbot; - height = area->r_ytop - area->r_ybot; - // ybot = grXtransY(w, area->r_ytop); - ybot = area->r_ybot; - xbot = area->r_xbot; - xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot; - yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop; - - if (GrPixelCorrect == 0) - { - height--; - width--; - xbot++; - } - - // OpenGL has no concept of a 2-dimensional arrangement to the - // data returned, or boundaries, so we have to enforce them. - - if (xbot < 0) - { - width += xbot; - xbot = 0; - } - if (ybot < 0) - { - height += ybot; - ybot = 0; - } - if (width > swidth) width = swidth; - - bpos = (ybot - yoff) * srow + 3 * (xbot - xoff); - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadBuffer(GL_FRONT); - for (y = ybot; y < ybot + height; y++) - { - // Remove next line once all math is correct. . . - if ((bpos + srow) > (srow * sheight)) break; - - glReadPixels(xbot, y, width, 1, - GL_RGB, GL_UNSIGNED_BYTE, - (GLvoid *)(w->w_backingStore + bpos)); - if (y >= sheight) break; - bpos += srow; - } -} - - -/* - * ---------------------------------------------------------------------------- - * GrTOGLReadPixel -- - * - * Read one pixel from the screen. - * - * Results: - * An integer containing the pixel's color. - * - * Side effects: - * none. - * - * ---------------------------------------------------------------------------- - */ - -int -GrTOGLReadPixel (w, x, y) - MagWindow *w; - int x,y; /* the location of a pixel in screen coords */ -{ - return 0; /* OpenGL has no such function, so return 0 */ -} - - -/* - * ---------------------------------------------------------------------------- - * GrTOGLBitBlt -- - * - * Copy information in bit block transfers. - * - * Results: - * None. - * - * Side effects: - * changes the screen. - * ---------------------------------------------------------------------------- - */ - -void -GrTOGLBitBlt(r, p) - Rect *r; - Point *p; -{ - glCopyPixels(r->r_xbot, r->r_ybot, r->r_xtop - r->r_xbot + 1, - r->r_ytop - r->r_ybot + 1, GL_COLOR); -} - -#ifdef VECTOR_FONTS - -/* - *---------------------------------------------------------------------- - * - * Technically, there should be no self-intersecting polygons in outline - * fonts. However, decomposition of bezier curves into line segments - * may occasionally produce one, so it needs to be handled. - *---------------------------------------------------------------------- - */ - -void -myCombine(GLdouble coords[3], GLdouble *vertex_data[4], - GLfloat weight[4], GLdouble **outData, void *dataptr) -{ - /* This needs to be free'd at the end of gluTessEndPolygon()! */ - GLdouble *new = (GLdouble *)mallocMagic(2 * sizeof(GLdouble)); - new[0] = coords[0]; - new[1] = coords[1]; - *outData = new; - /* Diagnostic */ - TxError("Intersecting polygon in char \"%c\" at %g %g!\n", - *((char *)dataptr), coords[0], coords[1]); -} - -/* - *---------------------------------------------------------------------- - * Draw a text character - * This routine differs from grtoglFillPolygon() in that it uses the - * glu library to handle non-convex polygons as may appear in font - * outlines. - *---------------------------------------------------------------------- - */ - -void -grtoglDrawCharacter(clist, tc, pixsize) - FontChar *clist; - unsigned char tc; - int pixsize; -{ - Point *tp; - int np, nptotal; - int i, j; - static GLUtesselator *tess = NULL; - static GLdouble *v = NULL; - static int maxnp = 0; - FontChar *ccur; - - if (pixsize < 5) return; /* Label too small to be useful */ - - if (tess == NULL) - { - tess = gluNewTess(); - gluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)glBegin); - gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)glVertex3dv); - gluTessCallback(tess, GLU_TESS_END, (_GLUfuncptr)glEnd); - gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)myCombine); - } - // Boundary-only does not look particularly good. . . - gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); - - nptotal = 0; - for (ccur = clist; ccur != NULL; ccur = ccur->fc_next) - nptotal += ccur->fc_numpoints; - - if (nptotal > maxnp) - { - if (v != NULL) freeMagic((char *)v); - maxnp = nptotal; - v = (GLdouble *)mallocMagic(nptotal * 3 * sizeof(GLdouble)); - } - - j = 0; - for (ccur = clist; ccur != NULL; ccur = ccur->fc_next) - { - tp = ccur->fc_points; - np = ccur->fc_numpoints; - - for (i = 0; i < np; i++, j += 3) { - v[j] = tp[i].p_x; - v[j + 1] = tp[i].p_y; - v[j + 2] = 0; - } - } - - gluTessBeginPolygon(tess, (GLvoid *)(&tc)); - j = 0; - for (ccur = clist; ccur != NULL; ccur = ccur->fc_next) - { - np = ccur->fc_numpoints; - gluTessBeginContour(tess); - for (i = 0; i < np; i++, j += 3) { - gluTessVertex(tess, &v[j], &v[j]); - } - gluTessEndContour(tess); - } - gluTessEndPolygon(tess); -} - -/*--------------------------------------------------------- - * grtoglFontText: - * - * This routine draws text from font vectors using the - * font vector routines in DBlabel.c. Text is clipped - * to the clipping rectangle. - * - * For speed, we should be transferring the font - * vectors into OpenGL display lists! - * - *--------------------------------------------------------- - */ - -void -grtoglFontText(text, font, size, rotate, pos, clip, obscure) - char *text; /* The text to be drawn */ - int font; /* Font to use from fontList */ - int size; /* Pixel size of the font */ - int rotate; /* Text rotation */ - Point *pos; /* Text base position */ - Rect *clip; /* Clipping area */ - LinkedRect *obscure; /* List of obscuring areas */ -{ - char *tptr; - Point *coffset; /* vector to next character */ - Rect *cbbox; - GLfloat fsize, matvals[16]; - FontChar *clist; - int cheight, baseline; - float tmp; - - /* Keep it simple for now---ignore clip and obscure */ - - glDisable(GL_BLEND); - glPushMatrix(); - glTranslated(pos->p_x, pos->p_y, 0); - glRotated(rotate, 0, 0, 1); - - /* Get label size */ - cbbox = &DBFontList[font]->mf_extents; - - fsize = (GLfloat)size / (GLfloat)cbbox->r_ytop; - glScalef(fsize, fsize, 1.0); - - /* Adjust to baseline */ - baseline = 0; - for (tptr = text; *tptr != '\0'; tptr++) - { - DBFontChar(font, *tptr, NULL, NULL, &cbbox); - if (cbbox->r_ybot < baseline) - baseline = cbbox->r_ybot; - } - glTranslated(0, -baseline, 0); - - for (tptr = text; *tptr != '\0'; tptr++) - { - DBFontChar(font, *tptr, &clist, &coffset, NULL); - grtoglDrawCharacter(clist, *tptr, size); - glTranslated(coffset->p_x, coffset->p_y, 0); - } - glPopMatrix(); -} - -#endif /* VECTOR_FONTS */ - -/*--------------------------------------------------------- - * grtoglPutText: - * (modified on SunPutText) - * - * This routine puts a chunk of text on the screen in the current - * color, size, etc. The caller must ensure that it fits on - * the screen -- no clipping is done except to the obscuring rectangle - * list and the clip rectangle. - * - * Results: - * none. - * - * Side Effects: - * The text is drawn on the screen. - * - *--------------------------------------------------------- - */ - -void -grtoglPutText (text, pos, clip, obscure) - char *text; /* The text to be drawn. */ - Point *pos; /* A point located at the leftmost point of - * the baseline for this string. - */ - Rect *clip; /* A rectangle to clip against */ - LinkedRect *obscure; /* A list of obscuring rectangles */ - -{ - Rect location; - Rect overlap; - Rect textrect; - LinkedRect *ob; - void grTOGLGeoSub(); - int i; - float tscale; - - GrTOGLTextSize(text, toglCurrent.fontSize, &textrect); - - location.r_xbot = pos->p_x + textrect.r_xbot; - location.r_xtop = pos->p_x + textrect.r_xtop; - location.r_ybot = pos->p_y + textrect.r_ybot; - location.r_ytop = pos->p_y + textrect.r_ytop; - - /* erase parts of the bitmap that are obscured */ - for (ob = obscure; ob != NULL; ob = ob->r_next) - { - if (GEO_TOUCH(&ob->r_r, &location)) - { - overlap = location; - GeoClip(&overlap, &ob->r_r); - grTOGLGeoSub(&location, &overlap); - } - } - - overlap = location; - GeoClip(&overlap, clip); - - /* copy the text to the color screen */ - if ((overlap.r_xbot < overlap.r_xtop)&&(overlap.r_ybot <= overlap.r_ytop)) - { - glScissor(overlap.r_xbot, overlap.r_ybot, overlap.r_xtop - overlap.r_xbot, - overlap.r_ytop - overlap.r_ybot); - glEnable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glRasterPos2i(pos->p_x, pos->p_y); - glListBase(grXBases[(toglCurrent.fontSize == GR_TEXT_DEFAULT) ? - GR_TEXT_SMALL : toglCurrent.fontSize]); - glCallLists(strlen(text), GL_UNSIGNED_BYTE, (unsigned char *)text); - glDisable(GL_SCISSOR_TEST); - } -} - - -/* grTOGLGeoSub: - * return the tallest sub-rectangle of r not obscured by area - * area must be within r. - */ - -void -grTOGLGeoSub(r, area) -Rect *r; /* Rectangle to be subtracted from. */ -Rect *area; /* Area to be subtracted. */ - -{ - if (r->r_xbot == area->r_xbot) r->r_xbot = area->r_xtop; - else - if (r->r_xtop == area->r_xtop) r->r_xtop = area->r_xbot; - else - if (r->r_ybot <= area->r_ybot) r->r_ybot = area->r_ytop; - else - if (r->r_ytop == area->r_ytop) r->r_ytop = area->r_ybot; - else - r->r_xtop = area->r_xbot; -} diff --git a/graphics/grTkCommon.c b/graphics/grTkCommon.c index f8ef1787..b88ffec1 100644 --- a/graphics/grTkCommon.c +++ b/graphics/grTkCommon.c @@ -1100,6 +1100,7 @@ ImgLayerConfigureInstance(instancePtr) tmpmw.w_flags = WIND_OFFSCREEN; tmpmw.w_grdata = (ClientData)instancePtr->pixmap; + tmpmw.w_grdata2 = (ClientData)NULL; tmpmw.w_allArea = r; tmpmw.w_clipAgainst = NULL; diff --git a/windows/windMove.c b/windows/windMove.c index 063a64f7..0f91b5f4 100644 --- a/windows/windMove.c +++ b/windows/windMove.c @@ -287,6 +287,7 @@ WindCreate(client, frameArea, isHint, argc, argv) w->w_stippleOrigin.p_y = 0; w->w_bbox = NULL; w->w_grdata = (ClientData) NULL; + w->w_grdata2 = (ClientData) NULL; w->w_backingStore = (ClientData)NULL; w->w_redrawAreas = (ClientData) NULL; w->w_iconname = NULL; diff --git a/windows/windows.h b/windows/windows.h index 5332fcd1..36f766a5 100644 --- a/windows/windows.h +++ b/windows/windows.h @@ -183,8 +183,13 @@ typedef struct WIND_S1 { * Set at window creation time. */ ClientData w_grdata; /* Data private to the graphics package. (G) - * Often used to contain variables needed to - * interface to SUNs window package. + * Generally references an X11 or Tk window. + */ + ClientData w_grdata2; /* Data private to the graphics packsge. (G) + * Used to contain per-window information + * other than the window itself, since + * various parts of the code have w_grdata + * hard-coded to the window pointer. */ ClientData w_backingStore; /* Specific data private to the graphics * package. Used to save and restore the