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