int Tk_Grab( Tcl_Interp *interp, /* Used for error reporting. */ Tk_Window tkwin, /* Window on whose behalf the pointer is to be * grabbed. */ int grabGlobal) /* Non-zero means issue a grab to the server * so that no other application gets mouse or * keyboard events. Zero means the grab only * applies within this application. */ { int grabResult, numTries; TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; TkWindow *winPtr2; unsigned int serial; ReleaseButtonGrab(dispPtr); if (dispPtr->eventualGrabWinPtr != NULL) { if ((dispPtr->eventualGrabWinPtr == winPtr) && (grabGlobal == ((dispPtr->grabFlags & GRAB_GLOBAL) != 0))) { return TCL_OK; } if (dispPtr->eventualGrabWinPtr->mainPtr != winPtr->mainPtr) { alreadyGrabbed: Tcl_SetResult(interp, "grab failed: another application has grab", TCL_STATIC); return TCL_ERROR; } Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr); } Tk_MakeWindowExist(tkwin); #ifndef MAC_OSX_TK if (!grabGlobal) #else if (0) #endif { Window dummy1, dummy2; int dummy3, dummy4, dummy5, dummy6; unsigned int state; /* * Local grab. However, if any mouse buttons are down, turn it into a * global grab temporarily, until the last button goes up. This does * two things: (a) it makes sure that we see the button-up event; and * (b) it allows us to track mouse motion among all of the windows of * this application. */ dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL); XQueryPointer(dispPtr->display, winPtr->window, &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &state); if ((state & ALL_BUTTONS) != 0) { dispPtr->grabFlags |= GRAB_TEMP_GLOBAL; goto setGlobalGrab; } } else { dispPtr->grabFlags |= GRAB_GLOBAL; setGlobalGrab: /* * Tricky point: must ungrab before grabbing. This is needed in case * there is a button auto-grab already in effect. If there is, and the * mouse has moved to a different window, X won't generate enter and * leave events to move the mouse if we grab without ungrabbing. */ XUngrabPointer(dispPtr->display, CurrentTime); serial = NextRequest(dispPtr->display); /* * Another tricky point: there are races with some window managers * that can cause grabs to fail because the window manager hasn't * released its grab quickly enough. To work around this problem, * retry a few times after AlreadyGrabbed errors to give the grab * release enough time to register with the server. */ grabResult = 0; /* Needed only to prevent gcc compiler * warnings. */ for (numTries = 0; numTries < 10; numTries++) { grabResult = XGrabPointer(dispPtr->display, winPtr->window, True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask |PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); if (grabResult != AlreadyGrabbed) { break; } Tcl_Sleep(100); } if (grabResult != 0) { grabError: if (grabResult == GrabNotViewable) { Tcl_SetResult(interp, "grab failed: window not viewable", TCL_STATIC); } else if (grabResult == AlreadyGrabbed) { goto alreadyGrabbed; } else if (grabResult == GrabFrozen) { Tcl_SetResult(interp, "grab failed: keyboard or pointer frozen", TCL_STATIC); } else if (grabResult == GrabInvalidTime) { Tcl_SetResult(interp, "grab failed: invalid time", TCL_STATIC); } else { char msg[64 + TCL_INTEGER_SPACE]; sprintf(msg, "grab failed for unknown reason (code %d)", grabResult); Tcl_AppendResult(interp, msg, NULL); } return TCL_ERROR; } grabResult = XGrabKeyboard(dispPtr->display, Tk_WindowId(tkwin), False, GrabModeAsync, GrabModeAsync, CurrentTime); if (grabResult != 0) { XUngrabPointer(dispPtr->display, CurrentTime); goto grabError; } /* * Eat up any grab-related events generated by the server for the * grab. There are several reasons for doing this: * * 1. We have to synthesize the events for local grabs anyway, since * the server doesn't participate in them. * 2. The server doesn't always generate the right events for global * grabs (e.g. it generates events even if the current window is in * the grab tree, which we don't want). * 3. We want all the grab-related events to be processed immediately * (before other events that are already queued); events coming * from the server will be in the wrong place, but events we * synthesize here will go to the front of the queue. */ EatGrabEvents(dispPtr, serial); } /* * Synthesize leave events to move the pointer from its current window up * to the lowest ancestor that it has in common with the grab window. * However, only do this if the pointer is outside the grab window's * subtree but inside the grab window's application. */ if ((dispPtr->serverWinPtr != NULL) && (dispPtr->serverWinPtr->mainPtr == winPtr->mainPtr)) { for (winPtr2 = dispPtr->serverWinPtr; ; winPtr2 = winPtr2->parentPtr) { if (winPtr2 == winPtr) { break; } if (winPtr2 == NULL) { MovePointer2(dispPtr->serverWinPtr, winPtr, NotifyGrab, 1, 0); break; } } } QueueGrabWindowChange(dispPtr, winPtr); return TCL_OK; }
static int AfterDelay( Tcl_Interp *interp, Tcl_WideInt ms) { Interp *iPtr = (Interp *) interp; Tcl_Time endTime, now; Tcl_WideInt diff; Tcl_GetTime(&now); endTime = now; endTime.sec += (long)(ms/1000); endTime.usec += ((int)(ms%1000))*1000; if (endTime.usec >= 1000000) { endTime.sec++; endTime.usec -= 1000000; } do { if (Tcl_AsyncReady()) { if (Tcl_AsyncInvoke(interp, TCL_OK) != TCL_OK) { return TCL_ERROR; } } if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { return TCL_ERROR; } if (iPtr->limit.timeEvent != NULL && TCL_TIME_BEFORE(iPtr->limit.time, now)) { iPtr->limit.granularityTicker = 0; if (Tcl_LimitCheck(interp) != TCL_OK) { return TCL_ERROR; } } if (iPtr->limit.timeEvent == NULL || TCL_TIME_BEFORE(endTime, iPtr->limit.time)) { diff = TCL_TIME_DIFF_MS_CEILING(endTime, now); #ifndef TCL_WIDE_INT_IS_LONG if (diff > LONG_MAX) { diff = LONG_MAX; } #endif if (diff > TCL_TIME_MAXIMUM_SLICE) { diff = TCL_TIME_MAXIMUM_SLICE; } if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) diff = 1; if (diff > 0) { Tcl_Sleep((long) diff); if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) break; } else break; } else { diff = TCL_TIME_DIFF_MS(iPtr->limit.time, now); #ifndef TCL_WIDE_INT_IS_LONG if (diff > LONG_MAX) { diff = LONG_MAX; } #endif if (diff > TCL_TIME_MAXIMUM_SLICE) { diff = TCL_TIME_MAXIMUM_SLICE; } if (diff > 0) { Tcl_Sleep((long) diff); } if (Tcl_AsyncReady()) { if (Tcl_AsyncInvoke(interp, TCL_OK) != TCL_OK) { return TCL_ERROR; } } if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { return TCL_ERROR; } if (Tcl_LimitCheck(interp) != TCL_OK) { return TCL_ERROR; } } Tcl_GetTime(&now); } while (TCL_TIME_BEFORE(now, endTime)); return TCL_OK; }
int draw_graph(int step) { int code; double display_width, display_height; double xscale, yscale; double xoff, yoff; struct vertex *v, *w; struct point t; int n, i, j; static int angle = 90; static int count = 0; int steps; double s, c; double xc, yc, zc; double d, dmax, avglen; double f1, f2; double xmin, xmax, ymin, ymax, zmin, zmax; double elevation; struct edge *edges; int e; edges = (struct edge *) malloc( sizeof(struct edge) * nedges ); if (edges == NULL) { fprintf(stderr, "Not enough memory"); return; } /* --- determine number of interpolation steps --- */ dmax = 0.0; avglen = 0.0; for (i = 1; i <= nvertices; i++) { v = &(vertices[i]); d = norm( difference( v->pos, v->saved_pos ) ); if (d > dmax) dmax = d; for (j = 0; j < v->valency; j++) { if (v->adj[j] > i) { w = &(vertices[v->adj[j]]); avglen += norm( difference( v->saved_pos, w->saved_pos ) ); } } } avglen /= nedges; steps = (int) ( dmax / maxdist ) + 1; /* --- interpolate and display --- */ if (count_only) count += steps; else { for (n = 1; n <= steps; n++) { /* --- initialize Tk stuff --- */ if (Tk_GetNumMainWindows() <= 0) { free(edges); return TCL_RETURN; } sprintf(tcl_command_buffer, "update; set step %d", step); code = Tcl_Eval(interp, tcl_command_buffer); if (code != TCL_OK) { fprintf(stderr, "in Tcl_Eval: %s\n", interp->result); free(edges); return code; } if (Tk_GetNumMainWindows() <= 0) { free(edges); return TCL_RETURN; } sprintf(tcl_command_buffer, "get_canvas_size"); code = Tcl_Eval(interp, tcl_command_buffer); if (code != TCL_OK) { fprintf(stderr, "in Tcl_Eval: %s\n", interp->result); free(edges); return code; } sscanf(interp->result, "%lf %lf", &display_width, &display_height); xscale = (display_width / 2.0 - 10.0) / height; yscale = (display_height / 2.0 - 10.0) / height; if (xscale <= yscale) yscale = xscale; else xscale = yscale; yscale *= -1; xoff = display_width / 2.0; yoff = display_height - 10.0; sprintf(tcl_command_buffer, "clear_canvas"); code = Tcl_Eval(interp, tcl_command_buffer); if (code != TCL_OK) { fprintf(stderr, "in Tcl_Eval: %s\n", interp->result); free(edges); return code; } /* --- compute current transformation parameters --- */ f2 = (double)n / (double)steps; f1 = 1.0 - f2; s = sin( angle * M_PI / 180.0); c = cos( angle * M_PI / 180.0); angle = ( angle - 1 ) % 360; /* --- compute center of gravity to rotate about --- */ xc = yc = zc = 0.0; for (i = 1; i <= nvertices; i++) { v = &(vertices[i]); xc += f1 * v->saved_pos.x + f2 * v->pos.x; yc += f1 * v->saved_pos.y + f2 * v->pos.y; zc += f1 * v->saved_pos.z + f2 * v->pos.z; } xc /= nvertices; yc /= nvertices; zc /= nvertices; /* --- compute endpoints of all the edges --- */ e = 0; for (i = 1; i <= nvertices; i++) { v = &(vertices[i]); for (j = 0; j < v->valency; j++) { if (v->adj[j] > i) { w = &(vertices[v->adj[j]]); t.x = f1 * w->saved_pos.x + f2 * w->pos.x - xc; t.y = f1 * w->saved_pos.y + f2 * w->pos.y - yc; t.z = f1 * w->saved_pos.z + f2 * w->pos.z - zc; edges[e].p.x = t.x * c - t.z * s; edges[e].p.y = t.y; edges[e].p.z = t.x * s + t.z * c; t.x = f1 * v->saved_pos.x + f2 * v->pos.x - xc; t.y = f1 * v->saved_pos.y + f2 * v->pos.y - yc; t.z = f1 * v->saved_pos.z + f2 * v->pos.z - zc; edges[e].q.x = t.x * c - t.z * s; edges[e].q.y = t.y; edges[e].q.z = t.x * s + t.z * c; ++e; } } } nedges = e; /* --- compute bounding box --- */ for (e = 0; e < nedges; e++) { if (e == 0) { xmin = xmax = edges[e].p.x; ymin = ymax = edges[e].p.y; zmin = zmax = edges[e].p.z; } if (edges[e].p.x < xmin) xmin = edges[e].p.x; if (edges[e].p.x > xmax) xmax = edges[e].p.x; if (edges[e].p.y < ymin) ymin = edges[e].p.y; if (edges[e].p.y > ymax) ymax = edges[e].p.y; if (edges[e].p.z < zmin) zmin = edges[e].p.z; if (edges[e].p.z > zmax) zmax = edges[e].p.z; if (edges[e].q.x < xmin) xmin = edges[e].q.x; if (edges[e].q.x > xmax) xmax = edges[e].q.x; if (edges[e].q.y < ymin) ymin = edges[e].q.y; if (edges[e].q.y > ymax) ymax = edges[e].q.y; if (edges[e].q.z < zmin) zmin = edges[e].q.z; if (edges[e].q.z > zmax) zmax = edges[e].q.z; } /* --- compute elevation --- */ if ( - ymin > 0.9 * height) elevation = - ymin + 0.1 * height; else elevation = height; for (e = 0; e < nedges; e++) { edges[e].p.y += elevation; edges[e].q.y += elevation; } /* --- now do the drawing --- */ qsort((void *)edges, nedges, sizeof(struct edge), cmp_edges); for (e = 0; e < nedges; e++) { edges[e].shade = (int) (0.5 + 14.0 * ((zmax - (edges[e].p.z + edges[e].q.z) / 2.0) / (zmax - zmin))); sprintf(tcl_command_buffer, "add_closer_line %lf %lf %lf %lf #%x%xf", edges[e].p.x * xscale + xoff, edges[e].p.y * yscale + yoff, edges[e].q.x * xscale + xoff, edges[e].q.y * yscale + yoff, edges[e].shade, edges[e].shade ); code = Tcl_Eval(interp, tcl_command_buffer); if (code != TCL_OK) { fprintf(stderr, "in Tcl_VarEval: %s\n", interp->result); free(edges); return code; } } /* --- update screen and pause if requested --- */ sprintf(tcl_command_buffer, "update idletasks"); code = Tcl_Eval(interp, tcl_command_buffer); if (code != TCL_OK) { fprintf(stderr, "in Tcl_Eval: %s\n", interp->result); free(edges); return code; } Tcl_Sleep(sleep_ms); } } for (i = 1; i <= nvertices; i++) { v = &vertices[i]; v->saved_pos.x = v->pos.x; v->saved_pos.y = v->pos.y; v->saved_pos.z = v->pos.z; } free(edges); return count; }