Ejemplo n.º 1
0
/* CENTRY */
void APIENTRY
glutMainLoop(void)
{
#if !defined(_WIN32)
  if (!__glutDisplay)
    __glutFatalUsage("main loop entered with out proper initialization.");
#endif
  if (!__glutWindowListSize)
    __glutFatalUsage(
      "main loop entered with no windows created.");
  for (;;) {
    if (__glutWindowWorkList) {
      GLUTwindow *remainder, *work;

      work = __glutWindowWorkList;
      __glutWindowWorkList = NULL;
      if (work) {
        remainder = processWindowWorkList(work);
        if (remainder) {
          *beforeEnd = __glutWindowWorkList;
          __glutWindowWorkList = remainder;
        }
      }
    }
    if (__glutIdleFunc || __glutWindowWorkList) {
      idleWait();
    } else {
      if (__glutTimerList) {
        waitForSomething();
      } else {
        processEventsAndTimeouts();
      }
    }
  }
}
Ejemplo n.º 2
0
static  /* X11 implementations do not need this global. */
void
__glutProcessWindowWorkLists(void)
{
  if (__glutWindowWorkList) {
    GLUTwindow *remainder, *work;

    work = __glutWindowWorkList;
    __glutWindowWorkList = NULL;
    if (work) {
      remainder = processWindowWorkList(work);
      if (remainder) {
        *beforeEnd = __glutWindowWorkList;
        __glutWindowWorkList = remainder;
      }
    }
  }
}
Ejemplo n.º 3
0
/* CENTRY */
void APIENTRY
glutMainLoop(void)
{
#if !defined(_WIN32)
  if (!__glutDisplay)
    __glutFatalUsage("main loop entered with out proper initialization.");
#endif
  if (!__glutWindowListSize)
    __glutFatalUsage(
      "main loop entered with no windows created.");
  for (;;) {
    if (__glutWindowWorkList) {
      GLUTwindow *remainder, *work;

      work = __glutWindowWorkList;
      __glutWindowWorkList = NULL;
      if (work) {
        remainder = processWindowWorkList(work);
        if (remainder) {
          *beforeEnd = __glutWindowWorkList;
          __glutWindowWorkList = remainder;
        }
      }
    }
    if (__glutIdleFunc || __glutWindowWorkList) {
      idleWait();
    } else {
      if (__glutTimerList) {
        waitForSomething();
      } else {
        processEventsAndTimeouts();
      }
#if defined(_WIN32)
	  // If there is no idle function, go to sleep for a millisecond (we 
	  // still need to possibly service timers) or until there is some 
	  // event in our queue.
      MsgWaitForMultipleObjects(0, NULL, FALSE, 1, QS_ALLEVENTS);
#endif
    }
 }
}
Ejemplo n.º 4
0
static GLUTwindow *
processWindowWorkList(GLUTwindow * window)
{
  int workMask;

  if (window->prevWorkWin) {
    window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
  } else {
    beforeEnd = &window->prevWorkWin;
  }

  /* Capture work mask for work that needs to be done to this
     window, then clear the window's work mask (excepting the
     dummy work bit, see below).  Then, process the captured
     work mask.  This allows callbacks in the processing the
     captured work mask to set the window's work mask for
     subsequent processing. */

  workMask = window->workMask;
  assert((workMask & GLUT_DUMMY_WORK) == 0);

  /* Set the dummy work bit, clearing all other bits, to
     indicate that the window is currently on the window work
     list _and_ that the window's work mask is currently being
     processed.  This convinces __glutPutOnWorkList that this
     window is on the work list still. */
  window->workMask = GLUT_DUMMY_WORK;

  /* Optimization: most of the time, the work to do is a
     redisplay and not these other types of work.  Check for
     the following cases as a group to before checking each one
     individually one by one. This saves about 25 MIPS
     instructions in the common redisplay only case. */
  if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
      GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
#if !defined(_WIN32)
    /* Be sure to set event mask BEFORE map window is done. */
    if (workMask & GLUT_EVENT_MASK_WORK) {
      long eventMask;

      /* Make sure children are not propogating events this
         window is selecting for.  Be sure to do this before
         enabling events on the children's parent. */
      if (window->children) {
        GLUTwindow *child = window->children;
        unsigned long attribMask = CWDontPropagate;
        XSetWindowAttributes wa;

        wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
        if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
          wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
          attribMask |= CWEventMask;
        }
        do {
          XChangeWindowAttributes(__glutDisplay, child->win,
            attribMask, &wa);
          child = child->siblings;
        } while (child);
      }
      eventMask = window->eventMask;
      if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
        eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
      XSelectInput(__glutDisplay, window->win, eventMask);
      if (window->overlay)
        XSelectInput(__glutDisplay, window->overlay->win,
          window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
    }
#endif /* !_WIN32 */
    /* Be sure to set device mask BEFORE map window is done. */
    if (workMask & GLUT_DEVICE_MASK_WORK) {
      __glutUpdateInputDeviceMaskFunc(window);
    }
    /* Be sure to configure window BEFORE map window is done. */
    if (workMask & GLUT_CONFIGURE_WORK) {
#if defined(_WIN32)
      RECT changes;
      POINT point;
      UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER
	| SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;

      GetClientRect(window->win, &changes);
      
      /* If this window is a toplevel window, translate the 0,0 client
         coordinate into a screen coordinate for proper placement. */
      if (!window->parent) {
        point.x = 0;
        point.y = 0;
        ClientToScreen(window->win, &point);
        changes.left = point.x;
        changes.top = point.y;
      }
      if (window->desiredConfMask & (CWX | CWY)) {
        changes.left = window->desiredX;
        changes.top = window->desiredY;
	flags &= ~SWP_NOMOVE;
      }
      if (window->desiredConfMask & (CWWidth | CWHeight)) {
        changes.right = changes.left + window->desiredWidth;
        changes.bottom = changes.top + window->desiredHeight;
	flags &= ~SWP_NOSIZE;
	/* XXX If overlay exists, resize the overlay here, ie.
	   if (window->overlay) ... */
      }
      if (window->desiredConfMask & CWStackMode) {
	flags &= ~SWP_NOZORDER;
	/* XXX Overlay support might require something special here. */
      }

      /* Adjust the window rectangle because Win32 thinks that the x, y,
         width & height are the WHOLE window (including decorations),
         whereas GLUT treats the x, y, width & height as only the CLIENT
         area of the window.  Only do this to top level windows
         that are not in game mode (since game mode windows do
         not have any decorations). */
      if (!window->parent && window != __glutGameModeWindow) {
        AdjustWindowRect(&changes,
          WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
          FALSE);
      }

      /* Do the repositioning, moving, and push/pop. */
      SetWindowPos(window->win,
        window->desiredStack == Above ? HWND_TOP : HWND_NOTOPMOST,
        changes.left, changes.top,
        changes.right - changes.left, changes.bottom - changes.top,
        flags);

      /* Zero out the mask. */
      window->desiredConfMask = 0;

      /* This hack causes the window to go back to the right position
         when it is taken out of fullscreen mode. */
      if (workMask & GLUT_FULL_SCREEN_WORK) {
        window->desiredConfMask |= CWX | CWY;
        window->desiredX = point.x;
        window->desiredY = point.y;
      }
#else /* !_WIN32 */
      XWindowChanges changes;

      changes.x = window->desiredX;
      changes.y = window->desiredY;
      if (window->desiredConfMask & (CWWidth | CWHeight)) {
        changes.width = window->desiredWidth;
        changes.height = window->desiredHeight;
        if (window->overlay)
          XResizeWindow(__glutDisplay, window->overlay->win,
            window->desiredWidth, window->desiredHeight);
        if (__glutMotifHints != None) {
          if (workMask & GLUT_FULL_SCREEN_WORK) {
            MotifWmHints hints;

            hints.flags = MWM_HINTS_DECORATIONS;
            hints.decorations = 0;  /* Absolutely no
                                       decorations. */
            XChangeProperty(__glutDisplay, window->win,
              __glutMotifHints, __glutMotifHints, 32,
              PropModeReplace, (unsigned char *) &hints, 4);
            if (workMask & GLUT_MAP_WORK) {
              /* Handle case where glutFullScreen is called
                 before the first time that the window is
                 mapped. Some window managers will randomly or
                 interactively position the window the first
                 time it is mapped if the window's
                 WM_NORMAL_HINTS property does not request an
                 explicit position. We don't want any such
                 window manager interaction when going
                 fullscreen.  Overwrite the WM_NORMAL_HINTS
                 property installed by glutCreateWindow's
                 XSetWMProperties property with one explicitly
                 requesting a fullscreen window. */
              XSizeHints hints;

              hints.flags = USPosition | USSize;
              hints.x = 0;
              hints.y = 0;
              hints.width = window->desiredWidth;
              hints.height = window->desiredHeight;
              XSetWMNormalHints(__glutDisplay, window->win, &hints);
            }
          } else {
            XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
          }
        }
      }
      if (window->desiredConfMask & CWStackMode) {
        changes.stack_mode = window->desiredStack;
        /* Do not let glutPushWindow push window beneath the
           underlay. */
        if (window->parent && window->parent->overlay
          && window->desiredStack == Below) {
          changes.stack_mode = Above;
          changes.sibling = window->parent->overlay->win;
          window->desiredConfMask |= CWSibling;
        }
      }
      XConfigureWindow(__glutDisplay, window->win,
        window->desiredConfMask, &changes);
      window->desiredConfMask = 0;
#endif
    }
#if !defined(_WIN32)
    /* Be sure to establish the colormaps BEFORE map window is
       done. */
    if (workMask & GLUT_COLORMAP_WORK) {
      __glutEstablishColormapsProperty(window);
    }
#endif
    if (workMask & GLUT_MAP_WORK) {
      switch (window->desiredMapState) {
      case WithdrawnState:
        if (window->parent) {
          XUnmapWindow(__glutDisplay, window->win);
        } else {
          XWithdrawWindow(__glutDisplay, window->win,
            __glutScreen);
        }
        window->shownState = 0;
        break;
      case NormalState:
        XMapWindow(__glutDisplay, window->win);
        window->shownState = 1;
        break;
#ifdef _WIN32
      case GameModeState:  /* Not an Xlib value. */
        ShowWindow(window->win, SW_SHOW);
        window->shownState = 1;
        break;
#endif
      case IconicState:
        XIconifyWindow(__glutDisplay, window->win, __glutScreen);
        window->shownState = 0;
        break;
      }
    }
  }
  if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
    if (window->forceReshape) {
      /* Guarantee that before a display callback is generated
         for a window, a reshape callback must be generated. */
      __glutSetWindow(window);
      window->reshape(window->width, window->height);
      window->forceReshape = False;

      /* Setting the redisplay bit on the first reshape is
         necessary to make the "Mesa glXSwapBuffers to repair
         damage" hack operate correctly.  Without indicating a
         redisplay is necessary, there's not an initial back
         buffer render from which to blit from when damage
         happens to the window. */
      workMask |= GLUT_REDISPLAY_WORK;
    }
    /* The code below is more involved than otherwise necessary
       because it is paranoid about the overlay or entire window
       being removed or destroyed in the course of the callbacks.
       Notice how the global __glutWindowDamaged is used to record
       the layers' damage status.  See the code in glutLayerGet for
       how __glutWindowDamaged is used. The  point is to not have to
       update the "damaged" field after  the callback since the
       window (or overlay) may be destroyed (or removed) when the
       callback returns. */

    if (window->overlay && window->overlay->display) {
      int num = window->num;
      Window xid = window->overlay ? window->overlay->win : None;

      /* If an overlay display callback is registered, we
         differentiate between a redisplay needed for the
         overlay and/or normal plane.  If there is no overlay
         display callback registered, we simply use the
         standard display callback. */

      if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) {
        if (__glutMesaSwapHackSupport) {
          if (window->usedSwapBuffers) {
            if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
	      SWAP_BUFFERS_WINDOW(window);
              goto skippedDisplayCallback1;
            }
          }
        }
        /* Render to normal plane. */
