Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}