1c041511dScube 2c041511dScube/* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1997, 1998. */ 3c041511dScube 4c041511dScube/* This program is freely distributable without licensing fees 5c041511dScube and is provided without guarantee or warrantee expressed or 6c041511dScube implied. This program is -not- in the public domain. */ 7c041511dScube 8c041511dScube#ifdef __VMS 9c041511dScube#include <GL/vms_x_fix.h> 10c041511dScube#endif 11c041511dScube 12c041511dScube#include <stdlib.h> 13c041511dScube#include <stdio.h> 14c041511dScube#include <errno.h> 15c041511dScube#include <assert.h> 16c041511dScube#include <string.h> /* Some FD_ZERO macros use memset without 17c041511dScube prototyping memset. */ 18c041511dScube 19c041511dScube/* Much of the following #ifdef logic to include the proper 20c041511dScube prototypes for the select system call is based on logic 21c041511dScube from the X11R6.3 version of <X11/Xpoll.h>. */ 22c041511dScube 23c041511dScube#if !defined(_WIN32) 24c041511dScube# ifdef __sgi 25c041511dScube# include <bstring.h> /* prototype for bzero used by FD_ZERO */ 26c041511dScube# endif 27c041511dScube# if (defined(__FreeBSD__) || defined(SVR4) || defined(CRAY) || defined(AIXV3)) && !defined(FD_SETSIZE) 28c041511dScube# include <sys/select.h> /* select system call interface */ 29c041511dScube# ifdef luna 30c041511dScube# include <sysent.h> 31c041511dScube# endif 32c041511dScube# endif 33c041511dScube /* AIX 4.2 fubar-ed <sys/select.h>, so go to heroic measures to get it */ 34c041511dScube# if defined(AIXV4) && !defined(NFDBITS) 35c041511dScube# include <sys/select.h> 36c041511dScube# endif 37c041511dScube#endif /* !_WIN32 */ 38c041511dScube 39c041511dScube#include <sys/types.h> 40c041511dScube 41c041511dScube#if !defined(_WIN32) 42c041511dScube# if defined(__vms) && ( __VMS_VER < 70000000 ) 43c041511dScube# include <sys/time.h> 44c041511dScube# else 45c041511dScube# ifndef __vms 46c041511dScube# include <sys/time.h> 47c041511dScube# endif 48c041511dScube# endif 49c041511dScube# include <unistd.h> 50c041511dScube# include <X11/Xlib.h> 51c041511dScube# include <X11/keysym.h> 52c041511dScube#else 53c041511dScube# ifdef __CYGWIN32__ 54c041511dScube# include <sys/time.h> 55c041511dScube# else 56c041511dScube# include <sys/timeb.h> 57c041511dScube# endif 58c041511dScube# ifdef __hpux 59c041511dScube /* XXX Bert Gijsbers <bert@mc.bio.uva.nl> reports that HP-UX 60c041511dScube needs different keysyms for the End, Insert, and Delete keys 61c041511dScube to work on an HP 715. It would be better if HP generated 62c041511dScube standard keysyms for standard keys. */ 63c041511dScube# include <X11/HPkeysym.h> 64c041511dScube# endif 65c041511dScube#endif /* !_WIN32 */ 66c041511dScube 67c041511dScube#include "glutint.h" 68c041511dScube 69c041511dScube#if defined(__vms) && ( __VMS_VER < 70000000 ) 70c041511dScube#include <ssdef.h> 71c041511dScube#include <psldef.h> 72c041511dScubeextern int SYS$CLREF(int efn); 73c041511dScubeextern int SYS$SETIMR(unsigned int efn, struct timeval6 *timeout, void *ast, 74c041511dScube unsigned int request_id, unsigned int flags); 75c041511dScubeextern int SYS$WFLOR(unsigned int efn, unsigned int mask); 76c041511dScubeextern int SYS$CANTIM(unsigned int request_id, unsigned int mode); 77c041511dScube#endif /* __vms, VMs 6.2 or earlier */ 78c041511dScube 79c041511dScubestatic GLUTtimer *freeTimerList = NULL; 80c041511dScube 81c041511dScubeGLUTidleCB __glutIdleFunc = NULL; 82c041511dScubeGLUTtimer *__glutTimerList = NULL; 83c041511dScube#ifdef SUPPORT_FORTRAN 84c041511dScubeGLUTtimer *__glutNewTimer; 85c041511dScube#endif 86c041511dScubeGLUTwindow *__glutWindowWorkList = NULL; 87c041511dScubeGLUTmenu *__glutMappedMenu; 88c041511dScubeGLUTmenu *__glutCurrentMenu = NULL; 89c041511dScube 90c041511dScubevoid (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *); 91c041511dScube#if !defined(_WIN32) 92c041511dScubevoid (*__glutMenuItemEnterOrLeave)(GLUTmenuItem * item, int num, int type) = NULL; 93c041511dScubevoid (*__glutFinishMenu)(Window win, int x, int y); 94c041511dScubevoid (*__glutPaintMenu)(GLUTmenu * menu); 95c041511dScubevoid (*__glutStartMenu)(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win); 96c041511dScubeGLUTmenu * (*__glutGetMenuByNum)(int menunum); 97c041511dScubeGLUTmenuItem * (*__glutGetMenuItem)(GLUTmenu * menu, Window win, int *which); 98c041511dScubeGLUTmenu * (*__glutGetMenu)(Window win); 99c041511dScube#endif 100c041511dScube 101c041511dScubeAtom __glutMotifHints = None; 102c041511dScube/* Modifier mask of ~0 implies not in core input callback. */ 103c041511dScubeunsigned int __glutModifierMask = (unsigned int) ~0; 104c041511dScubeint __glutWindowDamaged = 0; 105c041511dScube 106c041511dScubevoid GLUTAPIENTRY 107c041511dScubeglutIdleFunc(GLUTidleCB idleFunc) 108c041511dScube{ 109c041511dScube __glutIdleFunc = idleFunc; 110c041511dScube} 111c041511dScube 112c041511dScubevoid GLUTAPIENTRY 113c041511dScubeglutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value) 114c041511dScube{ 115c041511dScube GLUTtimer *timer, *other; 116c041511dScube GLUTtimer **prevptr; 117c041511dScube#ifdef OLD_VMS 118c041511dScube struct timeval6 now; 119c041511dScube#else 120c041511dScube struct timeval now; 121c041511dScube#endif 122c041511dScube 123c041511dScube if (!timerFunc) 124c041511dScube return; 125c041511dScube 126c041511dScube if (freeTimerList) { 127c041511dScube timer = freeTimerList; 128c041511dScube freeTimerList = timer->next; 129c041511dScube } else { 130c041511dScube timer = (GLUTtimer *) malloc(sizeof(GLUTtimer)); 131c041511dScube if (!timer) 132c041511dScube __glutFatalError("out of memory."); 133c041511dScube } 134c041511dScube 135c041511dScube timer->func = timerFunc; 136c041511dScube#if defined(__vms) && ( __VMS_VER < 70000000 ) 137c041511dScube /* VMS time is expressed in units of 100 ns */ 138c041511dScube timer->timeout.val = interval * TICKS_PER_MILLISECOND; 139c041511dScube#else 140c041511dScube timer->timeout.tv_sec = (int) interval / 1000; 141c041511dScube timer->timeout.tv_usec = (int) (interval % 1000) * 1000; 142c041511dScube#endif 143c041511dScube timer->value = value; 144c041511dScube timer->next = NULL; 145c041511dScube GETTIMEOFDAY(&now); 146c041511dScube ADD_TIME(timer->timeout, timer->timeout, now); 147c041511dScube prevptr = &__glutTimerList; 148c041511dScube other = *prevptr; 149c041511dScube while (other && IS_AFTER(other->timeout, timer->timeout)) { 150c041511dScube prevptr = &other->next; 151c041511dScube other = *prevptr; 152c041511dScube } 153c041511dScube timer->next = other; 154c041511dScube#ifdef SUPPORT_FORTRAN 155c041511dScube __glutNewTimer = timer; /* for Fortran binding! */ 156c041511dScube#endif 157c041511dScube *prevptr = timer; 158c041511dScube} 159c041511dScube 160c041511dScubevoid 161c041511dScubehandleTimeouts(void) 162c041511dScube{ 163c041511dScube#ifdef OLD_VMS 164c041511dScube struct timeval6 now; 165c041511dScube#else 166c041511dScube struct timeval now; 167c041511dScube#endif 168c041511dScube GLUTtimer *timer; 169c041511dScube 170c041511dScube /* Assumption is that __glutTimerList is already determined 171c041511dScube to be non-NULL. */ 172c041511dScube GETTIMEOFDAY(&now); 173c041511dScube while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) { 174c041511dScube timer = __glutTimerList; 175c041511dScube /* call the timer function */ 176c041511dScube timer->func(timer->value); 177c041511dScube /* remove from the linked list */ 178c041511dScube __glutTimerList = timer->next; 179c041511dScube /* put this timer on the "free" list */ 180c041511dScube timer->next = freeTimerList; 181c041511dScube freeTimerList = timer; 182c041511dScube 183c041511dScube if (!__glutTimerList) 184c041511dScube break; 185c041511dScube } 186c041511dScube} 187c041511dScube 188c041511dScubevoid 189c041511dScube__glutPutOnWorkList(GLUTwindow * window, int workMask) 190c041511dScube{ 191c041511dScube if (window->workMask) { 192c041511dScube /* Already on list; just OR in new workMask. */ 193c041511dScube window->workMask |= workMask; 194c041511dScube } else { 195c041511dScube /* Update work mask and add to window work list. */ 196c041511dScube window->workMask = workMask; 197c041511dScube /* Assert that if the window does not have a 198c041511dScube workMask already, the window should definitely 199c041511dScube not be the head of the work list. */ 200c041511dScube assert(window != __glutWindowWorkList); 201c041511dScube window->prevWorkWin = __glutWindowWorkList; 202c041511dScube __glutWindowWorkList = window; 203c041511dScube } 204c041511dScube} 205c041511dScube 206c041511dScubevoid 207c041511dScube__glutPostRedisplay(GLUTwindow * window, int layerMask) 208c041511dScube{ 209c041511dScube int shown = (layerMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) ? 210c041511dScube window->shownState : window->overlay->shownState; 211c041511dScube 212c041511dScube /* Post a redisplay if the window is visible (or the 213c041511dScube visibility of the window is unknown, ie. window->visState 214c041511dScube == -1) _and_ the layer is known to be shown. */ 215c041511dScube if (window->visState != GLUT_HIDDEN 216c041511dScube && window->visState != GLUT_FULLY_COVERED && shown) { 217c041511dScube __glutPutOnWorkList(window, layerMask); 218c041511dScube } 219c041511dScube} 220c041511dScube 221c041511dScube/* CENTRY */ 222c041511dScubevoid GLUTAPIENTRY 223c041511dScubeglutPostRedisplay(void) 224c041511dScube{ 225c041511dScube __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK); 226c041511dScube} 227c041511dScube 228c041511dScube/* The advantage of this routine is that it saves the cost of a 229c041511dScube glutSetWindow call (entailing an expensive OpenGL context switch), 230c041511dScube particularly useful when multiple windows need redisplays posted at 231c041511dScube the same times. See also glutPostWindowOverlayRedisplay. */ 232c041511dScubevoid GLUTAPIENTRY 233c041511dScubeglutPostWindowRedisplay(int win) 234c041511dScube{ 235c041511dScube __glutPostRedisplay(__glutWindowList[win - 1], GLUT_REDISPLAY_WORK); 236c041511dScube} 237c041511dScube 238c041511dScube/* ENDCENTRY */ 239c041511dScubestatic GLUTeventParser *eventParserList = NULL; 240c041511dScube 241c041511dScube/* __glutRegisterEventParser allows another module to register 242c041511dScube to intercept X events types not otherwise acted on by the 243c041511dScube GLUT processEventsAndTimeouts routine. The X Input 244c041511dScube extension support code uses an event parser for handling X 245c041511dScube Input extension events. */ 246c041511dScube 247c041511dScubevoid 248c041511dScube__glutRegisterEventParser(GLUTeventParser * parser) 249c041511dScube{ 250c041511dScube parser->next = eventParserList; 251c041511dScube eventParserList = parser; 252c041511dScube} 253c041511dScube 254c041511dScubestatic void 255c041511dScubemarkWindowHidden(GLUTwindow * window) 256c041511dScube{ 257c041511dScube if (GLUT_HIDDEN != window->visState) { 258c041511dScube GLUTwindow *child; 259c041511dScube 260c041511dScube if (window->windowStatus) { 261c041511dScube window->visState = GLUT_HIDDEN; 262c041511dScube __glutSetWindow(window); 263c041511dScube window->windowStatus(GLUT_HIDDEN); 264c041511dScube } 265c041511dScube /* An unmap is only reported on a single window; its 266c041511dScube descendents need to know they are no longer visible. */ 267c041511dScube child = window->children; 268c041511dScube while (child) { 269c041511dScube markWindowHidden(child); 270c041511dScube child = child->siblings; 271c041511dScube } 272c041511dScube } 273c041511dScube} 274c041511dScube 275c041511dScube#if !defined(_WIN32) 276c041511dScube 277c041511dScubestatic void 278c041511dScubepurgeStaleWindow(Window win) 279c041511dScube{ 280c041511dScube GLUTstale **pEntry = &__glutStaleWindowList; 281c041511dScube GLUTstale *entry = __glutStaleWindowList; 282c041511dScube 283c041511dScube /* Tranverse singly-linked stale window list look for the 284c041511dScube window ID. */ 285c041511dScube while (entry) { 286c041511dScube if (entry->win == win) { 287c041511dScube /* Found it; delete it. */ 288c041511dScube *pEntry = entry->next; 289c041511dScube free(entry); 290c041511dScube return; 291c041511dScube } else { 292c041511dScube pEntry = &entry->next; 293c041511dScube entry = *pEntry; 294c041511dScube } 295c041511dScube } 296c041511dScube} 297c041511dScube 298c041511dScube/* Unlike XNextEvent, if a signal arrives, 299c041511dScube interruptibleXNextEvent will return (with a zero return 300c041511dScube value). This helps GLUT drop out of XNextEvent if a signal 301c041511dScube is delivered. The intent is so that a GLUT program can call 302c041511dScube glutIdleFunc in a signal handler to register an idle func 303c041511dScube and then immediately get dropped into the idle func (after 304c041511dScube returning from the signal handler). The idea is to make 305c041511dScube GLUT's main loop reliably interruptible by signals. */ 306c041511dScubestatic int 307c041511dScubeinterruptibleXNextEvent(Display * dpy, XEvent * event) 308c041511dScube{ 309c041511dScube fd_set fds; 310c041511dScube int rc; 311c041511dScube 312c041511dScube /* Flush X protocol since XPending does not do this 313c041511dScube implicitly. */ 314c041511dScube XFlush(__glutDisplay); 315c041511dScube for (;;) { 316c041511dScube if (XPending(__glutDisplay)) { 317c041511dScube XNextEvent(dpy, event); 318c041511dScube return 1; 319c041511dScube } 320c041511dScube#ifndef VMS 321c041511dScube /* the combination ConectionNumber-select is buggy on VMS. Sometimes it 322c041511dScube * fails. This part of the code hangs the program on VMS7.2. But even 323c041511dScube * without it the program seems to run correctly. 324c041511dScube * Note that this is a bug in the VMS/DECWindows run-time-libraries. 325c041511dScube * Compaq engeneering does not want or is not able to make a fix. 326c041511dScube * (last sentence is a quotation from Compaq when I reported the 327c041511dScube * problem January 2000) */ 328c041511dScube FD_ZERO(&fds); 329c041511dScube FD_SET(__glutConnectionFD, &fds); 330c041511dScube rc = select(__glutConnectionFD + 1, &fds, NULL, NULL, NULL); 331c041511dScube if (rc < 0) { 332c041511dScube if (errno == EINTR) { 333c041511dScube return 0; 334c041511dScube } else { 335c041511dScube __glutFatalError("select error."); 336c041511dScube } 337c041511dScube } 338c041511dScube#endif 339c041511dScube } 340c041511dScube} 341c041511dScube 342c041511dScube#endif 343c041511dScube 344c041511dScubestatic void 345c041511dScubeprocessEventsAndTimeouts(void) 346c041511dScube{ 347c041511dScube do { 348c041511dScube#if defined(_WIN32) 349c041511dScube MSG event; 350c041511dScube 351c041511dScube if(!GetMessage(&event, NULL, 0, 0)) /* bail if no more messages */ 352c041511dScube exit(0); 353c041511dScube TranslateMessage(&event); /* translate virtual-key messages */ 354c041511dScube DispatchMessage(&event); /* call the window proc */ 355c041511dScube /* see win32_event.c for event (message) processing procedures */ 356c041511dScube#else 357c041511dScube static int mappedMenuButton; 358c041511dScube GLUTeventParser *parser; 359c041511dScube XEvent event, ahead; 360c041511dScube GLUTwindow *window; 361c041511dScube GLUTkeyboardCB keyboard; 362c041511dScube GLUTspecialCB special; 363c041511dScube int gotEvent, width, height; 364c041511dScube 365c041511dScube gotEvent = interruptibleXNextEvent(__glutDisplay, &event); 366c041511dScube if (gotEvent) { 367c041511dScube switch (event.type) { 368c041511dScube case MappingNotify: 369c041511dScube XRefreshKeyboardMapping((XMappingEvent *) & event); 370c041511dScube break; 371c041511dScube case ConfigureNotify: 372c041511dScube window = __glutGetWindow(event.xconfigure.window); 373c041511dScube if (window) { 374c041511dScube if (window->win != event.xconfigure.window) { 375c041511dScube /* Ignore ConfigureNotify sent to the overlay 376c041511dScube planes. GLUT could get here because overlays 377c041511dScube select for StructureNotify events to receive 378c041511dScube DestroyNotify. */ 379c041511dScube break; 380c041511dScube } 381c041511dScube width = event.xconfigure.width; 382c041511dScube height = event.xconfigure.height; 383c041511dScube if (width != window->width || height != window->height) { 384c041511dScube if (window->overlay) { 385c041511dScube XResizeWindow(__glutDisplay, window->overlay->win, width, height); 386c041511dScube } 387c041511dScube window->width = width; 388c041511dScube window->height = height; 389c041511dScube __glutSetWindow(window); 390c041511dScube /* Do not execute OpenGL out of sequence with 391c041511dScube respect to the XResizeWindow request! */ 392c041511dScube glXWaitX(); 393c041511dScube window->reshape(width, height); 394c041511dScube window->forceReshape = False; 395c041511dScube /* A reshape should be considered like posting a 396c041511dScube repair; this is necessary for the "Mesa 397c041511dScube glXSwapBuffers to repair damage" hack to operate 398c041511dScube correctly. Without it, there's not an initial 399c041511dScube back buffer render from which to blit from when 400c041511dScube damage happens to the window. */ 401c041511dScube __glutPostRedisplay(window, GLUT_REPAIR_WORK); 402c041511dScube } 403c041511dScube } 404c041511dScube break; 405c041511dScube case Expose: 406c041511dScube /* compress expose events */ 407c041511dScube while (XEventsQueued(__glutDisplay, QueuedAfterReading) 408c041511dScube > 0) { 409c041511dScube XPeekEvent(__glutDisplay, &ahead); 410c041511dScube if (ahead.type != Expose || 411c041511dScube ahead.xexpose.window != event.xexpose.window) { 412c041511dScube break; 413c041511dScube } 414c041511dScube XNextEvent(__glutDisplay, &event); 415c041511dScube } 416c041511dScube if (event.xexpose.count == 0) { 417c041511dScube GLUTmenu *menu; 418c041511dScube 419c041511dScube if (__glutMappedMenu && 420c041511dScube (menu = __glutGetMenu(event.xexpose.window))) { 421c041511dScube __glutPaintMenu(menu); 422c041511dScube } else { 423c041511dScube window = __glutGetWindow(event.xexpose.window); 424c041511dScube if (window) { 425c041511dScube if (window->win == event.xexpose.window) { 426c041511dScube __glutPostRedisplay(window, GLUT_REPAIR_WORK); 427c041511dScube } else if (window->overlay && window->overlay->win == event.xexpose.window) { 428c041511dScube __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK); 429c041511dScube } 430c041511dScube } 431c041511dScube } 432c041511dScube } else { 433c041511dScube /* there are more exposes to read; wait to redisplay */ 434c041511dScube } 435c041511dScube break; 436c041511dScube case ButtonPress: 437c041511dScube case ButtonRelease: 438c041511dScube if (__glutMappedMenu && event.type == ButtonRelease 439c041511dScube && mappedMenuButton == event.xbutton.button) { 440c041511dScube /* Menu is currently popped up and its button is 441c041511dScube released. */ 442c041511dScube __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y); 443c041511dScube } else { 444c041511dScube window = __glutGetWindow(event.xbutton.window); 445c041511dScube /* added button check for mice with > 3 buttons */ 446c041511dScube if (window) { 447c041511dScube GLUTmenu *menu; 448c041511dScube int menuNum; 449c041511dScube 450c041511dScube if (event.xbutton.button <= GLUT_MAX_MENUS) 451c041511dScube menuNum = window->menu[event.xbutton.button - 1]; 452c041511dScube else 453c041511dScube menuNum = 0; 454c041511dScube 455c041511dScube /* Make sure that __glutGetMenuByNum is only called if there 456c041511dScube really is a menu present. */ 457c041511dScube if ((menuNum > 0) && (menu = __glutGetMenuByNum(menuNum))) { 458c041511dScube if (event.type == ButtonPress && !__glutMappedMenu) { 459c041511dScube __glutStartMenu(menu, window, 460c041511dScube event.xbutton.x_root, event.xbutton.y_root, 461c041511dScube event.xbutton.x, event.xbutton.y); 462c041511dScube mappedMenuButton = event.xbutton.button; 463c041511dScube } else { 464c041511dScube /* Ignore a release of a button with a menu 465c041511dScube attatched to it when no menu is popped up, 466c041511dScube or ignore a press when another menu is 467c041511dScube already popped up. */ 468c041511dScube } 469c041511dScube } else if (window->mouse) { 470c041511dScube __glutSetWindow(window); 471c041511dScube __glutModifierMask = event.xbutton.state; 472c041511dScube window->mouse(event.xbutton.button - 1, 473c041511dScube event.type == ButtonRelease ? 474c041511dScube GLUT_UP : GLUT_DOWN, 475c041511dScube event.xbutton.x, event.xbutton.y); 476c041511dScube __glutModifierMask = ~0; 477c041511dScube } else { 478c041511dScube /* Stray mouse events. Ignore. */ 479c041511dScube } 480c041511dScube } else { 481c041511dScube /* Window might have been destroyed and all the 482c041511dScube events for the window may not yet be received. */ 483c041511dScube } 484c041511dScube } 485c041511dScube break; 486c041511dScube case MotionNotify: 487c041511dScube if (!__glutMappedMenu) { 488c041511dScube window = __glutGetWindow(event.xmotion.window); 489c041511dScube if (window) { 490c041511dScube /* If motion function registered _and_ buttons held 491c041511dScube * down, call motion function... */ 492c041511dScube if (window->motion && event.xmotion.state & 493c041511dScube (Button1Mask | Button2Mask | Button3Mask)) { 494c041511dScube __glutSetWindow(window); 495c041511dScube window->motion(event.xmotion.x, event.xmotion.y); 496c041511dScube } 497c041511dScube /* If passive motion function registered _and_ 498c041511dScube buttons not held down, call passive motion 499c041511dScube function... */ 500c041511dScube else if (window->passive && 501c041511dScube ((event.xmotion.state & 502c041511dScube (Button1Mask | Button2Mask | Button3Mask)) == 503c041511dScube 0)) { 504c041511dScube __glutSetWindow(window); 505c041511dScube window->passive(event.xmotion.x, 506c041511dScube event.xmotion.y); 507c041511dScube } 508c041511dScube } 509c041511dScube } else { 510c041511dScube /* Motion events are thrown away when a pop up menu 511c041511dScube is active. */ 512c041511dScube } 513c041511dScube break; 514c041511dScube case KeyPress: 515c041511dScube case KeyRelease: 516c041511dScube window = __glutGetWindow(event.xkey.window); 517c041511dScube if (!window) { 518c041511dScube break; 519c041511dScube } 520c041511dScube if (event.type == KeyPress) { 521c041511dScube keyboard = window->keyboard; 522c041511dScube } else { 523c041511dScube 524c041511dScube /* If we are ignoring auto repeated keys for this window, 525c041511dScube check if the next event in the X event queue is a KeyPress 526c041511dScube for the exact same key (and at the exact same time) as the 527c041511dScube key being released. The X11 protocol will send auto 528c041511dScube repeated keys as such KeyRelease/KeyPress pairs. */ 529c041511dScube 530c041511dScube if (window->ignoreKeyRepeat) { 531c041511dScube if (XEventsQueued(__glutDisplay, QueuedAfterReading)) { 532c041511dScube XPeekEvent(__glutDisplay, &ahead); 533c041511dScube if (ahead.type == KeyPress 534c041511dScube && ahead.xkey.window == event.xkey.window 535c041511dScube && ahead.xkey.keycode == event.xkey.keycode 536c041511dScube && ahead.xkey.time == event.xkey.time) { 537c041511dScube /* Pop off the repeated KeyPress and ignore 538c041511dScube the auto repeated KeyRelease/KeyPress pair. */ 539c041511dScube XNextEvent(__glutDisplay, &event); 540c041511dScube break; 541c041511dScube } 542c041511dScube } 543c041511dScube } 544c041511dScube keyboard = window->keyboardUp; 545c041511dScube } 546c041511dScube if (keyboard) { 547c041511dScube char tmp[1]; 548c041511dScube int rc; 549c041511dScube 550c041511dScube rc = XLookupString(&event.xkey, tmp, sizeof(tmp), 551c041511dScube NULL, NULL); 552c041511dScube if (rc) { 553c041511dScube __glutSetWindow(window); 554c041511dScube __glutModifierMask = event.xkey.state; 555c041511dScube keyboard(tmp[0], 556c041511dScube event.xkey.x, event.xkey.y); 557c041511dScube __glutModifierMask = ~0; 558c041511dScube break; 559c041511dScube } 560c041511dScube } 561c041511dScube if (event.type == KeyPress) { 562c041511dScube special = window->special; 563c041511dScube } else { 564c041511dScube special = window->specialUp; 565c041511dScube } 566c041511dScube if (special) { 567c041511dScube KeySym ks; 568c041511dScube int key; 569c041511dScube 570c041511dScube/* Introduced in X11R6: (Partial list of) Keypad Functions. Define 571c041511dScube in place in case compiling against an older pre-X11R6 572c041511dScube X11/keysymdef.h file. */ 573c041511dScube#ifndef XK_KP_Home 574c041511dScube#define XK_KP_Home 0xFF95 575c041511dScube#endif 576c041511dScube#ifndef XK_KP_Left 577c041511dScube#define XK_KP_Left 0xFF96 578c041511dScube#endif 579c041511dScube#ifndef XK_KP_Up 580c041511dScube#define XK_KP_Up 0xFF97 581c041511dScube#endif 582c041511dScube#ifndef XK_KP_Right 583c041511dScube#define XK_KP_Right 0xFF98 584c041511dScube#endif 585c041511dScube#ifndef XK_KP_Down 586c041511dScube#define XK_KP_Down 0xFF99 587c041511dScube#endif 588c041511dScube#ifndef XK_KP_Prior 589c041511dScube#define XK_KP_Prior 0xFF9A 590c041511dScube#endif 591c041511dScube#ifndef XK_KP_Next 592c041511dScube#define XK_KP_Next 0xFF9B 593c041511dScube#endif 594c041511dScube#ifndef XK_KP_End 595c041511dScube#define XK_KP_End 0xFF9C 596c041511dScube#endif 597c041511dScube#ifndef XK_KP_Insert 598c041511dScube#define XK_KP_Insert 0xFF9E 599c041511dScube#endif 600c041511dScube#ifndef XK_KP_Delete 601c041511dScube#define XK_KP_Delete 0xFF9F 602c041511dScube#endif 603c041511dScube 604c041511dScube ks = XLookupKeysym((XKeyEvent *) & event, 0); 605c041511dScube /* XXX Verbose, but makes no assumptions about keysym 606c041511dScube layout. */ 607c041511dScube switch (ks) { 608c041511dScube/* *INDENT-OFF* */ 609c041511dScube /* function keys */ 610c041511dScube case XK_F1: key = GLUT_KEY_F1; break; 611c041511dScube case XK_F2: key = GLUT_KEY_F2; break; 612c041511dScube case XK_F3: key = GLUT_KEY_F3; break; 613c041511dScube case XK_F4: key = GLUT_KEY_F4; break; 614c041511dScube case XK_F5: key = GLUT_KEY_F5; break; 615c041511dScube case XK_F6: key = GLUT_KEY_F6; break; 616c041511dScube case XK_F7: key = GLUT_KEY_F7; break; 617c041511dScube case XK_F8: key = GLUT_KEY_F8; break; 618c041511dScube case XK_F9: key = GLUT_KEY_F9; break; 619c041511dScube case XK_F10: key = GLUT_KEY_F10; break; 620c041511dScube case XK_F11: key = GLUT_KEY_F11; break; 621c041511dScube case XK_F12: key = GLUT_KEY_F12; break; 622c041511dScube /* directional keys */ 623c041511dScube case XK_KP_Left: 624c041511dScube case XK_Left: key = GLUT_KEY_LEFT; break; 625c041511dScube case XK_KP_Up: /* Introduced in X11R6. */ 626c041511dScube case XK_Up: key = GLUT_KEY_UP; break; 627c041511dScube case XK_KP_Right: /* Introduced in X11R6. */ 628c041511dScube case XK_Right: key = GLUT_KEY_RIGHT; break; 629c041511dScube case XK_KP_Down: /* Introduced in X11R6. */ 630c041511dScube case XK_Down: key = GLUT_KEY_DOWN; break; 631c041511dScube/* *INDENT-ON* */ 632c041511dScube 633c041511dScube case XK_KP_Prior: /* Introduced in X11R6. */ 634c041511dScube case XK_Prior: 635c041511dScube /* XK_Prior same as X11R6's XK_Page_Up */ 636c041511dScube key = GLUT_KEY_PAGE_UP; 637c041511dScube break; 638c041511dScube case XK_KP_Next: /* Introduced in X11R6. */ 639c041511dScube case XK_Next: 640c041511dScube /* XK_Next same as X11R6's XK_Page_Down */ 641c041511dScube key = GLUT_KEY_PAGE_DOWN; 642c041511dScube break; 643c041511dScube case XK_KP_Home: /* Introduced in X11R6. */ 644c041511dScube case XK_Home: 645c041511dScube key = GLUT_KEY_HOME; 646c041511dScube break; 647c041511dScube#ifdef __hpux 648c041511dScube case XK_Select: 649c041511dScube#endif 650c041511dScube case XK_KP_End: /* Introduced in X11R6. */ 651c041511dScube case XK_End: 652c041511dScube key = GLUT_KEY_END; 653c041511dScube break; 654c041511dScube#ifdef __hpux 655c041511dScube case XK_InsertChar: 656c041511dScube#endif 657c041511dScube case XK_KP_Insert: /* Introduced in X11R6. */ 658c041511dScube case XK_Insert: 659c041511dScube key = GLUT_KEY_INSERT; 660c041511dScube break; 661c041511dScube#ifdef __hpux 662c041511dScube case XK_DeleteChar: 663c041511dScube#endif 664c041511dScube case XK_KP_Delete: /* Introduced in X11R6. */ 665c041511dScube /* The Delete character is really an ASCII key. */ 666c041511dScube __glutSetWindow(window); 667553f1899Smrg assert(keyboard); 668c041511dScube keyboard(127, /* ASCII Delete character. */ 669c041511dScube event.xkey.x, event.xkey.y); 670c041511dScube goto skip; 671c041511dScube default: 672c041511dScube goto skip; 673c041511dScube } 674c041511dScube __glutSetWindow(window); 675c041511dScube __glutModifierMask = event.xkey.state; 676c041511dScube special(key, event.xkey.x, event.xkey.y); 677c041511dScube __glutModifierMask = ~0; 678c041511dScube skip:; 679c041511dScube } 680c041511dScube break; 681c041511dScube case EnterNotify: 682c041511dScube case LeaveNotify: 683c041511dScube if (event.xcrossing.mode != NotifyNormal || 684c041511dScube event.xcrossing.detail == NotifyNonlinearVirtual || 685c041511dScube event.xcrossing.detail == NotifyVirtual) { 686c041511dScube 687c041511dScube /* Careful to ignore Enter/LeaveNotify events that 688c041511dScube come from the pop-up menu pointer grab and ungrab. 689c041511dScube Also, ignore "virtual" Enter/LeaveNotify events 690c041511dScube since they represent the pointer passing through 691c041511dScube the window hierarchy without actually entering or 692c041511dScube leaving the actual real estate of a window. */ 693c041511dScube 694c041511dScube break; 695c041511dScube } 696c041511dScube if (__glutMappedMenu) { 697c041511dScube GLUTmenuItem *item; 698c041511dScube int num; 699c041511dScube 700c041511dScube item = __glutGetMenuItem(__glutMappedMenu, 701c041511dScube event.xcrossing.window, &num); 702c041511dScube if (item) { 703c041511dScube __glutMenuItemEnterOrLeave(item, num, event.type); 704c041511dScube break; 705c041511dScube } 706c041511dScube } 707c041511dScube window = __glutGetWindow(event.xcrossing.window); 708c041511dScube if (window) { 709c041511dScube if (window->entry) { 710c041511dScube if (event.type == EnterNotify) { 711c041511dScube 712c041511dScube /* With overlays established, X can report two 713c041511dScube enter events for both the overlay and normal 714c041511dScube plane window. Do not generate a second enter 715c041511dScube callback if we reported one without an 716c041511dScube intervening leave. */ 717c041511dScube 718c041511dScube if (window->entryState != EnterNotify) { 719c041511dScube int num = window->num; 720c041511dScube Window xid = window->win; 721c041511dScube 722c041511dScube window->entryState = EnterNotify; 723c041511dScube __glutSetWindow(window); 724c041511dScube window->entry(GLUT_ENTERED); 725c041511dScube 726c041511dScube if (__glutMappedMenu) { 727c041511dScube 728c041511dScube /* Do not generate any passive motion events 729c041511dScube when menus are in use. */ 730c041511dScube 731c041511dScube } else { 732c041511dScube 733c041511dScube /* An EnterNotify event can result in a 734c041511dScube "compound" callback if a passive motion 735c041511dScube callback is also registered. In this case, 736c041511dScube be a little paranoid about the possibility 737c041511dScube the window could have been destroyed in the 738c041511dScube entry callback. */ 739c041511dScube 740c041511dScube window = __glutWindowList[num]; 741c041511dScube if (window && window->passive && window->win == xid) { 742c041511dScube __glutSetWindow(window); 743c041511dScube window->passive(event.xcrossing.x, event.xcrossing.y); 744c041511dScube } 745c041511dScube } 746c041511dScube } 747c041511dScube } else { 748c041511dScube if (window->entryState != LeaveNotify) { 749c041511dScube 750c041511dScube /* When an overlay is established for a window 751c041511dScube already mapped and with the pointer in it, 752c041511dScube the X server will generate a leave/enter 753c041511dScube event pair as the pointer leaves (without 754c041511dScube moving) from the normal plane X window to 755c041511dScube the newly mapped overlay X window (or vice 756c041511dScube versa). This enter/leave pair should not be 757c041511dScube reported to the GLUT program since the pair 758c041511dScube is a consequence of creating (or destroying) 759c041511dScube the overlay, not an actual leave from the 760c041511dScube GLUT window. */ 761c041511dScube 762c041511dScube if (XEventsQueued(__glutDisplay, QueuedAfterReading)) { 763c041511dScube XPeekEvent(__glutDisplay, &ahead); 764c041511dScube if (ahead.type == EnterNotify && 765c041511dScube __glutGetWindow(ahead.xcrossing.window) == window) { 766c041511dScube XNextEvent(__glutDisplay, &event); 767c041511dScube break; 768c041511dScube } 769c041511dScube } 770c041511dScube window->entryState = LeaveNotify; 771c041511dScube __glutSetWindow(window); 772c041511dScube window->entry(GLUT_LEFT); 773c041511dScube } 774c041511dScube } 775c041511dScube } else if (window->passive) { 776c041511dScube __glutSetWindow(window); 777c041511dScube window->passive(event.xcrossing.x, event.xcrossing.y); 778c041511dScube } 779c041511dScube } 780c041511dScube break; 781c041511dScube case UnmapNotify: 782c041511dScube /* MapNotify events are not needed to maintain 783c041511dScube visibility state since VisibilityNotify events will 784c041511dScube be delivered when a window becomes visible from 785c041511dScube mapping. However, VisibilityNotify events are not 786c041511dScube delivered when a window is unmapped (for the window 787c041511dScube or its children). */ 788c041511dScube window = __glutGetWindow(event.xunmap.window); 789c041511dScube if (window) { 790c041511dScube if (window->win != event.xconfigure.window) { 791c041511dScube /* Ignore UnmapNotify sent to the overlay planes. 792c041511dScube GLUT could get here because overlays select for 793c041511dScube StructureNotify events to receive DestroyNotify. 794c041511dScube */ 795c041511dScube break; 796c041511dScube } 797c041511dScube markWindowHidden(window); 798c041511dScube } 799c041511dScube break; 800c041511dScube case VisibilityNotify: 801c041511dScube window = __glutGetWindow(event.xvisibility.window); 802c041511dScube if (window) { 803c041511dScube /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED, 804c041511dScube VisibilityPartiallyObscured+1 = 805c041511dScube GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1 806c041511dScube = GLUT_FULLY_COVERED. */ 807c041511dScube int visState = event.xvisibility.state + 1; 808c041511dScube 809c041511dScube if (visState != window->visState) { 810c041511dScube if (window->windowStatus) { 811c041511dScube window->visState = visState; 812c041511dScube __glutSetWindow(window); 813c041511dScube window->windowStatus(visState); 814c041511dScube } 815c041511dScube } 816c041511dScube } 817c041511dScube break; 818c041511dScube case ClientMessage: 819c041511dScube if (event.xclient.data.l[0] == __glutWMDeleteWindow) 820c041511dScube exit(0); 821c041511dScube break; 822c041511dScube case DestroyNotify: 823c041511dScube purgeStaleWindow(event.xdestroywindow.window); 824c041511dScube break; 825c041511dScube case CirculateNotify: 826c041511dScube case CreateNotify: 827c041511dScube case GravityNotify: 828c041511dScube case ReparentNotify: 829c041511dScube /* Uninteresting to GLUT (but possible for GLUT to 830c041511dScube receive). */ 831c041511dScube break; 832c041511dScube default: 833c041511dScube /* Pass events not directly handled by the GLUT main 834c041511dScube event loop to any event parsers that have been 835c041511dScube registered. In this way, X Input extension events 836c041511dScube are passed to the correct handler without forcing 837c041511dScube all GLUT programs to support X Input event handling. 838c041511dScube */ 839c041511dScube parser = eventParserList; 840c041511dScube while (parser) { 841c041511dScube if (parser->func(&event)) 842c041511dScube break; 843c041511dScube parser = parser->next; 844c041511dScube } 845c041511dScube break; 846c041511dScube } 847c041511dScube } 848c041511dScube#endif /* _WIN32 */ 849c041511dScube if (__glutTimerList) { 850c041511dScube handleTimeouts(); 851c041511dScube } 852c041511dScube } 853c041511dScube while (XPending(__glutDisplay)); 854c041511dScube} 855c041511dScube 856c041511dScubestatic void 857c041511dScubewaitForSomething(void) 858c041511dScube{ 859c041511dScube#if defined(__vms) && ( __VMS_VER < 70000000 ) 860c041511dScube static struct timeval6 zerotime = 861c041511dScube {0}; 862c041511dScube unsigned int timer_efn; 863c041511dScube#define timer_id 'glut' /* random :-) number */ 864c041511dScube unsigned int wait_mask; 865c041511dScube#else 866c041511dScube static struct timeval zerotime = 867c041511dScube {0, 0}; 868c041511dScube#if !defined(_WIN32) 869c041511dScube fd_set fds; 870c041511dScube#endif 871c041511dScube#endif 872c041511dScube#ifdef OLD_VMS 873c041511dScube struct timeval6 now, timeout, waittime; 874c041511dScube#else 875c041511dScube struct timeval now, timeout, waittime; 876c041511dScube#endif 877c041511dScube#if !defined(_WIN32) 878c041511dScube int rc; 879c041511dScube#endif 880c041511dScube 881c041511dScube /* Flush X protocol since XPending does not do this 882c041511dScube implicitly. */ 883c041511dScube XFlush(__glutDisplay); 884c041511dScube if (XPending(__glutDisplay)) { 885c041511dScube /* It is possible (but quite rare) that XFlush may have 886c041511dScube needed to wait for a writable X connection file 887c041511dScube descriptor, and in the process, may have had to read off 888c041511dScube X protocol from the file descriptor. If XPending is true, 889c041511dScube this case occured and we should avoid waiting in select 890c041511dScube since X protocol buffered within Xlib is due to be 891c041511dScube processed and potentially no more X protocol is on the 892c041511dScube file descriptor, so we would risk waiting improperly in 893c041511dScube select. */ 894c041511dScube goto immediatelyHandleXinput; 895c041511dScube } 896c041511dScube#if defined(__vms) && ( __VMS_VER < 70000000 ) 897c041511dScube timeout = __glutTimerList->timeout; 898c041511dScube GETTIMEOFDAY(&now); 899c041511dScube wait_mask = 1 << (__glutConnectionFD & 31); 900c041511dScube if (IS_AFTER(now, timeout)) { 901c041511dScube /* We need an event flag for the timer. */ 902c041511dScube /* XXX The `right' way to do this is to use LIB$GET_EF, but 903c041511dScube since it needs to be in the same cluster as the EFN for 904c041511dScube the display, we will have hack it. */ 905c041511dScube timer_efn = __glutConnectionFD - 1; 906c041511dScube if ((timer_efn / 32) != (__glutConnectionFD / 32)) { 907c041511dScube timer_efn = __glutConnectionFD + 1; 908c041511dScube } 909c041511dScube rc = SYS$CLREF(timer_efn); 910c041511dScube rc = SYS$SETIMR(timer_efn, &timeout, NULL, timer_id, 0); 911c041511dScube wait_mask |= 1 << (timer_efn & 31); 912c041511dScube } else { 913c041511dScube timer_efn = 0; 914c041511dScube } 915c041511dScube rc = SYS$WFLOR(__glutConnectionFD, wait_mask); 916c041511dScube if (timer_efn != 0 && SYS$CLREF(timer_efn) == SS$_WASCLR) { 917c041511dScube rc = SYS$CANTIM(timer_id, PSL$C_USER); 918c041511dScube } 919c041511dScube /* XXX There does not seem to be checking of "rc" in the code 920c041511dScube above. Can any of the SYS$ routines above fail? */ 921c041511dScube#else /* not vms6.2 or lower */ 922c041511dScube#if !defined(_WIN32) 923c041511dScube FD_ZERO(&fds); 924c041511dScube FD_SET(__glutConnectionFD, &fds); 925c041511dScube#endif 926c041511dScube timeout = __glutTimerList->timeout; 927c041511dScube GETTIMEOFDAY(&now); 928c041511dScube if (IS_AFTER(now, timeout)) { 929c041511dScube TIMEDELTA(waittime, timeout, now); 930c041511dScube } else { 931c041511dScube waittime = zerotime; 932c041511dScube } 933c041511dScube#if !defined(_WIN32) 934c041511dScube rc = select(__glutConnectionFD + 1, &fds, 935c041511dScube NULL, NULL, &waittime); 936c041511dScube if (rc < 0 && errno != EINTR) 937c041511dScube __glutFatalError("select error."); 938c041511dScube#else 939c041511dScube 940c041511dScube MsgWaitForMultipleObjects(0, NULL, FALSE, 941c041511dScube waittime.tv_sec*1000 + waittime.tv_usec/1000, QS_ALLINPUT); 942c041511dScube 943c041511dScube#endif 944c041511dScube#endif /* not vms6.2 or lower */ 945c041511dScube /* Without considering the cause of select unblocking, check 946c041511dScube for pending X events and handle any timeouts (by calling 947c041511dScube processEventsAndTimeouts). We always look for X events 948c041511dScube even if select returned with 0 (indicating a timeout); 949c041511dScube otherwise we risk starving X event processing by continous 950c041511dScube timeouts. */ 951c041511dScube if (XPending(__glutDisplay)) { 952c041511dScube immediatelyHandleXinput: 953c041511dScube processEventsAndTimeouts(); 954c041511dScube } else { 955c041511dScube if (__glutTimerList) 956c041511dScube handleTimeouts(); 957c041511dScube } 958c041511dScube} 959c041511dScube 960c041511dScubestatic void 961c041511dScubeidleWait(void) 962c041511dScube{ 963c041511dScube if (XPending(__glutDisplay)) { 964c041511dScube processEventsAndTimeouts(); 965c041511dScube } else { 966c041511dScube if (__glutTimerList) { 967c041511dScube handleTimeouts(); 968c041511dScube } 969c041511dScube } 970c041511dScube /* Make sure idle func still exists! */ 971c041511dScube if (__glutIdleFunc) { 972c041511dScube __glutIdleFunc(); 973c041511dScube } 974c041511dScube} 975c041511dScube 976c041511dScubestatic GLUTwindow **beforeEnd; 977c041511dScube 978c041511dScubestatic GLUTwindow * 979c041511dScubeprocessWindowWorkList(GLUTwindow * window) 980c041511dScube{ 981c041511dScube int workMask; 982c041511dScube 983c041511dScube if (window->prevWorkWin) { 984c041511dScube window->prevWorkWin = processWindowWorkList(window->prevWorkWin); 985c041511dScube } else { 986c041511dScube beforeEnd = &window->prevWorkWin; 987c041511dScube } 988c041511dScube 989c041511dScube /* Capture work mask for work that needs to be done to this 990c041511dScube window, then clear the window's work mask (excepting the 991c041511dScube dummy work bit, see below). Then, process the captured 992c041511dScube work mask. This allows callbacks in the processing the 993c041511dScube captured work mask to set the window's work mask for 994c041511dScube subsequent processing. */ 995c041511dScube 996c041511dScube workMask = window->workMask; 997c041511dScube assert((workMask & GLUT_DUMMY_WORK) == 0); 998c041511dScube 999c041511dScube /* Set the dummy work bit, clearing all other bits, to 1000c041511dScube indicate that the window is currently on the window work 1001c041511dScube list _and_ that the window's work mask is currently being 1002c041511dScube processed. This convinces __glutPutOnWorkList that this 1003c041511dScube window is on the work list still. */ 1004c041511dScube window->workMask = GLUT_DUMMY_WORK; 1005c041511dScube 1006c041511dScube /* Optimization: most of the time, the work to do is a 1007c041511dScube redisplay and not these other types of work. Check for 1008c041511dScube the following cases as a group to before checking each one 1009c041511dScube individually one by one. This saves about 25 MIPS 1010c041511dScube instructions in the common redisplay only case. */ 1011c041511dScube if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK | 1012c041511dScube GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) { 1013c041511dScube#if !defined(_WIN32) 1014c041511dScube /* Be sure to set event mask BEFORE map window is done. */ 1015c041511dScube if (workMask & GLUT_EVENT_MASK_WORK) { 1016c041511dScube long eventMask; 1017c041511dScube 1018c041511dScube /* Make sure children are not propogating events this 1019c041511dScube window is selecting for. Be sure to do this before 1020c041511dScube enabling events on the children's parent. */ 1021c041511dScube if (window->children) { 1022c041511dScube GLUTwindow *child = window->children; 1023c041511dScube unsigned long attribMask = CWDontPropagate; 1024c041511dScube XSetWindowAttributes wa; 1025c041511dScube 1026c041511dScube wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK; 1027c041511dScube if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) { 1028c041511dScube wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK); 1029c041511dScube attribMask |= CWEventMask; 1030c041511dScube } 1031c041511dScube do { 1032c041511dScube XChangeWindowAttributes(__glutDisplay, child->win, 1033c041511dScube attribMask, &wa); 1034c041511dScube child = child->siblings; 1035c041511dScube } while (child); 1036c041511dScube } 1037c041511dScube eventMask = window->eventMask; 1038c041511dScube if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) 1039c041511dScube eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK); 1040c041511dScube XSelectInput(__glutDisplay, window->win, eventMask); 1041c041511dScube if (window->overlay) 1042c041511dScube XSelectInput(__glutDisplay, window->overlay->win, 1043c041511dScube window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK); 1044c041511dScube } 1045c041511dScube#endif /* !_WIN32 */ 1046c041511dScube /* Be sure to set device mask BEFORE map window is done. */ 1047c041511dScube if (workMask & GLUT_DEVICE_MASK_WORK) { 1048c041511dScube __glutUpdateInputDeviceMaskFunc(window); 1049c041511dScube } 1050c041511dScube /* Be sure to configure window BEFORE map window is done. */ 1051c041511dScube if (workMask & GLUT_CONFIGURE_WORK) { 1052c041511dScube#if defined(_WIN32) 1053c041511dScube RECT changes; 1054c041511dScube POINT point; 1055c041511dScube UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER 1056c041511dScube | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER; 1057c041511dScube 1058c041511dScube GetClientRect(window->win, &changes); 1059c041511dScube 1060c041511dScube /* If this window is a toplevel window, translate the 0,0 client 1061c041511dScube coordinate into a screen coordinate for proper placement. */ 1062c041511dScube if (!window->parent) { 1063c041511dScube point.x = 0; 1064c041511dScube point.y = 0; 1065c041511dScube ClientToScreen(window->win, &point); 1066c041511dScube changes.left = point.x; 1067c041511dScube changes.top = point.y; 1068c041511dScube } 1069c041511dScube if (window->desiredConfMask & (CWX | CWY)) { 1070c041511dScube changes.left = window->desiredX; 1071c041511dScube changes.top = window->desiredY; 1072c041511dScube flags &= ~SWP_NOMOVE; 1073c041511dScube } 1074c041511dScube if (window->desiredConfMask & (CWWidth | CWHeight)) { 1075c041511dScube changes.right = changes.left + window->desiredWidth; 1076c041511dScube changes.bottom = changes.top + window->desiredHeight; 1077c041511dScube flags &= ~SWP_NOSIZE; 1078c041511dScube /* XXX If overlay exists, resize the overlay here, ie. 1079c041511dScube if (window->overlay) ... */ 1080c041511dScube } 1081c041511dScube if (window->desiredConfMask & CWStackMode) { 1082c041511dScube flags &= ~SWP_NOZORDER; 1083c041511dScube /* XXX Overlay support might require something special here. */ 1084c041511dScube } 1085c041511dScube 1086c041511dScube /* Adjust the window rectangle because Win32 thinks that the x, y, 1087c041511dScube width & height are the WHOLE window (including decorations), 1088c041511dScube whereas GLUT treats the x, y, width & height as only the CLIENT 1089c041511dScube area of the window. Only do this to top level windows 1090c041511dScube that are not in game mode (since game mode windows do 1091c041511dScube not have any decorations). */ 1092c041511dScube if (!window->parent && window != __glutGameModeWindow) { 1093c041511dScube AdjustWindowRect(&changes, 1094c041511dScube WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 1095c041511dScube FALSE); 1096c041511dScube } 1097c041511dScube 1098c041511dScube /* Do the repositioning, moving, and push/pop. */ 1099c041511dScube SetWindowPos(window->win, 1100c041511dScube window->desiredStack == Above ? HWND_TOP : HWND_NOTOPMOST, 1101c041511dScube changes.left, changes.top, 1102c041511dScube changes.right - changes.left, changes.bottom - changes.top, 1103c041511dScube flags); 1104c041511dScube 1105c041511dScube /* Zero out the mask. */ 1106c041511dScube window->desiredConfMask = 0; 1107c041511dScube 1108c041511dScube /* This hack causes the window to go back to the right position 1109c041511dScube when it is taken out of fullscreen mode. */ 1110c041511dScube if (workMask & GLUT_FULL_SCREEN_WORK) { 1111c041511dScube window->desiredConfMask |= CWX | CWY; 1112c041511dScube window->desiredX = point.x; 1113c041511dScube window->desiredY = point.y; 1114c041511dScube } 1115c041511dScube#else /* !_WIN32 */ 1116c041511dScube XWindowChanges changes; 1117c041511dScube 1118c041511dScube changes.x = window->desiredX; 1119c041511dScube changes.y = window->desiredY; 1120c041511dScube if (window->desiredConfMask & (CWWidth | CWHeight)) { 1121c041511dScube changes.width = window->desiredWidth; 1122c041511dScube changes.height = window->desiredHeight; 1123c041511dScube if (window->overlay) 1124c041511dScube XResizeWindow(__glutDisplay, window->overlay->win, 1125c041511dScube window->desiredWidth, window->desiredHeight); 1126c041511dScube if (__glutMotifHints != None) { 1127c041511dScube if (workMask & GLUT_FULL_SCREEN_WORK) { 1128c041511dScube MotifWmHints hints; 1129c041511dScube 1130c041511dScube hints.flags = MWM_HINTS_DECORATIONS; 1131c041511dScube hints.decorations = 0; /* Absolutely no 1132c041511dScube decorations. */ 1133c041511dScube XChangeProperty(__glutDisplay, window->win, 1134c041511dScube __glutMotifHints, __glutMotifHints, 32, 1135c041511dScube PropModeReplace, (unsigned char *) &hints, 4); 1136c041511dScube if (workMask & GLUT_MAP_WORK) { 1137c041511dScube /* Handle case where glutFullScreen is called 1138c041511dScube before the first time that the window is 1139c041511dScube mapped. Some window managers will randomly or 1140c041511dScube interactively position the window the first 1141c041511dScube time it is mapped if the window's 1142c041511dScube WM_NORMAL_HINTS property does not request an 1143c041511dScube explicit position. We don't want any such 1144c041511dScube window manager interaction when going 1145c041511dScube fullscreen. Overwrite the WM_NORMAL_HINTS 1146c041511dScube property installed by glutCreateWindow's 1147c041511dScube XSetWMProperties property with one explicitly 1148c041511dScube requesting a fullscreen window. */ 1149c041511dScube XSizeHints hints; 1150c041511dScube 1151c041511dScube hints.flags = USPosition | USSize; 1152c041511dScube hints.x = 0; 1153c041511dScube hints.y = 0; 1154c041511dScube hints.width = window->desiredWidth; 1155c041511dScube hints.height = window->desiredHeight; 1156c041511dScube XSetWMNormalHints(__glutDisplay, window->win, &hints); 1157c041511dScube } 1158c041511dScube } else { 1159c041511dScube XDeleteProperty(__glutDisplay, window->win, __glutMotifHints); 1160c041511dScube } 1161c041511dScube } 1162c041511dScube } 1163c041511dScube if (window->desiredConfMask & CWStackMode) { 1164c041511dScube changes.stack_mode = window->desiredStack; 1165c041511dScube /* Do not let glutPushWindow push window beneath the 1166c041511dScube underlay. */ 1167c041511dScube if (window->parent && window->parent->overlay 1168c041511dScube && window->desiredStack == Below) { 1169c041511dScube changes.stack_mode = Above; 1170c041511dScube changes.sibling = window->parent->overlay->win; 1171c041511dScube window->desiredConfMask |= CWSibling; 1172c041511dScube } 1173c041511dScube } 1174c041511dScube XConfigureWindow(__glutDisplay, window->win, 1175c041511dScube window->desiredConfMask, &changes); 1176c041511dScube window->desiredConfMask = 0; 1177c041511dScube#endif 1178c041511dScube } 1179c041511dScube#if !defined(_WIN32) 1180c041511dScube /* Be sure to establish the colormaps BEFORE map window is 1181c041511dScube done. */ 1182c041511dScube if (workMask & GLUT_COLORMAP_WORK) { 1183c041511dScube __glutEstablishColormapsProperty(window); 1184c041511dScube } 1185c041511dScube#endif 1186c041511dScube if (workMask & GLUT_MAP_WORK) { 1187c041511dScube switch (window->desiredMapState) { 1188c041511dScube case WithdrawnState: 1189c041511dScube if (window->parent) { 1190c041511dScube XUnmapWindow(__glutDisplay, window->win); 1191c041511dScube } else { 1192c041511dScube XWithdrawWindow(__glutDisplay, window->win, 1193c041511dScube __glutScreen); 1194c041511dScube } 1195c041511dScube window->shownState = 0; 1196c041511dScube break; 1197c041511dScube case NormalState: 1198c041511dScube XMapWindow(__glutDisplay, window->win); 1199c041511dScube window->shownState = 1; 1200c041511dScube break; 1201c041511dScube#ifdef _WIN32 1202c041511dScube case GameModeState: /* Not an Xlib value. */ 1203c041511dScube ShowWindow(window->win, SW_SHOW); 1204c041511dScube window->shownState = 1; 1205c041511dScube break; 1206c041511dScube#endif 1207c041511dScube case IconicState: 1208c041511dScube XIconifyWindow(__glutDisplay, window->win, __glutScreen); 1209c041511dScube window->shownState = 0; 1210c041511dScube break; 1211c041511dScube } 1212c041511dScube } 1213c041511dScube } 1214c041511dScube if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) { 1215c041511dScube if (window->forceReshape) { 1216c041511dScube /* Guarantee that before a display callback is generated 1217c041511dScube for a window, a reshape callback must be generated. */ 1218c041511dScube __glutSetWindow(window); 1219c041511dScube window->reshape(window->width, window->height); 1220c041511dScube window->forceReshape = False; 1221c041511dScube 1222c041511dScube /* Setting the redisplay bit on the first reshape is 1223c041511dScube necessary to make the "Mesa glXSwapBuffers to repair 1224c041511dScube damage" hack operate correctly. Without indicating a 1225c041511dScube redisplay is necessary, there's not an initial back 1226c041511dScube buffer render from which to blit from when damage 1227c041511dScube happens to the window. */ 1228c041511dScube workMask |= GLUT_REDISPLAY_WORK; 1229c041511dScube } 1230c041511dScube /* The code below is more involved than otherwise necessary 1231c041511dScube because it is paranoid about the overlay or entire window 1232c041511dScube being removed or destroyed in the course of the callbacks. 1233c041511dScube Notice how the global __glutWindowDamaged is used to record 1234c041511dScube the layers' damage status. See the code in glutLayerGet for 1235c041511dScube how __glutWindowDamaged is used. The point is to not have to 1236c041511dScube update the "damaged" field after the callback since the 1237c041511dScube window (or overlay) may be destroyed (or removed) when the 1238c041511dScube callback returns. */ 1239c041511dScube 1240c041511dScube if (window->overlay && window->overlay->display) { 1241c041511dScube int num = window->num; 1242c041511dScube Window xid = window->overlay ? window->overlay->win : None; 1243c041511dScube 1244c041511dScube /* If an overlay display callback is registered, we 1245c041511dScube differentiate between a redisplay needed for the 1246c041511dScube overlay and/or normal plane. If there is no overlay 1247c041511dScube display callback registered, we simply use the 1248c041511dScube standard display callback. */ 1249c041511dScube 1250c041511dScube if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) { 1251c041511dScube if (__glutMesaSwapHackSupport) { 1252c041511dScube if (window->usedSwapBuffers) { 1253c041511dScube if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) { 1254c041511dScube SWAP_BUFFERS_WINDOW(window); 1255c041511dScube goto skippedDisplayCallback1; 1256c041511dScube } 1257c041511dScube } 1258c041511dScube } 1259c041511dScube /* Render to normal plane. */ 1260c041511dScube#ifdef _WIN32 1261c041511dScube window->renderDc = window->hdc; 1262c041511dScube#endif 1263c041511dScube window->renderWin = window->win; 1264c041511dScube window->renderCtx = window->ctx; 1265c041511dScube __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK); 1266c041511dScube __glutSetWindow(window); 1267c041511dScube window->usedSwapBuffers = 0; 1268c041511dScube window->display(); 1269c041511dScube __glutWindowDamaged = 0; 1270c041511dScube 1271c041511dScube skippedDisplayCallback1:; 1272c041511dScube } 1273c041511dScube if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) { 1274c041511dScube window = __glutWindowList[num]; 1275c041511dScube if (window && window->overlay && 1276c041511dScube window->overlay->win == xid && window->overlay->display) { 1277c041511dScube 1278c041511dScube /* Render to overlay. */ 1279c041511dScube#ifdef _WIN32 1280c041511dScube window->renderDc = window->overlay->hdc; 1281c041511dScube#endif 1282c041511dScube window->renderWin = window->overlay->win; 1283c041511dScube window->renderCtx = window->overlay->ctx; 1284c041511dScube __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK); 1285c041511dScube __glutSetWindow(window); 1286c041511dScube window->overlay->display(); 1287c041511dScube __glutWindowDamaged = 0; 1288c041511dScube } else { 1289c041511dScube /* Overlay may have since been destroyed or the 1290c041511dScube overlay callback may have been disabled during 1291c041511dScube normal display callback. */ 1292c041511dScube } 1293c041511dScube } 1294c041511dScube } else { 1295c041511dScube if (__glutMesaSwapHackSupport) { 1296c041511dScube if (!window->overlay && window->usedSwapBuffers) { 1297c041511dScube if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) { 1298c041511dScube SWAP_BUFFERS_WINDOW(window); 1299c041511dScube goto skippedDisplayCallback2; 1300c041511dScube } 1301c041511dScube } 1302c041511dScube } 1303c041511dScube /* Render to normal plane (and possibly overlay). */ 1304c041511dScube __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK)); 1305c041511dScube __glutSetWindow(window); 1306c041511dScube window->usedSwapBuffers = 0; 1307c041511dScube window->display(); 1308c041511dScube __glutWindowDamaged = 0; 1309c041511dScube 1310c041511dScube skippedDisplayCallback2:; 1311c041511dScube } 1312c041511dScube } 1313c041511dScube /* Combine workMask with window->workMask to determine what 1314c041511dScube finish and debug work there is. */ 1315553f1899Smrg assert(window); 1316c041511dScube workMask |= window->workMask; 1317c041511dScube 1318c041511dScube if (workMask & GLUT_FINISH_WORK) { 1319c041511dScube /* Finish work makes sure a glFinish gets done to indirect 1320c041511dScube rendering contexts. Indirect contexts tend to have much 1321c041511dScube longer latency because lots of OpenGL extension requests 1322c041511dScube can queue up in the X protocol stream. __glutSetWindow 1323c041511dScube is where the finish works gets queued for indirect 1324c041511dScube contexts. */ 1325c041511dScube __glutSetWindow(window); 13262590f9beSmrg#if !defined(_WIN32) 13272590f9beSmrg if (!window->isDirect) 13282590f9beSmrg#endif 13292590f9beSmrg { 13302590f9beSmrg glFinish(); 13312590f9beSmrg } 1332c041511dScube } 1333c041511dScube if (workMask & GLUT_DEBUG_WORK) { 1334c041511dScube __glutSetWindow(window); 1335c041511dScube glutReportErrors(); 1336c041511dScube } 1337c041511dScube /* Strip out dummy, finish, and debug work bits. */ 1338c041511dScube window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK); 1339c041511dScube if (window->workMask) { 1340c041511dScube /* Leave on work list. */ 1341c041511dScube return window; 1342c041511dScube } else { 1343c041511dScube /* Remove current window from work list. */ 1344c041511dScube return window->prevWorkWin; 1345c041511dScube } 1346c041511dScube} 1347c041511dScube 1348c041511dScubestatic /* X11 implementations do not need this global. */ 1349c041511dScubevoid 1350c041511dScube__glutProcessWindowWorkLists(void) 1351c041511dScube{ 1352c041511dScube if (__glutWindowWorkList) { 1353c041511dScube GLUTwindow *remainder, *work; 1354c041511dScube 1355c041511dScube work = __glutWindowWorkList; 1356c041511dScube __glutWindowWorkList = NULL; 1357c041511dScube if (work) { 1358c041511dScube remainder = processWindowWorkList(work); 1359c041511dScube if (remainder) { 1360c041511dScube *beforeEnd = __glutWindowWorkList; 1361c041511dScube __glutWindowWorkList = remainder; 1362c041511dScube } 1363c041511dScube } 1364c041511dScube } 1365c041511dScube} 1366c041511dScube 1367c041511dScube/* CENTRY */ 1368c041511dScubevoid GLUTAPIENTRY 1369c041511dScubeglutMainLoop(void) 1370c041511dScube{ 1371c041511dScube#if !defined(_WIN32) 1372c041511dScube if (!__glutDisplay) 1373c041511dScube __glutFatalUsage("main loop entered with out proper initialization."); 1374c041511dScube#endif 1375c041511dScube if (!__glutWindowListSize) 1376c041511dScube __glutFatalUsage( 1377c041511dScube "main loop entered with no windows created."); 1378c041511dScube for (;;) { 1379c041511dScube __glutProcessWindowWorkLists(); 1380c041511dScube if (__glutIdleFunc || __glutWindowWorkList) { 1381c041511dScube idleWait(); 1382c041511dScube } else { 1383c041511dScube if (__glutTimerList) { 1384c041511dScube waitForSomething(); 1385c041511dScube } else { 1386c041511dScube processEventsAndTimeouts(); 1387c041511dScube } 1388c041511dScube } 1389c041511dScube } 1390c041511dScube} 1391c041511dScube/* ENDCENTRY */ 1392