#ifdef _WIN32
        window->renderDc = window->hdc;
#endif
        window->renderWin = window->win;
        window->renderCtx = window->ctx;
        __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK);
        __glutSetWindow(window);
        window->usedSwapBuffers = 0;
        window->display();
        __glutWindowDamaged = 0;

      skippedDisplayCallback1:;
      }
      if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
        window = __glutWindowList[num];
        if (window && window->overlay &&
          window->overlay->win == xid && window->overlay->display) {

          /* Render to overlay. */
#ifdef _WIN32
          window->renderDc = window->overlay->hdc;
#endif
          window->renderWin = window->overlay->win;
          window->renderCtx = window->overlay->ctx;
          __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK);
          __glutSetWindow(window);
          window->overlay->display();
          __glutWindowDamaged = 0;
        } else {
          /* Overlay may have since been destroyed or the
             overlay callback may have been disabled during
             normal display callback. */
        }
      }
    } else {
      if (__glutMesaSwapHackSupport) {
        if (!window->overlay && window->usedSwapBuffers) {
          if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
	    SWAP_BUFFERS_WINDOW(window);
            goto skippedDisplayCallback2;
          }
        }
      }
      /* Render to normal plane (and possibly overlay). */
      __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK));
      __glutSetWindow(window);
      window->usedSwapBuffers = 0;
      window->display();
      __glutWindowDamaged = 0;

    skippedDisplayCallback2:;
    }
  }
  /* Combine workMask with window->workMask to determine what
     finish and debug work there is. */
  workMask |= window->workMask;

  if (workMask & GLUT_FINISH_WORK) {
    /* Finish work makes sure a glFinish gets done to indirect
       rendering contexts.  Indirect contexts tend to have much 
       longer latency because lots of OpenGL extension requests 
       can queue up in the X protocol stream. __glutSetWindow
       is where the finish works gets queued for indirect
       contexts. */
    __glutSetWindow(window);
#if !defined(_WIN32)
    if (!window->isDirect)
#endif
    {
       glFinish();
    }
  }
  if (workMask & GLUT_DEBUG_WORK) {
    __glutSetWindow(window);
    glutReportErrors();
  }
  /* Strip out dummy, finish, and debug work bits. */
  window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
  if (window->workMask) {
    /* Leave on work list. */
    return window;
  } else {
    /* Remove current window from work list. */
    return window->prevWorkWin;
  }
}