ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/bin/geomview/gl/glevent.c

This is glevent.c in view mode; [Download] [Up]

/* Copyright (c) 1992 The Geometry Center; University of Minnesota
   1300 South Second Street;  Minneapolis, MN  55454, USA;
   
This file is part of geomview/OOGL. geomview/OOGL is free software;
you can redistribute it and/or modify it only under the terms given in
the file COPYING, which you should have received along with this file.
This and other related software may be obtained via anonymous ftp from
geom.umn.edu; email: software@geom.umn.edu. */

/* Authors: Stuart Levy, Tamara Munzner, Mark Phillips */

#include "mg.h"
#include "mggl.h"
#include <gl/gl.h>
#include <gl/device.h>
#include <sys/types.h>
#include <sys/time.h>
#include "../common/event.h"
#include "../common/drawer.h"
#include "../common/ui.h"

/************************************************************************

 Event module:

    Public procedures:
    	MainLoop()

 ************************************************************************/

#define QDEVICE	fl_qdevice
#define QTEST	fl_qtest
#define QREAD	fl_qread

static int ReadEvent(Event *event);
static void GetMousePosition(int *x, int *y, unsigned long int *millisec);
static void perftick();
extern void timing(int report_interval);

extern int leftmouse_only;	/* From glmain.c: hack */
	/*
	 * File descriptors being watched in the main loop.
	 * Includes the GL input queue descriptor.
	 */
static int nseen;
static int queuefd;

static struct perf {		/* Performance metering */
    int interval;		/* Interval between auto-reports */
    int mindt, maxdt, meandt;	/* Integer milliseconds */
    int cycles;			/* # cycles where we actually did something */
    struct timeval then;
} perf;



