1 /* grTOGL1.c
2 *
3 * Copyright (C) 2003 Open Circuit Design, Inc., for MultiGiG Ltd.
4 *
5 * This file contains primitive functions for OpenGL running under
6 * an X window system in a Tcl/Tk interpreter environment
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <signal.h>
17
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #include <X11/keysym.h>
21
22 #include <GL/gl.h>
23 #include <GL/glx.h>
24
25 #include "tcltk/tclmagic.h"
26 #include "utils/main.h"
27 #include "utils/magic.h"
28 #include "utils/malloc.h"
29 #include "utils/magsgtty.h"
30 #include "utils/geometry.h"
31 #include "windows/windows.h"
32 #include "graphics/graphics.h"
33 #include "graphics/graphicsInt.h"
34 #include "textio/textio.h"
35 #include "textio/txcommands.h"
36 #include "utils/signals.h"
37 #include "utils/utils.h"
38 #include "tiles/tile.h"
39 #include "utils/hash.h"
40 #include "database/database.h"
41 #include "drc/drc.h"
42 #include "utils/macros.h"
43 #include "graphics/grTOGLInt.h"
44 #include "utils/paths.h"
45 #include "graphics/grTkCommon.h"
46
47 GLubyte **grTOGLStipples;
48 HashTable grTOGLWindowTable;
49 GLXContext grXcontext;
50 XVisualInfo *grVisualInfo;
51
52 TOGL_CURRENT toglCurrent= {(Tk_Font)0, 0, 0, 0, 0,
53 (Tk_Window)0, (Window)0, (MagWindow *)NULL};
54
55 /* This is kind of a long story, and very kludgy, but the following
56 * things need to be defined as externals because of the way lint
57 * libraries are made by taking this module and changing all procedures
58 * names "Xxxx" to "Grxxx". The change is only done at the declaration
59 * of the procedure, so we need these declarations to handle uses
60 * of those names, which don't get modified. Check out the Makefile
61 * for details on this.
62 */
63 extern void GrTOGLClose(), GrTOGLFlush();
64 extern void GrTOGLDelete(), GrTOGLConfigure(), GrTOGLRaise(), GrTOGLLower();
65 extern void GrTOGLLock(), GrTOGLUnlock(), GrTOGLIconUpdate();
66 extern bool GrTOGLInit();
67 extern bool GrTOGLEventPending(), GrTOGLCreate(), grtoglGetCursorPos();
68 extern int GrTOGLWindowId();
69 extern char *GrTkWindowName();
70
71 extern void toglSetProjection();
72
73
74 /*---------------------------------------------------------
75 * grtoglSetWMandC:
76 * This is a local routine that resets the value of the current
77 * write alpha (mask) and color, if necessary.
78 *
79 * Results: None.
80 *
81 * Side Effects: None.
82 *
83 * Errors: None.
84 *---------------------------------------------------------
85 */
86
87 void
grtoglSetWMandC(mask,c)88 grtoglSetWMandC (mask, c)
89 int mask; /* New value for write mask */
90 int c; /* New value for current color */
91 {
92 static int oldColor = -1;
93 static int oldMask = -1;
94
95 int lr, lb, lg;
96 GLfloat fr, fb, fg;
97 GLfloat aval; /* Alpha default value was 0.75 */
98
99 if (mask == -65) mask = 127; /* All planes */
100 if (mask == oldMask && c == oldColor) return;
101
102 GR_TOGL_FLUSH_BATCH();
103
104 GrGetColor(c, &lr, &lb, &lg);
105
106 fr = ((GLfloat)lr / 255);
107 fg = ((GLfloat)lg / 255);
108 fb = ((GLfloat)lb / 255);
109
110 if (mask == 127)
111 {
112 glDisable(GL_BLEND);
113 aval = 1.0;
114 }
115 else
116 {
117 /* Calculate a "supercolor", outside of the normal color range, */
118 /* but which results in the desired color after a blend with */
119 /* the background color. */
120
121 fr = fr * 2 - 0.8;
122 fg = fg * 2 - 0.8;
123 fb = fb * 2 - 0.8;
124
125 aval = (GLfloat)mask / 127.0; /* mask translates to alpha in */
126 /* the OpenGL version. */
127
128 glEnable(GL_BLEND);
129 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
130 }
131 glColor4f(fr, fb, fg, aval);
132
133 oldColor = c;
134 oldMask = mask;
135 }
136
137
138 /*---------------------------------------------------------
139 * grtoglSetLineStyle:
140 * This local routine sets the current line style.
141 *
142 * Results: None.
143 *
144 * Side Effects:
145 * A new line style is output to the display.
146 *
147 *---------------------------------------------------------
148 */
149
150 void
grtoglSetLineStyle(style)151 grtoglSetLineStyle (style)
152 int style; /* New stipple pattern for lines. */
153 {
154 static int oldStyle = -1;
155 GLushort glstyle;
156
157 style &= 0xFF;
158 if (style == oldStyle) return;
159 oldStyle = style;
160 GR_TOGL_FLUSH_BATCH();
161
162 switch (style) {
163 case 0xFF:
164 case 0x00:
165 glDisable(GL_LINE_STIPPLE);
166 break;
167 default:
168 glstyle = style | (style << 8);
169 glEnable(GL_LINE_STIPPLE);
170 glLineStipple(1, glstyle);
171 break;
172 }
173 }
174
175
176 /*---------------------------------------------------------
177 * grtoglSetSPattern:
178 * toglSetSPattern associates a stipple pattern with a given
179 * stipple number. This is a local routine called from
180 * grStyle.c .
181 *
182 * Results: None.
183 *
184 * Side Effects: None.
185 *---------------------------------------------------------
186 */
187
188 void
grtoglSetSPattern(sttable,numstipples)189 grtoglSetSPattern (sttable, numstipples)
190 int **sttable; /* The table of patterns */
191 int numstipples; /* Number of stipples */
192 {
193 int i, j, k, n;
194 GLubyte *pdata;
195
196 grTOGLStipples = (GLubyte **)mallocMagic(numstipples * sizeof(GLubyte *));
197 for (k = 0; k < numstipples; k++)
198 {
199 pdata = (GLubyte *)mallocMagic(128 * sizeof(GLubyte));
200 n = 0;
201
202 /* expand magic's default 8x8 stipple to OpenGL's 32x32 */
203
204 for (i = 0; i < 32; i++)
205 for (j = 0; j < 4; j++)
206 pdata[n++] = (GLubyte)sttable[k][i % 8];
207
208 grTOGLStipples[k] = pdata;
209 }
210 }
211
212
213 /*---------------------------------------------------------
214 * grtoglSetStipple:
215 * This routine sets the Xs current stipple number.
216 *
217 * Results: None.
218 *
219 * Side Effects:
220 * The current clipmask in the X is set to stipple,
221 * if it wasn't that already.
222 *---------------------------------------------------------
223 */
224
225 void
grtoglSetStipple(stipple)226 grtoglSetStipple (stipple)
227 int stipple; /* The stipple number to be used. */
228 {
229 static int oldStip = -1;
230 if (stipple == oldStip) return;
231 oldStip = stipple;
232 GR_TOGL_FLUSH_BATCH();
233 if (stipple == 0 || stipple > grNumStipples) {
234 glDisable(GL_POLYGON_STIPPLE);
235 } else {
236 if (grTOGLStipples[stipple] == (GLubyte *)NULL) MainExit(1);
237 glEnable(GL_POLYGON_STIPPLE);
238 glPolygonStipple(grTOGLStipples[stipple]);
239 }
240 }
241
242
243 /*------------------------------------------------------------------------
244 * GrTOGLInit:
245 * GrTOGLInit initializes the graphics display and clears its screen.
246 * Files must have been previously opened with GrSetDisplay();
247 *
248 * Results: TRUE if successful.
249 *
250 * Notes: When 3D rendering is compiled in, we search for a double-buffered
251 * configuration first, because it generates the smoothest graphics,
252 * and fall back on a single-buffered configuration if necessary.
253 * For normal, 2D-only rendering, we look for a single-buffered
254 * configuration first because we don't use the back buffer, so a
255 * double-buffered configuration just wastes space.
256 *------------------------------------------------------------------------
257 */
258
259 bool
GrTOGLInit()260 GrTOGLInit ()
261 {
262 bool rstatus;
263 #ifdef THREE_D
264 static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
265 #else
266 static int attributeList[] = { GLX_RGBA, None, None };
267 #endif
268
269 if (Tk_InitStubs(magicinterp, "8.5", 0) == NULL) return FALSE;
270
271 toglCurrent.window = Tk_MainWindow(magicinterp);
272 if (toglCurrent.window == NULL)
273 {
274 TxError("No Top-Level Tk window available. . . is Tk running?\n");
275 return FALSE;
276 }
277
278 toglCurrent.windowid = Tk_WindowId(toglCurrent.window);
279 grXdpy = Tk_Display(toglCurrent.window);
280 toglCurrent.depth = Tk_Depth(toglCurrent.window);
281
282 grXscrn = DefaultScreen(grXdpy);
283
284 grVisualInfo = glXChooseVisual(grXdpy, grXscrn, attributeList);
285
286 if (!grVisualInfo)
287 {
288 /* Try for a double-buffered configuration */
289 #ifdef THREE_D
290 attributeList[1] = None;
291 #else
292 attributeList[1] = GLX_DOUBLEBUFFER;
293 #endif
294 grVisualInfo = glXChooseVisual(grXdpy, grXscrn, attributeList);
295 if (!grVisualInfo)
296 {
297 TxError("No suitable visual!\n");
298 return FALSE;
299 }
300 }
301 grXscrn = grVisualInfo->screen;
302 toglCurrent.depth = grVisualInfo->depth;
303
304 /* glXCreateContext() 4th argument: */
305 /* TRUE = Direct rendering, FALSE = Indirect rendering */
306
307 /* Direct rendering may not be able to deal with pixmaps. */
308 /* Normally, magic should compile with OpenGL framebuffer */
309 /* backing store and pbuffer offscreen rendering. However, */
310 /* if X11_BACKING_STORE is selected then force indirect */
311 /* rendering. This can be avoided if the backing store */
312 /* functions sync between OpenGL and X11; this has not */
313 /* been done yet. */
314
315 /* The CAIRO_OFFSCREEN_RENDER compile-time option uses */
316 /* Cairo to do the off-screen rendering, which allows */
317 /* OpenGL to run in direct-rendering mode only. To do: */
318 /* determine from OpenGL attributes if indirect rendering */
319 /* is allowed, and handle automatically. */
320
321 #ifdef X11_BACKING_STORE
322 grXcontext = glXCreateContext(grXdpy, grVisualInfo, NULL, GL_FALSE);
323 #else
324 grXcontext = glXCreateContext(grXdpy, grVisualInfo, NULL, GL_TRUE);
325 #endif
326
327 /* Basic GL parameters */
328
329 glLineWidth(1.0);
330 glShadeModel (GL_FLAT);
331 glPixelStorei(GL_PACK_LSB_FIRST, TRUE);
332
333 /* OpenGL sets its own names for colormap and dstyle file types */
334 grCMapType = "OpenGL";
335 grDStyleType = "OpenGL";
336
337 /* Globally-accessed variables */
338 grNumBitPlanes = toglCurrent.depth;
339 grBitPlaneMask = (1 << toglCurrent.depth) - 1;
340
341 HashInit(&grTOGLWindowTable,8,HT_WORDKEYS);
342
343 return grTkLoadFont();
344 }
345
346 /*---------------------------------------------------------
347 * GrTOGLClose:
348 *
349 * Results: None.
350 *
351 * Side Effects:
352 *---------------------------------------------------------
353 */
354
355 void
GrTOGLClose()356 GrTOGLClose ()
357 {
358 if (grXdpy == NULL) return;
359 if (grVisualInfo != NULL) XFree(grVisualInfo);
360
361 grTkFreeFonts();
362
363 /* Pop down Tk window but let Tcl/Tk */
364 /* do XCloseDisplay() */
365 }
366
367
368 /*---------------------------------------------------------
369 * GrTOGLFlush:
370 * Flush output to display.
371 *
372 * Flushing is done automatically the next time input is read,
373 * so this procedure should not be used very often.
374 *
375 * Results: None.
376 *
377 * Side Effects: None.
378 *---------------------------------------------------------
379 */
380
381 void
GrTOGLFlush()382 GrTOGLFlush ()
383 {
384 GR_TOGL_FLUSH_BATCH();
385 glFlush();
386 }
387
388 /*
389 *---------------------------------------------------------
390 */
391
392 static GLXPbuffer pbuffer = None;
393
394 #define glTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n))
395
396 /*
397 *---------------------------------------------------------
398 * Set the OpenGL viewport (projection matrix) for a window
399 *---------------------------------------------------------
400 */
401
402 void
toglSetProjection(llx,lly,width,height)403 toglSetProjection(llx, lly, width, height)
404 int llx, lly, width, height;
405 {
406 if (toglCurrent.mw->w_flags & WIND_OFFSCREEN)
407 {
408 int count = 0;
409 int PBattrib[] = {
410 GLX_PBUFFER_WIDTH, width,
411 GLX_PBUFFER_HEIGHT, height,
412 GLX_LARGEST_PBUFFER, False,
413 None
414 };
415 GLXFBConfig *config;
416
417 if (pbuffer != None) glXDestroyPbuffer(grXdpy, pbuffer);
418 config = glXGetFBConfigs(grXdpy, grXscrn, &count);
419 if (config != NULL && count != 0)
420 {
421 pbuffer = glXCreatePbuffer(grXdpy, config[0], PBattrib);
422 glXMakeCurrent(grXdpy, (GLXDrawable)pbuffer, grXcontext);
423 }
424 if (config != NULL) XFree(config);
425 }
426 else
427 glXMakeCurrent(grXdpy, (GLXDrawable)toglCurrent.windowid, grXcontext);
428
429 #ifndef OGL_SERVER_SIDE_ONLY
430 /* For batch-processing lines and rectangles */
431 glEnableClientState(GL_VERTEX_ARRAY);
432 #endif
433
434 /* Because this tends to result in thick lines, it has been moved */
435 /* the line drawing routine so it can be enabled for individual */
436 /* lines. */
437 /* glEnable(GL_LINE_SMOOTH); */
438
439 /* Force draw to front buffer (in case of double-buffered config) */
440 glDrawBuffer(GL_FRONT);
441
442 glMatrixMode(GL_PROJECTION);
443 glLoadIdentity();
444
445 glViewport((GLsizei)llx, (GLsizei)lly, (GLsizei) width, (GLsizei) height);
446
447 /* scale to fit window */
448
449 #ifdef OGL_INVERT_Y
450 glScalef(1.0 / (float)(width >> 1), -1.0 / (float)(height >> 1), 1.0);
451 #else
452 glScalef(1.0 / (float)(width >> 1), 1.0 / (float)(height >> 1), 1.0);
453 #endif
454
455 /* magic origin maps to window center; move to window origin */
456
457 glTranslated(-(GLsizei)(width >> 1), -(GLsizei)(height >> 1), 0);
458
459 if (toglCurrent.mw->w_flags & WIND_OFFSCREEN)
460 glTranslatef((float)0.5, (float)0.5, 0);
461
462 /* Remaining transformations are done on the modelview matrix */
463
464 glMatrixMode(GL_MODELVIEW);
465 glLoadIdentity();
466 }
467
468
469 /*
470 * ---------------------------------------------------------------------------
471 *
472 * TOGLEventProc ---
473 *
474 * Tk Event Handler
475 *
476 * Results:
477 * None.
478 *
479 * Side Effects:
480 * Calls functions in response to X11 events.
481 *
482 * ---------------------------------------------------------------------------
483 */
484
485 void
TOGLEventProc(clientData,xevent)486 TOGLEventProc(clientData, xevent)
487 ClientData clientData;
488 XEvent *xevent;
489 {
490 TxInputEvent *event;
491 HashEntry *entry;
492 Tk_Window tkwind = (Tk_Window)clientData;
493 Window wind;
494 MagWindow *mw;
495 unsigned char LocRedirect = TxInputRedirect;
496
497 XKeyPressedEvent *KeyPressedEvent = (XKeyPressedEvent *) xevent;
498 KeySym keysym;
499 int nbytes;
500
501 /* Keys and Buttons: Determine expansion of macros or redirect
502 * keys to the terminal or console.
503 */
504
505 switch (xevent->type)
506 {
507 case ButtonPress:
508 {
509 XButtonEvent *ButtonEvent = (XButtonEvent *) xevent;
510 int txbutton;
511
512 switch (ButtonEvent->button) {
513 case Button1:
514 txbutton = TX_LEFT_BUTTON;
515 keysym = XK_Pointer_Button1;
516 break;
517 case Button2:
518 txbutton = TX_MIDDLE_BUTTON;
519 keysym = XK_Pointer_Button2;
520 break;
521 case Button3:
522 txbutton = TX_RIGHT_BUTTON;
523 keysym = XK_Pointer_Button3;
524 break;
525 case Button4:
526 txbutton = TX_BUTTON_4;
527 keysym = XK_Pointer_Button4;
528 break;
529 case Button5:
530 txbutton = TX_BUTTON_5;
531 keysym = XK_Pointer_Button5;
532 break;
533 }
534 nbytes = 0;
535
536 entry = HashLookOnly(&grTOGLWindowTable, (char *)tkwind);
537 mw = (entry)?(MagWindow *)HashGetValue(entry):0;
538
539 if (mw && (mw->w_flags & WIND_SCROLLBARS))
540 if (WindButtonInFrame(mw, ButtonEvent->x,
541 grXtransY(mw, ButtonEvent->y),
542 txbutton))
543 break;
544
545 goto keys_and_buttons;
546 }
547 break;
548 case KeyPress:
549 {
550 int keywstate, keymod, idx, idxmax;
551 char inChar[10];
552 Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
553
554 nbytes = XLookupString(KeyPressedEvent, inChar, sizeof(inChar),
555 &keysym, NULL);
556
557 if (IsModifierKey(keysym)) break; /* Don't handle modifiers */
558
559 entry = HashLookOnly(&grTOGLWindowTable, (char *)tkwind);
560 mw = (entry)?(MagWindow *)HashGetValue(entry):0;
561
562 keys_and_buttons:
563
564 keymod = (LockMask | ControlMask | ShiftMask)
565 & KeyPressedEvent->state;
566 #ifdef __APPLE__
567 if (KeyPressedEvent->state & (Mod1Mask | Mod2Mask |
568 Mod3Mask | Mod4Mask | Mod5Mask))
569 keymod |= Mod1Mask;
570 #else
571 keymod |= (Mod1Mask & KeyPressedEvent->state);
572 #endif
573
574 if (nbytes == 0) /* No ASCII equivalent */
575 {
576 keywstate = (keymod << 16) | (keysym & 0xffff);
577 }
578 else if (!strncmp(XKeysymToString(keysym), "KP_", 3))
579 {
580 /* keypad key (special case---would like to */
581 /* differentiate between shift-KP-# and # itself) */
582 keymod &= ~ShiftMask;
583 keywstate = (keymod << 16) | (keysym & 0xffff);
584 nbytes = 0;
585 }
586 else /* ASCII-valued character */
587 {
588 if (!(keymod & (LockMask | Mod1Mask))) {
589 if (!(keymod & ControlMask))
590 keymod &= ~ShiftMask;
591 else if (!(keymod & ShiftMask))
592 keymod &= ~ControlMask;
593 }
594 }
595
596 idxmax = (nbytes == 0) ? 1 : nbytes;
597 for (idx = 0; idx < idxmax; idx++)
598 {
599 if (inChar[idx] == 3) /* Ctrl-C interrupt */
600 {
601 if (SigInterruptPending)
602 MainExit(0); /* double Ctrl-C */
603 else
604 sigOnInterrupt(0); /* Set InterruptPending */
605 break;
606 }
607 else if (nbytes > 0)
608 {
609 if ((keymod & ControlMask) && (inChar[idx] < 32))
610 inChar[idx] += 'A' - 1;
611
612 keywstate = (keymod << 16) | ((int)inChar[idx] & 0xff);
613 }
614
615 /* Allow buttons to bypass the console and be */
616 /* treated as macros. */
617
618 if (LocRedirect == TX_INPUT_REDIRECTED)
619 {
620 switch (keysym)
621 {
622 case XK_Pointer_Button1:
623 case XK_Pointer_Button2:
624 case XK_Pointer_Button3:
625 case XK_Pointer_Button4:
626 case XK_Pointer_Button5:
627 LocRedirect = TX_INPUT_NORMAL;;
628 break;
629 }
630 }
631
632 if ((LocRedirect == TX_INPUT_REDIRECTED) && TxTkConsole)
633 {
634 Tcl_SavedResult state;
635 static char outstr[] = "::tkcon::Insert .text \"x\" ";
636
637 switch (keysym)
638 {
639 case XK_Return:
640 TxSetPoint(KeyPressedEvent->x,
641 grXtransY(mw, KeyPressedEvent->y),
642 mw->w_wid);
643 TxInputRedirect = TX_INPUT_PROCESSING;
644 Tcl_EvalEx(consoleinterp, "::tkcon::Eval .text",
645 19, 0);
646 TxInputRedirect = TX_INPUT_NORMAL;
647 TxSetPrompt('%');
648
649 Tcl_SaveResult(magicinterp, &state);
650 Tcl_EvalEx(magicinterp, "history event 0", 15, 0);
651 MacroDefine(mw->w_client, (int)'.',
652 Tcl_GetStringResult(magicinterp), NULL,
653 FALSE);
654 Tcl_RestoreResult(magicinterp, &state);
655 break;
656 case XK_Up:
657 Tcl_EvalEx(consoleinterp, "::tkcon::Event -1",
658 17, 0);
659 break;
660 case XK_Down:
661 Tcl_EvalEx(consoleinterp, "::tkcon::Event 1",
662 16, 0);
663 break;
664 case XK_Left:
665 Tcl_EvalEx(consoleinterp, ".text mark set insert "
666 "insert-1c ; .text see insert", 50, 0);
667 break;
668 case XK_Right:
669 Tcl_EvalEx(consoleinterp, ".text mark set insert "
670 "insert+1c ; .text see insert", 50, 0);
671 break;
672 case XK_BackSpace: case XK_Delete:
673 Tcl_EvalEx(consoleinterp, ".text delete insert-1c ;"
674 ".text see insert", 40, 0);
675 break;
676 case XK_quotedbl: case XK_backslash: case XK_bracketleft:
677 outstr[23] = '\\';
678 outstr[24] = inChar[idx];
679 outstr[25] = '\"';
680 Tcl_EvalEx(consoleinterp, outstr, 26, 0);
681 outstr[24] = '\"';
682 outstr[25] = '\0';
683 default:
684 outstr[23] = inChar[idx];
685 Tcl_EvalEx(consoleinterp, outstr, 25, 0);
686 break;
687 }
688 }
689 else if (LocRedirect == TX_INPUT_REDIRECTED) {
690 int tl;
691 if (TxBuffer == NULL)
692 {
693 TxBuffer = Tcl_Alloc(2);
694 *TxBuffer = '\0';
695 tl = 0;
696 }
697 else
698 {
699 tl = strlen(TxBuffer);
700 TxBuffer = Tcl_Realloc(TxBuffer, tl + 2);
701 }
702 if (keysym == XK_BackSpace || keysym == XK_Delete)
703 {
704 if (tl >= 0)
705 {
706 if (tl > 0)
707 {
708 *(TxBuffer + tl - 1) = '\0';
709 TxPrintf("\b");
710 }
711 TxPrintf(" \b");
712 TxFlushOut();
713 }
714 }
715 else if (keysym == XK_Return)
716 {
717 *(TxBuffer + tl) = '\n';
718 *(TxBuffer + tl + 1) = '\0';
719 if (tl != 0) MacroDefine(mw->w_client,
720 XK_period, TxBuffer, NULL, FALSE);
721 TxInputRedirect = TX_INPUT_NORMAL;
722 TxSetPoint(KeyPressedEvent->x,
723 grXtransY(mw, KeyPressedEvent->y),
724 mw->w_wid);
725 TxPrintf("\n");
726 TxFlushOut();
727 Tcl_NotifyChannel(Tcl_GetStdChannel(TCL_STDIN),
728 TCL_READABLE);
729 }
730 else
731 {
732 *(TxBuffer + tl) = *(inChar + idx);
733 *(TxBuffer + tl + 1) = '\0';
734 TxPrintf("%c", *(inChar + idx));
735 TxFlushOut();
736 }
737 }
738 else
739 {
740 bool iMacro;
741 char *macroDef;
742
743 macroDef = MacroRetrieve(mw->w_client, keywstate, &iMacro);
744
745 /* Special handling: An imacro beginning with ':' */
746 /* sets the prompt to ':' and moves to the next char. */
747
748 if (macroDef != NULL && *macroDef == ':' && iMacro)
749 {
750 if (TxTkConsole)
751 TxSetPrompt(':');
752 else
753 {
754 TxPrintf("\b\b: ");
755 TxFlushOut();
756 }
757 memmove(macroDef, macroDef + 1, strlen(macroDef + 1) + 1);
758 }
759
760 macroDef = MacroSubstitute(macroDef, "%W", Tk_PathName(tkwind));
761
762 if (macroDef == NULL)
763 {
764 if (keysym != XK_Return)
765 {
766 char *vis = MacroName(keywstate);
767 TxError("Unknown macro or short command: '%s'\n", vis);
768
769 freeMagic(vis);
770 }
771 /* Print Carriage Return & Put back Tcl/Tk prompt */
772 TxParseString("", NULL, NULL);
773 }
774 else
775 {
776 int sl = strlen(macroDef);
777
778 if (iMacro)
779 {
780 /* Echo macro to interpreter, then redirect keys */
781
782 if (TxTkConsole)
783 {
784 char *outstring = Tcl_Alloc(sl + 20);
785 sprintf(outstring, ".text insert end \"%s\"",
786 macroDef);
787 Tcl_EvalEx(consoleinterp, outstring, -1, 0);
788 Tcl_Free(outstring);
789 }
790 else
791 {
792 TxBuffer = Tcl_Alloc(sl + 1);
793 strcpy(TxBuffer, macroDef);
794 TxPrintf("%s", macroDef);
795 TxFlushOut();
796 }
797 TxInputRedirect = TX_INPUT_REDIRECTED;
798 }
799 else
800 {
801 /* TxParseString is defined by tcltk/tclmagic.c
802 * and calls Tcl_Eval()
803 */
804
805 TxSetPoint(KeyPressedEvent->x,
806 grXtransY(mw, KeyPressedEvent->y),
807 mw->w_wid);
808 TxParseString(macroDef, NULL, NULL);
809 }
810 freeMagic(macroDef);
811 }
812 }
813 }
814 }
815 break;
816 case ConfigureNotify:
817 {
818 XConfigureEvent *ConfigureEvent = (XConfigureEvent*) xevent;
819 Rect screenRect;
820 int width, height;
821 bool result, need_resize;
822
823 width = ConfigureEvent->width;
824 height = ConfigureEvent->height;
825
826 entry = HashLookOnly(&grTOGLWindowTable, (char *)tkwind);
827 mw = (entry)?(MagWindow *)HashGetValue(entry):0;
828
829 screenRect.r_xbot = ConfigureEvent->x;
830 screenRect.r_xtop = ConfigureEvent->x + width;
831 screenRect.r_ytop = glTransYs(ConfigureEvent->y);
832 screenRect.r_ybot = glTransYs(ConfigureEvent->y + height);
833
834 need_resize = (screenRect.r_xbot != mw->w_screenArea.r_xbot ||
835 screenRect.r_xtop != mw->w_screenArea.r_xtop ||
836 screenRect.r_ybot != mw->w_screenArea.r_ybot ||
837 screenRect.r_ytop != mw->w_screenArea.r_ytop);
838
839 /* Redraw the window */
840
841 WindReframe(mw, &screenRect, FALSE, FALSE);
842 WindRedisplay(mw);
843 if (need_resize) (*GrCreateBackingStorePtr)(mw);
844 }
845 break;
846 case VisibilityNotify:
847 {
848 XVisibilityEvent *VisEvent = (XVisibilityEvent*) xevent;
849
850 entry = HashLookOnly(&grTOGLWindowTable, (char *)tkwind);
851 mw = (entry)?(MagWindow *)HashGetValue(entry):0;
852
853 switch(VisEvent->state)
854 {
855 case VisibilityUnobscured:
856 mw->w_flags &= ~WIND_OBSCURED;
857 if (mw->w_backingStore == (ClientData)NULL)
858 {
859 (*GrCreateBackingStorePtr)(mw);
860 if (mw->w_backingStore != (ClientData)NULL)
861 {
862 WindAreaChanged(mw, &mw->w_allArea);
863 WindUpdate();
864 }
865 }
866 break;
867 case VisibilityPartiallyObscured:
868 case VisibilityFullyObscured:
869 mw->w_flags |= WIND_OBSCURED;
870 break;
871 }
872 }
873 break;
874 case Expose:
875 {
876 XExposeEvent *ExposeEvent = (XExposeEvent*) xevent;
877 Rect screenRect;
878
879 entry = HashLookOnly(&grTOGLWindowTable, (char *)tkwind);
880 mw = (entry)?(MagWindow *)HashGetValue(entry):0;
881
882 screenRect.r_xbot = ExposeEvent->x;
883 screenRect.r_xtop = ExposeEvent->x+ExposeEvent->width;
884 screenRect.r_ytop = mw->w_allArea.r_ytop-ExposeEvent->y;
885 screenRect.r_ybot = mw->w_allArea.r_ytop -
886 (ExposeEvent->y + ExposeEvent->height);
887
888 if (mw->w_backingStore != (ClientData)NULL)
889 {
890 Rect surface;
891 (*GrLockPtr)(mw, FALSE);
892 (*GrGetBackingStorePtr)(mw, &screenRect);
893 (*GrUnlockPtr)(mw);
894 WindScreenToSurface(mw, &screenRect, &surface);
895 DBWHLRedrawPrepWindow(mw, &surface);
896 WindDrawBorder(mw, &screenRect);
897 }
898 else
899 WindAreaChanged(mw, &screenRect);
900 WindUpdate();
901 }
902 break;
903
904 case MapNotify:
905 case UnmapNotify:
906 case DestroyNotify: /* Do nothing */
907 break;
908
909 default:
910 TxError("Tk Event: Unknown (%d)\n", xevent->type);
911 TxFlush();
912 break;
913 }
914 }
915
916
917
918 /* Set for on-screen display */
919
920 void
toglOnScreen()921 toglOnScreen()
922 {
923 GrSetCMapPtr = GrTOGLSetCMap;
924 GrFlushPtr = GrTOGLFlush;
925
926 grSetSPatternPtr = grtoglSetSPattern;
927 grDrawLinePtr = grtoglDrawLine;
928 grSetWMandCPtr = grtoglSetWMandC;
929 grFillRectPtr = grtoglFillRect;
930 grSetStipplePtr = grtoglSetStipple;
931 grSetLineStylePtr = grtoglSetLineStyle;
932 grFillPolygonPtr = grtoglFillPolygon;
933 }
934
935 /*---------------------------------------------------------
936 * oglSetDisplay:
937 * This routine sets the appropriate parameters so that
938 * Magic will work with the X display.
939 *
940 * Under Xlib, all input events (mouse and keyboard) are
941 * sent to one queue which has to be polled to discover
942 * whether there is any input or not. To fit the Magic
943 * interrupt-driven input model, a helper process is
944 * spawned which reads and blocks on the event queue,
945 * sending SIGIO's to Magic when it detects input. The
946 * input read in the helper process is then sent to Magic
947 * via a communication pipe.
948 *
949 * Results: success / fail
950 *
951 * Side Effects: Sets up the pipe.
952 *---------------------------------------------------------
953 */
954
955 bool
oglSetDisplay(dispType,outFileName,mouseFileName)956 oglSetDisplay (dispType, outFileName, mouseFileName)
957 char *dispType;
958 char *outFileName;
959 char *mouseFileName;
960 {
961 char *planecount;
962 char *fullname;
963 FILE* f;
964 bool execFailed = FALSE;
965 int x, y, width, height;
966
967 WindPackageType = WIND_X_WINDOWS; /* to be changed? */
968 TxInputRedirect = TX_INPUT_NORMAL;
969
970 grCursorType = "color";
971 WindScrollBarWidth = 14;
972
973 /* Set up the procedure values in the indirection table. */
974
975 GrPixelCorrect = 0;
976
977 GrLockPtr = GrTOGLLock;
978 GrUnlockPtr = GrTOGLUnlock;
979 GrInitPtr = GrTOGLInit;
980 GrClosePtr = GrTOGLClose;
981 GrSetCMapPtr = GrTOGLSetCMap;
982
983 GrEnableTabletPtr = GrTOGLEnableTablet;
984 GrDisableTabletPtr = GrTOGLDisableTablet;
985 GrSetCursorPtr = GrTOGLSetCursor;
986 GrTextSizePtr = GrTOGLTextSize;
987 GrDrawGlyphPtr = GrTOGLDrawGlyph;
988 GrReadPixelPtr = GrTOGLReadPixel;
989 GrFlushPtr = GrTOGLFlush;
990
991 GrCreateWindowPtr = GrTOGLCreate;
992 GrDeleteWindowPtr = GrTOGLDelete;
993 GrConfigureWindowPtr = GrTOGLConfigure;
994 GrOverWindowPtr = GrTOGLRaise;
995 GrUnderWindowPtr = GrTOGLLower;
996 GrUpdateIconPtr = GrTOGLIconUpdate;
997 GrEventPendingPtr = GrTOGLEventPending;
998 GrWindowIdPtr = GrTOGLWindowId;
999 GrWindowNamePtr = GrTkWindowName; /* from grTkCommon.c */
1000 GrGetCursorPosPtr = grtoglGetCursorPos;
1001 GrGetCursorRootPosPtr = grtoglGetCursorRootPos;
1002
1003 /* local indirections */
1004 grSetSPatternPtr = grtoglSetSPattern;
1005 grPutTextPtr = grtoglPutText;
1006 #ifdef VECTOR_FONTS
1007 grFontTextPtr = grtoglFontText;
1008 #endif
1009 grDefineCursorPtr = grTkDefineCursor;
1010 grFreeCursorPtr = grTkFreeCursors;
1011 GrBitBltPtr = GrTOGLBitBlt;
1012 grDrawGridPtr = grtoglDrawGrid;
1013 grDrawLinePtr = grtoglDrawLine;
1014 grSetWMandCPtr = grtoglSetWMandC;
1015 grFillRectPtr = grtoglFillRect;
1016 grSetStipplePtr = grtoglSetStipple;
1017 grSetLineStylePtr = grtoglSetLineStyle;
1018 grSetCharSizePtr = grtoglSetCharSize;
1019 grFillPolygonPtr = grtoglFillPolygon;
1020
1021 #ifdef X11_BACKING_STORE
1022 GrFreeBackingStorePtr = grtkFreeBackingStore;
1023 GrCreateBackingStorePtr = grtkCreateBackingStore;
1024 GrGetBackingStorePtr = grtkGetBackingStore;
1025 GrPutBackingStorePtr = grtkPutBackingStore;
1026 GrScrollBackingStorePtr = grtkScrollBackingStore;
1027 #else
1028 GrFreeBackingStorePtr = grtoglFreeBackingStore;
1029 GrCreateBackingStorePtr = grtoglCreateBackingStore;
1030 GrGetBackingStorePtr = grtoglGetBackingStore;
1031 GrPutBackingStorePtr = grtoglPutBackingStore;
1032 GrScrollBackingStorePtr = grtoglScrollBackingStore;
1033 #endif
1034
1035 if (execFailed) {
1036 TxError("Execution failed!\n");
1037 return FALSE;
1038 }
1039
1040 if(!GrTOGLInit()){
1041 return FALSE;
1042 };
1043
1044 Tk_GetVRootGeometry(Tk_MainWindow(magicinterp), &x, &y, &width, &height);
1045 GrScreenRect.r_xbot = x;
1046 GrScreenRect.r_ybot = y;
1047 GrScreenRect.r_xtop = width + x;
1048 GrScreenRect.r_ytop = height + y;
1049
1050 return Tk_MainWindow(magicinterp) ? TRUE : FALSE;
1051 }
1052
1053 extern void MakeWindowCommand();
1054
1055 /*
1056 * ----------------------------------------------------------------------------
1057 *
1058 * GrTOGLCreate --
1059 * Create a new window under the X window system.
1060 * Bind X window to Magic Window w.
1061 *
1062 * Results:
1063 * Success/Fail
1064 *
1065 * Side Effects:
1066 * Window created, window ID send to Xhelper.
1067 *
1068 * ----------------------------------------------------------------------------
1069 */
1070
1071 bool
GrTOGLCreate(w,name)1072 GrTOGLCreate(w, name)
1073 MagWindow *w;
1074 char *name;
1075 {
1076 Tk_Window tkwind, tktop;
1077 Window wind;
1078 static int WindowNumber = 0;
1079 HashEntry *entry;
1080 char *windowplace;
1081 char windowname[10];
1082 int x = w->w_frameArea.r_xbot;
1083 int y = glTransYs(w->w_frameArea.r_ytop);
1084 int width = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot;
1085 int height = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot;
1086 unsigned long attribmask = CWBackPixel | CWBorderPixel | CWColormap;
1087 XSetWindowAttributes grAttributes;
1088
1089 WindSeparateRedisplay(w);
1090
1091 sprintf(windowname, ".magic%d", WindowNumber + 1);
1092 if (windowplace = XGetDefault(grXdpy, "magic", windowname))
1093 {
1094 XParseGeometry(windowplace,&x,&y,
1095 (unsigned int *)&width,(unsigned int *)&height);
1096 w->w_frameArea.r_xbot = x;
1097 w->w_frameArea.r_xtop = x+width;
1098 w->w_frameArea.r_ytop = glTransYs(y);
1099 w->w_frameArea.r_ybot = glTransYs(y+height);
1100 WindReframe(w,&(w->w_frameArea),FALSE,FALSE);
1101 }
1102
1103 grAttributes.colormap = XCreateColormap(grXdpy, RootWindow(grXdpy, grXscrn),
1104 grVisualInfo->visual, AllocNone);
1105 grAttributes.background_pixel = WhitePixel(grXdpy,grXscrn);
1106 grAttributes.border_pixel = BlackPixel(grXdpy,grXscrn);
1107
1108 if (tktop = Tk_MainWindow(magicinterp))
1109 {
1110 if (!WindowNumber)
1111 {
1112 /* To do: deal with grVisualInfo---destroy and recreate top */
1113 /* frame if necessary */
1114
1115 if (Tk_WindowId(tktop) == 0)
1116 {
1117 Tk_SetWindowVisual(tktop, grVisualInfo->visual,
1118 toglCurrent.depth, grAttributes.colormap);
1119 }
1120 else
1121 {
1122 /* The Top-level window has already been mapped. We can't mess */
1123 /* with it's visual. If the title is "wish", we'll assume that */
1124 /* nobody else is claiming it, and unmap it. */
1125
1126 if (!strcmp(Tk_Name(tktop), "wish")) Tk_UnmapWindow(tktop);
1127 }
1128 }
1129 }
1130 else
1131 return 0; /* failure */
1132
1133 /* Last parameter "" indicates a top-level window in the space of */
1134 /* the parent. */
1135
1136 if (name == NULL)
1137 tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, windowname, "");
1138 else
1139 tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, name, NULL);
1140
1141 /* TxError("Creating window named \"%s\", tkwind = 0x%x\n",
1142 windowname, tkwind); TxFlush(); */
1143
1144 if (tkwind != 0)
1145 {
1146 bool result;
1147
1148 GrTOGLFlush();
1149
1150 toglCurrent.window = tkwind;
1151 toglCurrent.mw = w;
1152
1153 w->w_grdata = (ClientData) tkwind;
1154
1155 entry = HashFind(&grTOGLWindowTable, (char *)tkwind);
1156 HashSetValue(entry,w);
1157
1158 /* ensure that the visual is what we wanted, if possible to change */
1159
1160 Tk_SetWindowVisual(tkwind, grVisualInfo->visual, toglCurrent.depth,
1161 grAttributes.colormap);
1162
1163 /* map the window, if necessary */
1164
1165 Tk_MapWindow(tkwind);
1166
1167 /* use x, y, width, height to size and position the window */
1168
1169 Tk_GeometryRequest(tkwind, width, height);
1170 /* Tk_MoveResizeWindow(tkwind, x, y, width, height); */
1171
1172 wind = Tk_WindowId(tkwind);
1173 toglCurrent.windowid = wind;
1174 glXMakeCurrent(grXdpy, (GLXDrawable)wind, grXcontext);
1175
1176 Tk_DefineCursor(tkwind, toglCurrent.cursor);
1177 GrTOGLIconUpdate(w, w->w_caption);
1178
1179 WindowNumber++;
1180
1181 /* execute all Tk events up to current */
1182
1183 while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0);
1184
1185 /* set up Tk event handler to start processing */
1186
1187 Tk_CreateEventHandler(tkwind, ExposureMask | StructureNotifyMask
1188 | ButtonPressMask | KeyPressMask | VisibilityChangeMask,
1189 (Tk_EventProc *)TOGLEventProc, (ClientData) tkwind);
1190
1191 /* set up commands to be passed expressly to this window */
1192
1193 MakeWindowCommand((name == NULL) ? windowname : name, w);
1194
1195 return (WindowNumber == 1) ? grtoglLoadFont() : 1;
1196 }
1197 else
1198 {
1199 TxError("Could not open new Tk window\n");
1200 }
1201
1202 return 0;
1203 }
1204
1205 /*
1206 * ----------------------------------------------------------------------------
1207 *
1208 * GrTOGLDelete --
1209 * Destroy a Tk/OpenGL window.
1210 *
1211 * Results:
1212 * None.
1213 *
1214 * Side Effects:
1215 * Window destroyed.
1216 *
1217 * ----------------------------------------------------------------------------
1218 */
1219
1220 void
GrTOGLDelete(w)1221 GrTOGLDelete(w)
1222 MagWindow *w;
1223 {
1224 Tk_Window xw;
1225 HashEntry *entry;
1226
1227 xw = (Tk_Window) w->w_grdata;
1228 entry = HashLookOnly(&grTOGLWindowTable, (char *)xw);
1229 HashSetValue(entry,NULL);
1230
1231 Tcl_DeleteCommand(magicinterp, Tk_PathName(xw));
1232 Tk_DestroyWindow(xw);
1233 }
1234
1235 /*
1236 * ----------------------------------------------------------------------------
1237 *
1238 * GrTOGLConfigure --
1239 * Resize/ Move an existing X window.
1240 *
1241 * Results:
1242 * None.
1243 *
1244 * Side Effects:
1245 * Window reconfigured to w->w_frameArea.
1246 *
1247 * ----------------------------------------------------------------------------
1248 */
1249
1250 void
GrTOGLConfigure(w)1251 GrTOGLConfigure(w)
1252 MagWindow *w;
1253 {
1254 if (w->w_flags & WIND_OFFSCREEN) return;
1255
1256 Tk_MoveResizeWindow((Tk_Window)w->w_grdata,
1257 w->w_frameArea.r_xbot, glTransYs(w->w_frameArea.r_ytop),
1258 w->w_frameArea.r_xtop - w->w_frameArea.r_xbot,
1259 w->w_frameArea.r_ytop - w->w_frameArea.r_ybot);
1260 }
1261
1262 /*
1263 * ----------------------------------------------------------------------------
1264 *
1265 * GrTOGLRaise --
1266 * Raise a window to the top of the screen such that nothing
1267 * obscures it.
1268 *
1269 * Results:
1270 * None.
1271 *
1272 * Side Effects:
1273 * Window raised.
1274 *
1275 * ----------------------------------------------------------------------------
1276 */
1277
1278 void
GrTOGLRaise(w)1279 GrTOGLRaise(w)
1280 MagWindow *w;
1281 {
1282 Tk_Window tkwind;
1283
1284 if (w->w_flags & WIND_OFFSCREEN) return;
1285
1286 tkwind = (Tk_Window)w->w_grdata;
1287 Tk_RestackWindow(tkwind, Above, NULL);
1288 }
1289
1290 /*
1291 * ----------------------------------------------------------------------------
1292 *
1293 * GrTOGLLower --
1294 * Lower a window below all other Tk windows.
1295 * obscures it.
1296 *
1297 * Results:
1298 * None.
1299 *
1300 * Side Effects:
1301 * Window lowered.
1302 *
1303 * ----------------------------------------------------------------------------
1304 */
1305
1306 void
GrTOGLLower(w)1307 GrTOGLLower(w)
1308 MagWindow *w;
1309 {
1310 Tk_Window tkwind;
1311
1312 if (w->w_flags & WIND_OFFSCREEN) return;
1313
1314 tkwind = (Tk_Window)w->w_grdata;
1315 Tk_RestackWindow(tkwind, Below, NULL);
1316 }
1317
1318
1319 /*
1320 * ----------------------------------------------------------------------------
1321 *
1322 * GrTOGLLock --
1323 * Lock a window and set global variables "toglCurrent.window"
1324 * and "toglCurrent.mw" to reference the locked window.
1325 *
1326 * Results:
1327 * None.
1328 *
1329 * Side Effects:
1330 * Window locked.
1331 *
1332 * ----------------------------------------------------------------------------
1333 */
1334
1335 #ifdef CAIRO_OFFSCREEN_RENDER
1336 extern void GrTCairoLock();
1337 extern void TCairoOffScreen();
1338 #endif
1339
1340 void
GrTOGLLock(w,flag)1341 GrTOGLLock(w, flag)
1342 MagWindow *w;
1343 bool flag;
1344 {
1345 Window wind;
1346
1347 #ifdef CAIRO_OFFSCREEN_RENDER
1348 /* Use Cairo graphics for off-screen rendering */
1349
1350 if ((w != GR_LOCK_SCREEN) && (w->w_flags & WIND_OFFSCREEN))
1351 {
1352 GrTCairoLock(w, flag);
1353 TCairoOffScreen();
1354 return;
1355 }
1356 #endif
1357
1358 grSimpleLock(w, flag);
1359 if ( w != GR_LOCK_SCREEN )
1360 {
1361 toglCurrent.mw = w;
1362
1363 if (w->w_flags & WIND_OFFSCREEN)
1364 {
1365 toglCurrent.window = (Tk_Window) NULL;
1366 toglCurrent.windowid = (Pixmap) w->w_grdata;
1367 }
1368 else
1369 {
1370 toglCurrent.window = (Tk_Window) w->w_grdata;
1371 toglCurrent.windowid = Tk_WindowId(toglCurrent.window);
1372 }
1373
1374 toglSetProjection(w->w_allArea.r_xbot, w->w_allArea.r_ybot,
1375 w->w_allArea.r_xtop - w->w_allArea.r_xbot,
1376 w->w_allArea.r_ytop - w->w_allArea.r_ybot);
1377 }
1378 }
1379
1380 /*
1381 * ----------------------------------------------------------------------------
1382 *
1383 * GrTOGLUnlock --
1384 * Unlock a window, flushing stuff out to the display.
1385 *
1386 * Results:
1387 * None.
1388 *
1389 * Side Effects:
1390 * Window unlocked.
1391 * Display update.
1392 *
1393 * ----------------------------------------------------------------------------
1394 */
1395
1396 void
GrTOGLUnlock(w)1397 GrTOGLUnlock(w)
1398 MagWindow *w;
1399 {
1400
1401 #ifdef CAIRO_OFFSCREEN_RENDER
1402 /* Use Cairo graphics for off-screen rendering */
1403
1404 if ((w != GR_LOCK_SCREEN) && (w->w_flags & WIND_OFFSCREEN))
1405 {
1406 GrTCairoUnlock(w);
1407 toglOnScreen();
1408 return;
1409 }
1410 #endif
1411
1412 GrTOGLFlush();
1413
1414 if ((w != GR_LOCK_SCREEN) && (w->w_flags & WIND_OFFSCREEN))
1415 {
1416 GC grXcopyGC;
1417 XGCValues gcValues;
1418 unsigned char *pdata, *tdata;
1419 int i, j;
1420
1421 Window root_return;
1422 int x_return, y_return;
1423 unsigned int pbwidth, pbheight, wborder, depth;
1424
1425 XGetGeometry(grXdpy, (Drawable)toglCurrent.windowid, &root_return,
1426 &x_return, &y_return, &pbwidth, &pbheight, &wborder, &depth);
1427
1428 pdata = (unsigned char *)mallocMagic((pbwidth * pbheight * 3)
1429 * sizeof(unsigned int));
1430
1431 /* In offscreen-rendering mode, copy Pbuffer back to window */
1432 glReadBuffer(GL_FRONT);
1433 glReadPixels(0, 0, pbwidth, pbheight, GL_RGB, GL_UNSIGNED_BYTE, pdata);
1434
1435 gcValues.graphics_exposures = FALSE;
1436 grXcopyGC = XCreateGC(grXdpy, (Drawable)toglCurrent.windowid,
1437 GCGraphicsExposures, &gcValues);
1438
1439 /* This is very slow, but the only way I've found to copy data */
1440 /* from a Pbuffer into a Pixmap. It is only used to make the */
1441 /* icon images for the toolbar, so it does not need to be */
1442 /* efficient. */
1443
1444 tdata = pdata;
1445 for (i = 0; i < pbwidth; i++) {
1446 for (j = 0; j < pbheight; j++)
1447 {
1448 unsigned long pcolor;
1449 pcolor = *tdata++;
1450 pcolor <<= 8;
1451 pcolor |= *tdata++;
1452 pcolor <<= 8;
1453 pcolor |= *tdata++;
1454 XSetForeground(grXdpy, grXcopyGC, pcolor);
1455 XDrawPoint(grXdpy, (Drawable)toglCurrent.windowid, grXcopyGC,
1456 pbwidth - i - 1, j);
1457 }
1458 }
1459
1460 freeMagic(pdata);
1461 XFreeGC(grXdpy, grXcopyGC);
1462 }
1463 grSimpleUnlock(w);
1464 }
1465
1466
1467
1468 /*
1469 *-------------------------------------------------------------------------
1470 * GrTOGLEventPending --
1471 * check for pending graphics events.
1472 * Here we use the X11 check for window events, because Tcl/Tk doesn't
1473 * allows peeking into its event queue without executing whatever is
1474 * in the queue.
1475 *
1476 * Results:
1477 * TRUE if an event is waiting in the event queue.
1478 *
1479 * Side effects:
1480 * None, hopefully (put back the event!)
1481 *
1482 *-------------------------------------------------------------------------
1483 */
1484
1485 bool
GrTOGLEventPending()1486 GrTOGLEventPending()
1487 {
1488 Window wind = toglCurrent.windowid;
1489 XEvent genEvent;
1490 bool retval;
1491
1492 XSync(grXdpy, FALSE); /* Necessary, or it won't catch mouse/key events */
1493 retval = XCheckWindowEvent(grXdpy, wind, ExposureMask
1494 | StructureNotifyMask | ButtonPressMask
1495 | KeyPressMask, &genEvent);
1496 if (retval) XPutBackEvent(grXdpy, &genEvent);
1497 return retval;
1498 }
1499
1500 /*
1501 *-------------------------------------------------------------------------
1502 *
1503 * GrTOGLIconUpdate -- updates the icon text with the window script
1504 *
1505 * Results: none
1506 *
1507 * Side Effects: changes the icon text
1508 *
1509 *-------------------------------------------------------------------------
1510 */
1511
1512 void
GrTOGLIconUpdate(w,text)1513 GrTOGLIconUpdate(w,text) /* See Blt code */
1514 MagWindow *w;
1515 char *text;
1516 {
1517 Tk_Window tkwind;
1518 Window wind;
1519 XClassHint class;
1520 char *brack;
1521
1522 if (w->w_flags & WIND_OFFSCREEN) return;
1523
1524 tkwind = (Tk_Window)(w->w_grdata);
1525 if (tkwind == NULL) {
1526 tkwind = Tk_MainWindow(magicinterp);
1527 if (tkwind == NULL) return;
1528 }
1529 wind = Tk_WindowId(tkwind);
1530 if (wind == 0) return;
1531
1532 class.res_name = "magic";
1533 class.res_class = "magic";
1534
1535 XSetClassHint( grXdpy, wind, &class);
1536 if (text)
1537 {
1538 if (brack = strchr(text,'['))
1539 {
1540 brack--;
1541 *brack = 0;
1542 XSetIconName(grXdpy,wind,text);
1543 XStoreName(grXdpy,wind,text);
1544 *brack = ' ';
1545 return;
1546 }
1547 if (brack = strrchr(text,' ')) text = brack+1;
1548 XSetIconName(grXdpy,wind,text);
1549 XStoreName(grXdpy,wind,text);
1550 }
1551 }
1552
1553 /*
1554 *-------------------------------------------------------------------------
1555 * GrTOGLWindowId --
1556 * Get magic's ID number from the indicated MagWindow structure
1557 *
1558 * Results:
1559 * The window ID number.
1560 *
1561 * Side effects:
1562 * None.
1563 *
1564 *-------------------------------------------------------------------------
1565 */
1566
1567 int
GrTOGLWindowId(tkname)1568 GrTOGLWindowId(tkname)
1569 char *tkname;
1570 {
1571 Tk_Window tkwind;
1572 MagWindow *mw;
1573 HashEntry *entry;
1574 int id = 0;
1575
1576 tkwind = Tk_NameToWindow(magicinterp, tkname, Tk_MainWindow(magicinterp));
1577 if (tkwind != NULL)
1578 {
1579 entry = HashLookOnly(&grTOGLWindowTable, (char *)tkwind);
1580 mw = (entry) ? (MagWindow *)HashGetValue(entry) : 0;
1581 if (mw) id = mw->w_wid;
1582 }
1583 return id;
1584 }
1585