Exemplo n.º 1
0
GLUTmenuItem *
__glutGetMenuItem(GLUTmenu * menu, Window win, int *which)
{
  GLUTmenuItem *item;
  int i;

  i = menu->num;
  item = menu->list;
  while (item) {
    if (item->win == win) {
      *which = i;
      return item;
    }
    if (item->isTrigger) {
      GLUTmenuItem *subitem;

      subitem = __glutGetMenuItem(menuList[item->value],
        win, which);
      if (subitem) {
        return subitem;
      }
    }
    i--;
    item = item->next;
  }
  return NULL;
}
Exemplo n.º 2
0
static void
processEventsAndTimeouts(void)
{
  do {
#if defined(_WIN32)
    MSG event;

    if(!GetMessage(&event, NULL, 0, 0))	/* bail if no more messages */
      exit(0);
    TranslateMessage(&event);		/* translate virtual-key messages */
    DispatchMessage(&event);		/* call the window proc */
    /* see win32_event.c for event (message) processing procedures */
#else
    static int mappedMenuButton;
    GLUTeventParser *parser;
    XEvent event, ahead;
    GLUTwindow *window;
    GLUTkeyboardCB keyboard;
    GLUTspecialCB special;
    int gotEvent, width, height;

    gotEvent = interruptibleXNextEvent(__glutDisplay, &event);
    if (gotEvent) {
      switch (event.type) {
      case MappingNotify:
        XRefreshKeyboardMapping((XMappingEvent *) & event);
        break;
      case ConfigureNotify:
        window = __glutGetWindow(event.xconfigure.window);
        if (window) {
          if (window->win != event.xconfigure.window) {
            /* Ignore ConfigureNotify sent to the overlay
               planes. GLUT could get here because overlays
               select for StructureNotify events to receive
               DestroyNotify. */
            break;
          }
          width = event.xconfigure.width;
          height = event.xconfigure.height;
          if (width != window->width || height != window->height) {
            if (window->overlay) {
              XResizeWindow(__glutDisplay, window->overlay->win, width, height);
            }
            window->width = width;
            window->height = height;
            __glutSetWindow(window);
            /* Do not execute OpenGL out of sequence with
               respect to the XResizeWindow request! */
            glXWaitX();
            window->reshape(width, height);
            window->forceReshape = False;
            /* A reshape should be considered like posting a
               repair; this is necessary for the "Mesa
               glXSwapBuffers to repair damage" hack to operate
               correctly.  Without it, there's not an initial
               back buffer render from which to blit from when
               damage happens to the window. */
            __glutPostRedisplay(window, GLUT_REPAIR_WORK);
          }
        }
        break;
      case Expose:
        /* compress expose events */
        while (XEventsQueued(__glutDisplay, QueuedAfterReading)
          > 0) {
          XPeekEvent(__glutDisplay, &ahead);
          if (ahead.type != Expose ||
            ahead.xexpose.window != event.xexpose.window) {
            break;
          }
          XNextEvent(__glutDisplay, &event);
        }
        if (event.xexpose.count == 0) {
          GLUTmenu *menu;

          if (__glutMappedMenu &&
            (menu = __glutGetMenu(event.xexpose.window))) {
            __glutPaintMenu(menu);
          } else {
            window = __glutGetWindow(event.xexpose.window);
            if (window) {
              if (window->win == event.xexpose.window) {
                __glutPostRedisplay(window, GLUT_REPAIR_WORK);
              } else if (window->overlay && window->overlay->win == event.xexpose.window) {
                __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK);
              }
            }
          }
        } else {
          /* there are more exposes to read; wait to redisplay */
        }
        break;
      case ButtonPress:
      case ButtonRelease:
        if (__glutMappedMenu && event.type == ButtonRelease
          && mappedMenuButton == event.xbutton.button) {
          /* Menu is currently popped up and its button is
             released. */
          __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
        } else {
          window = __glutGetWindow(event.xbutton.window);
          /* added button check for mice with > 3 buttons */
          if (window) {
            GLUTmenu *menu;
	    int menuNum;

            if (event.xbutton.button <= GLUT_MAX_MENUS)
              menuNum = window->menu[event.xbutton.button - 1];
            else
              menuNum = 0;

            /* Make sure that __glutGetMenuByNum is only called if there
	       really is a menu present. */
            if ((menuNum > 0) && (menu = __glutGetMenuByNum(menuNum))) {
              if (event.type == ButtonPress && !__glutMappedMenu) {
                __glutStartMenu(menu, window,
                  event.xbutton.x_root, event.xbutton.y_root,
                  event.xbutton.x, event.xbutton.y);
                mappedMenuButton = event.xbutton.button;
              } else {
                /* Ignore a release of a button with a menu
                   attatched to it when no menu is popped up,
                   or ignore a press when another menu is
                   already popped up. */
              }
            } else if (window->mouse) {
              __glutSetWindow(window);
              __glutModifierMask = event.xbutton.state;
              window->mouse(event.xbutton.button - 1,
                event.type == ButtonRelease ?
                GLUT_UP : GLUT_DOWN,
                event.xbutton.x, event.xbutton.y);
              __glutModifierMask = ~0;
            } else {
              /* Stray mouse events.  Ignore. */
            }
          } else {
            /* Window might have been destroyed and all the 
               events for the window may not yet be received. */
          }
        }
        break;
      case MotionNotify:
        if (!__glutMappedMenu) {
          window = __glutGetWindow(event.xmotion.window);
          if (window) {
            /* If motion function registered _and_ buttons held 
               * down, call motion function...  */
            if (window->motion && event.xmotion.state &
              (Button1Mask | Button2Mask | Button3Mask)) {
              __glutSetWindow(window);
              window->motion(event.xmotion.x, event.xmotion.y);
            }
            /* If passive motion function registered _and_
               buttons not held down, call passive motion
               function...  */
            else if (window->passive &&
                ((event.xmotion.state &
                    (Button1Mask | Button2Mask | Button3Mask)) ==
                0)) {
              __glutSetWindow(window);
              window->passive(event.xmotion.x,
                event.xmotion.y);
            }
          }
        } else {
          /* Motion events are thrown away when a pop up menu
             is active. */
        }
        break;
      case KeyPress:
      case KeyRelease:
        window = __glutGetWindow(event.xkey.window);
        if (!window) {
          break;
        }
	if (event.type == KeyPress) {
	  keyboard = window->keyboard;
	} else {

	  /* If we are ignoring auto repeated keys for this window,
	     check if the next event in the X event queue is a KeyPress
	     for the exact same key (and at the exact same time) as the
	     key being released.  The X11 protocol will send auto
	     repeated keys as such KeyRelease/KeyPress pairs. */

	  if (window->ignoreKeyRepeat) {
	    if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
	      XPeekEvent(__glutDisplay, &ahead);
	      if (ahead.type == KeyPress
	        && ahead.xkey.window == event.xkey.window
	        && ahead.xkey.keycode == event.xkey.keycode
	        && ahead.xkey.time == event.xkey.time) {
		/* Pop off the repeated KeyPress and ignore
		   the auto repeated KeyRelease/KeyPress pair. */
	        XNextEvent(__glutDisplay, &event);
	        break;
	      }
	    }
	  }
	  keyboard = window->keyboardUp;
	}
        if (keyboard) {
          char tmp[1];
          int rc;

          rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
            NULL, NULL);
          if (rc) {
            __glutSetWindow(window);
            __glutModifierMask = event.xkey.state;
            keyboard(tmp[0],
              event.xkey.x, event.xkey.y);
            __glutModifierMask = ~0;
            break;
          }
        }
	if (event.type == KeyPress) {
	  special = window->special;
        } else {
	  special = window->specialUp;
	}
        if (special) {
          KeySym ks;
          int key;

/* Introduced in X11R6:  (Partial list of) Keypad Functions.  Define
   in place in case compiling against an older pre-X11R6
   X11/keysymdef.h file. */
#ifndef XK_KP_Home
#define XK_KP_Home              0xFF95
#endif
#ifndef XK_KP_Left
#define XK_KP_Left              0xFF96
#endif
#ifndef XK_KP_Up
#define XK_KP_Up                0xFF97
#endif
#ifndef XK_KP_Right
#define XK_KP_Right             0xFF98
#endif
#ifndef XK_KP_Down
#define XK_KP_Down              0xFF99
#endif
#ifndef XK_KP_Prior
#define XK_KP_Prior             0xFF9A
#endif
#ifndef XK_KP_Next
#define XK_KP_Next              0xFF9B
#endif
#ifndef XK_KP_End
#define XK_KP_End               0xFF9C
#endif
#ifndef XK_KP_Insert
#define XK_KP_Insert            0xFF9E
#endif
#ifndef XK_KP_Delete
#define XK_KP_Delete            0xFF9F
#endif

          ks = XLookupKeysym((XKeyEvent *) & event, 0);
          /* XXX Verbose, but makes no assumptions about keysym
             layout. */
          switch (ks) {
/* *INDENT-OFF* */
          /* function keys */
          case XK_F1:    key = GLUT_KEY_F1; break;
          case XK_F2:    key = GLUT_KEY_F2; break;
          case XK_F3:    key = GLUT_KEY_F3; break;
          case XK_F4:    key = GLUT_KEY_F4; break;
          case XK_F5:    key = GLUT_KEY_F5; break;
          case XK_F6:    key = GLUT_KEY_F6; break;
          case XK_F7:    key = GLUT_KEY_F7; break;
          case XK_F8:    key = GLUT_KEY_F8; break;
          case XK_F9:    key = GLUT_KEY_F9; break;
          case XK_F10:   key = GLUT_KEY_F10; break;
          case XK_F11:   key = GLUT_KEY_F11; break;
          case XK_F12:   key = GLUT_KEY_F12; break;
          /* directional keys */
	  case XK_KP_Left:
          case XK_Left:  key = GLUT_KEY_LEFT; break;
	  case XK_KP_Up: /* Introduced in X11R6. */
          case XK_Up:    key = GLUT_KEY_UP; break;
	  case XK_KP_Right: /* Introduced in X11R6. */
          case XK_Right: key = GLUT_KEY_RIGHT; break;
	  case XK_KP_Down: /* Introduced in X11R6. */
          case XK_Down:  key = GLUT_KEY_DOWN; break;
/* *INDENT-ON* */

	  case XK_KP_Prior: /* Introduced in X11R6. */
          case XK_Prior:
            /* XK_Prior same as X11R6's XK_Page_Up */
            key = GLUT_KEY_PAGE_UP;
            break;
	  case XK_KP_Next: /* Introduced in X11R6. */
          case XK_Next:
            /* XK_Next same as X11R6's XK_Page_Down */
            key = GLUT_KEY_PAGE_DOWN;
            break;
	  case XK_KP_Home: /* Introduced in X11R6. */
          case XK_Home:
            key = GLUT_KEY_HOME;
            break;
#ifdef __hpux
          case XK_Select:
#endif
	  case XK_KP_End: /* Introduced in X11R6. */
          case XK_End:
            key = GLUT_KEY_END;
            break;
#ifdef __hpux
          case XK_InsertChar:
#endif
	  case XK_KP_Insert: /* Introduced in X11R6. */
          case XK_Insert:
            key = GLUT_KEY_INSERT;
            break;
#ifdef __hpux
          case XK_DeleteChar:
#endif
	  case XK_KP_Delete: /* Introduced in X11R6. */
            /* The Delete character is really an ASCII key. */
            __glutSetWindow(window);
            keyboard(127,  /* ASCII Delete character. */
              event.xkey.x, event.xkey.y);
            goto skip;
          default:
            goto skip;
          }
          __glutSetWindow(window);
          __glutModifierMask = event.xkey.state;
          special(key, event.xkey.x, event.xkey.y);
          __glutModifierMask = ~0;
        skip:;
        }
        break;
      case EnterNotify:
      case LeaveNotify:
        if (event.xcrossing.mode != NotifyNormal ||
          event.xcrossing.detail == NotifyNonlinearVirtual ||
          event.xcrossing.detail == NotifyVirtual) {

          /* Careful to ignore Enter/LeaveNotify events that
             come from the pop-up menu pointer grab and ungrab. 
             Also, ignore "virtual" Enter/LeaveNotify events
             since they represent the pointer passing through
             the window hierarchy without actually entering or
             leaving the actual real estate of a window.  */

          break;
        }
        if (__glutMappedMenu) {
          GLUTmenuItem *item;
          int num;

          item = __glutGetMenuItem(__glutMappedMenu,
            event.xcrossing.window, &num);
          if (item) {
            __glutMenuItemEnterOrLeave(item, num, event.type);
            break;
          }
        }
        window = __glutGetWindow(event.xcrossing.window);
        if (window) {
          if (window->entry) {
            if (event.type == EnterNotify) {

              /* With overlays established, X can report two
                 enter events for both the overlay and normal
                 plane window. Do not generate a second enter
                 callback if we reported one without an
                 intervening leave. */

              if (window->entryState != EnterNotify) {
                int num = window->num;
                Window xid = window->win;

                window->entryState = EnterNotify;
                __glutSetWindow(window);
                window->entry(GLUT_ENTERED);

                if (__glutMappedMenu) {

                  /* Do not generate any passive motion events
                     when menus are in use. */

                } else {

                  /* An EnterNotify event can result in a
                     "compound" callback if a passive motion
                     callback is also registered. In this case,
                     be a little paranoid about the possibility
                     the window could have been destroyed in the
                     entry callback. */

                  window = __glutWindowList[num];
                  if (window && window->passive && window->win == xid) {
                    __glutSetWindow(window);
                    window->passive(event.xcrossing.x, event.xcrossing.y);
                  }
                }
              }
            } else {
              if (window->entryState != LeaveNotify) {

                /* When an overlay is established for a window
                   already mapped and with the pointer in it,
                   the X server will generate a leave/enter
                   event pair as the pointer leaves (without
                   moving) from the normal plane X window to
                   the newly mapped overlay  X window (or vice
                   versa). This enter/leave pair should not be
                   reported to the GLUT program since the pair
                   is a consequence of creating (or destroying) 
                   the overlay, not an actual leave from the
                   GLUT window. */

                if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
                  XPeekEvent(__glutDisplay, &ahead);
                  if (ahead.type == EnterNotify &&
                    __glutGetWindow(ahead.xcrossing.window) == window) {
                    XNextEvent(__glutDisplay, &event);
                    break;
                  }
                }
                window->entryState = LeaveNotify;
                __glutSetWindow(window);
                window->entry(GLUT_LEFT);
              }
            }
          } else if (window->passive) {
            __glutSetWindow(window);
            window->passive(event.xcrossing.x, event.xcrossing.y);
          }
        }
        break;
      case UnmapNotify:
        /* MapNotify events are not needed to maintain
           visibility state since VisibilityNotify events will
           be delivered when a window becomes visible from
           mapping.  However, VisibilityNotify events are not
           delivered when a window is unmapped (for the window
           or its children). */
        window = __glutGetWindow(event.xunmap.window);
        if (window) {
          if (window->win != event.xconfigure.window) {
            /* Ignore UnmapNotify sent to the overlay planes.
               GLUT could get here because overlays select for
               StructureNotify events to receive DestroyNotify. 
             */
            break;
          }
          markWindowHidden(window);
        }
        break;
      case VisibilityNotify:
        window = __glutGetWindow(event.xvisibility.window);
        if (window) {
          /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED,
             VisibilityPartiallyObscured+1 =
             GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1 
             =  GLUT_FULLY_COVERED. */
          int visState = event.xvisibility.state + 1;

          if (visState != window->visState) {
            if (window->windowStatus) {
              window->visState = visState;
              __glutSetWindow(window);
              window->windowStatus(visState);
            }
          }
        }
        break;
      case ClientMessage:
        if (event.xclient.data.l[0] == __glutWMDeleteWindow)
          exit(0);
        break;
      case DestroyNotify:
        purgeStaleWindow(event.xdestroywindow.window);
        break;
      case CirculateNotify:
      case CreateNotify:
      case GravityNotify:
      case ReparentNotify:
        /* Uninteresting to GLUT (but possible for GLUT to
           receive). */
        break;
      default:
        /* Pass events not directly handled by the GLUT main
           event loop to any event parsers that have been
           registered.  In this way, X Input extension events
           are passed to the correct handler without forcing
           all GLUT programs to support X Input event handling. 
         */
        parser = eventParserList;
        while (parser) {
          if (parser->func(&event))
            break;
          parser = parser->next;
        }
        break;
      }
    }
#endif /* _WIN32 */
    if (__glutTimerList) {
      handleTimeouts();
    }
  }
  while (XPending(__glutDisplay));
}