void
MainLoop()
{
  Event event;
  fd_set thesefds;
  int hurry;
  mgcontext *mgctx;
  int panel;
  int immedcount = 0;
  int dragging = 0;
  int i;
  int nwatch = 0;
  struct timeval then, now;
  int lastx, lasty, dragx, dragy;
  unsigned long lastt;
  int firstclick;

  QDEVICE(RIGHTMOUSE);
  QDEVICE(MIDDLEMOUSE);
  QDEVICE(LEFTMOUSE);
  QDEVICE(KEYBD);
  QDEVICE(LEFTSHIFTKEY);  QDEVICE(RIGHTSHIFTKEY);
  QDEVICE(LEFTCTRLKEY);   QDEVICE(RIGHTCTRLKEY);

  QDEVICE(WINSHUT);		/* WINSHUT and WINQUIT are needed to force */
  QDEVICE(WINQUIT);		/* the lightning bolt to appear; by default */
  QDEVICE(WINFREEZE);		/* detect iconify requests */
  QDEVICE(WINTHAW);		/* and de-iconifies */

  tie(LEFTMOUSE, MOUSEX, MOUSEY);
  tie(MIDDLEMOUSE, MOUSEX, MOUSEY);
  tie(RIGHTMOUSE, MOUSEX, MOUSEY);

  queuefd = qgetfd();

  while (1) {
    struct timeval await;
#define	BRIEF	0.1
    static struct timeval brief = { 0, 100000 };
    float timelimit;

    if(drawerstate.pause) {
	if(!dragging && !drawer_moving())
	    select(0, NULL, NULL, NULL, &brief);
	nseen = 0;
    } else {
	timelimit = PoolInputFDs( &thesefds, &nwatch );

	if(!dragging && timelimit > 0 && drawer_moving())
	    timelimit = 0;	/* "Is anything moving?" */

	FD_SET(queuefd, &thesefds);
	if(queuefd >= nwatch)
	    nwatch = queuefd+1;

	if(timelimit > BRIEF) timelimit = BRIEF;

	await.tv_sec = floor(timelimit);
	await.tv_usec = 1000000*(timelimit - await.tv_sec);

	nseen = select(nwatch, &thesefds, NULL, NULL, &await);
    }

    gettimeofday(&perf.then, NULL);

    if(!drawerstate.pause)
	PoolInAll( &thesefds, &nseen );

    panel_check();
    firstclick = 1;
    while((dragging = ReadEvent( &event )) != 0) {

	switch (event.dev) {
	case INPUTCHANGE:
	  if(event.val != 0 && ((mgctx = mggl_findctx(event.val)) != NULL)) {
		/* Resync button states in case we lost a transition */
	    button.shift = getbutton(LEFTSHIFTKEY)+getbutton(RIGHTSHIFTKEY);
	    button.ctrl = getbutton(CTRLKEY);
		/* Track which window has mouse focus */
	    gv_winenter(drawer_idbyctx(mgctx));
	  }
	  break;

	case WINFREEZE:
	  if((mgctx = mggl_findctx(event.val)) != NULL)
	    gv_freeze(drawer_idbyctx(mgctx));
	  break;

	case REDRAW:
	case WINTHAW:
	  if((mgctx = mggl_findctx(event.val)) != NULL)
	    gv_redraw(drawer_idbyctx(mgctx));
	  break;

	case WINSHUT:
	  if((mgctx = mggl_findctx(event.val)) != NULL)
	    gv_delete(drawer_idbyctx(mgctx));
	  else if((panel = ui_winid2panel(event.val)) != 0)
	    ui_showpanel(panel, 0);
	  break;

	case WINQUIT:
	  return;		/* Terminate */

	case ELEFTMOUSE:
	case EMIDDLEMOUSE:
	case ERIGHTMOUSE:
	  if (event.val == -1) {	/* Mouse drag */
	    if (event.t - lastt > uistate.cursor_still) {
	      if (abs(event.x - lastx) < uistate.cursor_twitch &&
		  abs(event.y - lasty) < uistate.cursor_twitch) {
		event.x = dragx;
		event.y = dragy;
	      }
	      lastx = event.x;
	      lasty = event.y;
	      lastt = event.t;
	    }
	  } else {
	    if(event.val == 1 && firstclick) {
		/* If a down-click occurs during a pause, pretend it
		 * happened at the beginning of the pause.
		 */
		event.t = 1000 * drawerstate.lastupdate;
		firstclick = 0;
	    }
	    lastt = event.t;
	  }
	  dragx = event.x;
	  dragy = event.y;
	  /* Falling through... */
	default:
	  gv_rawevent( event.dev, event.val, event.x, event.y, event.t );
	  break;
	}

	if(!uistate.cursor_on) {
	    extern Event oldmouse;
	    int xmid = (drawerstate.winpos.xmin + drawerstate.winpos.xmax)/2;
	    int ymid = (drawerstate.winpos.ymin + drawerstate.winpos.ymax)/2;
	    oldmouse.x -= event.x - xmid;
	    oldmouse.y -= event.y - ymid;
	    setvaluator(MOUSEX, xmid, 0, 1280);
	    setvaluator(MOUSEY, ymid, 0, 1024);
	}

	if(dragging < 0)
	    break;
    }
    if(!uistate.cursor_on || uistate.clamp_cursor) {
	extern Event oldmouse;
	int xmid = (drawerstate.winpos.xmin + drawerstate.winpos.xmax)/2;
	int ymid = (drawerstate.winpos.ymin + drawerstate.winpos.ymax)/2;
	oldmouse.x -= event.x - xmid;
	oldmouse.y -= event.y - ymid;
	setvaluator(MOUSEX, xmid, 0, 1280);
	setvaluator(MOUSEY, ymid, 0, 1024);
    }

    ui_update();

    gv_update_draw( ALLCAMS, 0. );

    if(perf.interval > 0)
	perftick();
  }
}

static void
perftick()
{
    int dt;
    struct timeval now;
    gettimeofday(&now, NULL);
    dt = (now.tv_sec - perf.then.tv_sec)*1000 +
	 (now.tv_usec - perf.then.tv_usec)/1000;
    if(dt > 0) {
	if(dt < perf.mindt) perf.mindt = dt;
	if(dt > perf.maxdt) perf.maxdt = dt;
	perf.meandt += dt;
	if(++perf.cycles == perf.interval)
	    timing(perf.interval);
    }
}

void
timing(int interval)
{
    if(perf.cycles > 0) {
	printf("%d..%d ms/cycle, mean %d ms over %d cycles\n",
		perf.mindt, perf.maxdt,
		perf.cycles ? perf.meandt/perf.cycles : 0,
		perf.cycles);
	fflush(stdout);
    }
    perf.mindt = 9999999, perf.maxdt = -1, perf.meandt = perf.cycles = 0;
    perf.interval = interval;
}



/*-----------------------------------------------------------------------
 * Function:	ReadEvent
 * Description:	read an event from the queue, if any
 * Args:	*event:
 * Returns:	1 if an event was read,
 *		-1 if no event on queue but a drag event was synthesized,
 *		0 if queue is empty
 * Author:	mbp
 * Date:	Tue Oct 15 12:16:33 1991
 * Notes:	This procedure merges the following kinds of events into
 *		a single queue:
 *		  1. events from the GL queue
 *		  2. mouse motion with a mouse button held down
 *		These queues are polled in this order and the first
 *		event encountered is returned.  If both are empty, 0
 *		is returned.
 */
static int
ReadEvent(Event *event)
{
  short val;
  int dev = 0;
  char *btn;

  static int buttondown = 0;
  static int glmouse, emouse;
  static int lastx, lasty;

  GetMousePosition( &event->x, &event->y, &event->t );

 another:
  if (QTEST()) {
    switch (dev = QREAD( &val )) {
    case LEFTMOUSE:
	event->dev = ELEFTMOUSE; btn = &button.left; goto domousebutton;
    case MIDDLEMOUSE:
	event->dev = EMIDDLEMOUSE; btn = &button.middle; goto domousebutton;
    case RIGHTMOUSE:
	event->dev = ERIGHTMOUSE; btn = &button.right; goto domousebutton;

    domousebutton:
      if(leftmouse_only) {	/* Hack to simulate a one-button mouse */
	event->dev = ELEFTMOUSE;
	btn = &button.left;
      }
      buttondown = event->val = val;
      if(QREAD( &val ) == MOUSEX) {
	/* Fetch mouse position -- supplied because of tie() call above. */
	event->x = val;
        if(QREAD( &val ) == MOUSEY) event->y = val;
      }
      if (buttondown) {
	glmouse = dev;
	emouse = event->dev;
	lastx = event->x;
	lasty = event->y;
      } 
      *btn = buttondown;
      break;

    case LEFTSHIFTKEY: case RIGHTSHIFTKEY:
	button.shift += val ? 1 : -1;
	goto another;

    case LEFTCTRLKEY: case RIGHTCTRLKEY:
	button.ctrl += val ? 1 : -1;
	goto another;
    

    case KEYBD:
	event->dev = val;
	event->val = 1;
	break;

    default:
	event->dev = dev;
	event->val = val;
	break;
    }
    return 1;
  }
  else if (buttondown && (buttondown=getbutton(glmouse))) {
    /* a mouse button is being held down; generate a drag event */

    event->dev = emouse;
    event->val = -1;
    lastx = event->x;
    lasty = event->y;
    return -1;
  }
  return 0;
}
 
static void
GetMousePosition(int *x, int *y, unsigned long int *msec)
{
  *x = getvaluator(MOUSEX);
  *y = getvaluator(MOUSEY);
  *msec = 1000*elapsed(NULL, NULL);
}

/**********************************************************************/
/*
 * the stuff below here is for debugging only
 */

char *devstring();

PrintEvent(s, event)
     char *s;
     Event *event;
{
  printf("%s dev=%s val=%1d, x=%1d, y=%1d\n",
	 s, devstring(event->dev), event->val, event->x, event->y);
}

char *devstring(dev)
     int dev;
{
  static char buf[80];
  switch (dev) {
  case ELEFTMOUSE: return "ELEFTMOUSE";
  case EMIDDLEMOUSE: return "EMIDDLEMOUSE";
  case ERIGHTMOUSE: return "ERIGHTMOUSE";
  default: sprintf(buf,"%1d",dev); return(buf);
  }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.