1c041511dScube 2c041511dScube/* Copyright (c) Nate Robins, 1997. */ 3c041511dScube/* portions Copyright (c) Mark Kilgard, 1997, 1998. */ 4c041511dScube 5c041511dScube/* This program is freely distributable without licensing fees 6c041511dScube and is provided without guarantee or warrantee expressed or 7c041511dScube implied. This program is -not- in the public domain. */ 8c041511dScube 9c041511dScube 10c041511dScube#include "glutint.h" 11c041511dScube#include <sys/timeb.h> 12c041511dScube#ifdef __MINGW32__ 13c041511dScube#include <ctype.h> 14c041511dScube#endif 15c041511dScube 16c041511dScube#if defined(_WIN32) && !defined(__CYGWIN32__) 17c041511dScube#include <mmsystem.h> /* Win32 Multimedia API header. */ 18c041511dScube#endif 19c041511dScube 20c041511dScubeextern unsigned __glutMenuButton; 21c041511dScubeextern GLUTidleCB __glutIdleFunc; 22c041511dScubeextern GLUTtimer *__glutTimerList; 232590f9beSmrgextern GLUTmenuItem *__glutGetUniqueMenuItem(GLUTmenu * menu, UINT unique); 24c041511dScubestatic HMENU __glutHMenu; 25c041511dScube 262590f9beSmrgstatic void 27c041511dScubeupdateWindowState(GLUTwindow *window, int visState) 28c041511dScube{ 29c041511dScube GLUTwindow* child; 30c041511dScube 31c041511dScube /* XXX shownState and visState are the same in Win32. */ 32c041511dScube window->shownState = visState; 33c041511dScube if (visState != window->visState) { 34c041511dScube if (window->windowStatus) { 35c041511dScube window->visState = visState; 36c041511dScube __glutSetWindow(window); 37c041511dScube window->windowStatus(visState); 38c041511dScube } 39c041511dScube } 40c041511dScube /* Since Win32 only sends an activate for the toplevel window, 41c041511dScube update the visibility for all the child windows. */ 42c041511dScube child = window->children; 43c041511dScube while (child) { 44c041511dScube updateWindowState(child, visState); 45c041511dScube child = child->siblings; 46c041511dScube } 47c041511dScube} 48c041511dScube 49c041511dScubeLONG WINAPI 50c041511dScube__glutWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51c041511dScube{ 52c041511dScube POINT point; /* Point structure. */ 53c041511dScube PAINTSTRUCT ps; /* Paint structure. */ 54c041511dScube LPMINMAXINFO minmax; /* Minimum/maximum info structure. */ 55c041511dScube GLUTwindow* window; /* GLUT window associated with message. */ 56c041511dScube GLUTmenu* menu; /* GLUT menu associated with message. */ 57c041511dScube int x, y, width, height, key; 58c041511dScube int button = -1; 59c041511dScube 60c041511dScube switch(msg) { 61c041511dScube case WM_CREATE: 62c041511dScube return 0; 63c041511dScube case WM_CLOSE: 64c041511dScube if (__glutExitFunc) { 65c041511dScube __glutExitFunc(0); 66c041511dScube } 67c041511dScube exit(0); 68c041511dScube break; 69c041511dScube#if 0 70c041511dScube case WM_DESTROY: 71c041511dScube /* XXX NVidia's NT OpenGL can have problems closing down 72c041511dScube its OpenGL internal data structures if we just allow 73c041511dScube the process to terminate without unbinding and deleting 74c041511dScube the windows context. Apparently, DirectDraw unloads 75c041511dScube before OPENGL32.DLL in the close down sequence, but 76c041511dScube NVidia's NT OpenGL needs DirectDraw to close down its 77c041511dScube data structures. */ 78c041511dScube window = __glutGetWindow(hwnd); 79c041511dScube if (window) { 80c041511dScube if (window->ctx) { 81c041511dScube wglMakeCurrent(NULL, NULL); 82c041511dScube wglDeleteContext(window->ctx); 83c041511dScube } 84c041511dScube } 85c041511dScube return 0; 86c041511dScube#endif 87c041511dScube case WM_PAINT: 88c041511dScube window = __glutGetWindow(hwnd); 89c041511dScube if (window) { 90c041511dScube BeginPaint(hwnd, &ps); /* Must have this for some Win32 reason. */ 91c041511dScube EndPaint(hwnd, &ps); 92c041511dScube if (window->win == hwnd) { 93c041511dScube __glutPostRedisplay(window, GLUT_REPAIR_WORK); 94c041511dScube } else if (window->overlay && window->overlay->win == hwnd) { 95c041511dScube __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK); 96c041511dScube } 97c041511dScube } 98c041511dScube return 0; 99c041511dScube 100c041511dScube case WM_SYSKEYUP: 101c041511dScube case WM_KEYUP: 102c041511dScube window = __glutGetWindow(hwnd); 103c041511dScube if (!window) { 104c041511dScube break; 105c041511dScube } 106c041511dScube /* Win32 is dumb and sends these messages only to the parent 107c041511dScube window. Therefore, find out if we're in a child window and 108c041511dScube call the child windows keyboard callback if we are. */ 109c041511dScube if (window->parent) { 110c041511dScube GetCursorPos(&point); 111c041511dScube ScreenToClient(hwnd, &point); 112c041511dScube hwnd = ChildWindowFromPoint(hwnd, point); 113c041511dScube window = __glutGetWindow(hwnd); 114c041511dScube } 115c041511dScube if (window->specialUp || window->keyboardUp) { 116c041511dScube GetCursorPos(&point); 117c041511dScube ScreenToClient(window->win, &point); 118c041511dScube __glutSetWindow(window); 119c041511dScube __glutModifierMask = 0; 120c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 121c041511dScube __glutModifierMask |= ShiftMask; 122c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 123c041511dScube __glutModifierMask |= ControlMask; 124c041511dScube if (GetKeyState(VK_MENU) < 0) 125c041511dScube __glutModifierMask |= Mod1Mask; 126c041511dScube switch (wParam) { 127c041511dScube /* *INDENT-OFF* */ 128c041511dScube case VK_F1: key = GLUT_KEY_F1; break; 129c041511dScube case VK_F2: key = GLUT_KEY_F2; break; 130c041511dScube case VK_F3: key = GLUT_KEY_F3; break; 131c041511dScube case VK_F4: key = GLUT_KEY_F4; break; 132c041511dScube case VK_F5: key = GLUT_KEY_F5; break; 133c041511dScube case VK_F6: key = GLUT_KEY_F6; break; 134c041511dScube case VK_F7: key = GLUT_KEY_F7; break; 135c041511dScube case VK_F8: key = GLUT_KEY_F8; break; 136c041511dScube case VK_F9: key = GLUT_KEY_F9; break; 137c041511dScube case VK_F10: key = GLUT_KEY_F10; break; 138c041511dScube case VK_F11: key = GLUT_KEY_F11; break; 139c041511dScube case VK_F12: key = GLUT_KEY_F12; break; 140c041511dScube case VK_LEFT: key = GLUT_KEY_LEFT; break; 141c041511dScube case VK_UP: key = GLUT_KEY_UP; break; 142c041511dScube case VK_RIGHT: key = GLUT_KEY_RIGHT; break; 143c041511dScube case VK_DOWN: key = GLUT_KEY_DOWN; break; 144c041511dScube case VK_PRIOR: key = GLUT_KEY_PAGE_UP; break; 145c041511dScube case VK_NEXT: key = GLUT_KEY_PAGE_DOWN; break; 146c041511dScube case VK_HOME: key = GLUT_KEY_HOME; break; 147c041511dScube case VK_END: key = GLUT_KEY_END; break; 148c041511dScube case VK_INSERT: key = GLUT_KEY_INSERT; break; 149c041511dScube case VK_DELETE: 150c041511dScube /* Delete is an ASCII character. */ 151c041511dScube if (window->keyboardUp) { 152c041511dScube window->keyboardUp((unsigned char) 127, point.x, point.y); 153c041511dScube } 154c041511dScube return 0; 155c041511dScube /* *INDENT-ON* */ 156c041511dScube default: 157c041511dScube if (window->keyboardUp) { 158c041511dScube key = MapVirtualKey(wParam, 2); /* Map to ASCII. */ 159c041511dScube if (isascii(key) && (key != 0)) { 160c041511dScube 161c041511dScube /* XXX Attempt to determine modified ASCII character 162c041511dScube is quite incomplete. Digits, symbols, CapsLock, 163c041511dScube Ctrl, and numeric keypad are all ignored. Fix this. */ 164c041511dScube 165c041511dScube if (!(__glutModifierMask & ShiftMask)) 166c041511dScube key = tolower(key); 167c041511dScube window->keyboardUp((unsigned char) key, point.x, point.y); 168c041511dScube } 169c041511dScube } 170c041511dScube __glutModifierMask = (unsigned int) ~0; 171c041511dScube return 0; 172c041511dScube } 173c041511dScube if (window->specialUp) { 174c041511dScube window->specialUp(key, point.x, point.y); 175c041511dScube } 176c041511dScube __glutModifierMask = (unsigned int) ~0; 177c041511dScube } 178c041511dScube return 0; 179c041511dScube 180c041511dScube case WM_SYSCHAR: 181c041511dScube case WM_CHAR: 182c041511dScube window = __glutGetWindow(hwnd); 183c041511dScube if (!window) { 184c041511dScube break; 185c041511dScube } 186c041511dScube 187c041511dScube /* Bit 30 of lParam is set if key already held down. If 188c041511dScube we are ignoring auto repeated key strokes for the window, bail. */ 189c041511dScube if (window->ignoreKeyRepeat && (lParam & (1 << 30)) ) { 190c041511dScube break; 191c041511dScube } 192c041511dScube 193c041511dScube /* Win32 is dumb and sends these messages only to the parent 194c041511dScube window. Therefore, find out if we're in a child window and 195c041511dScube call the child windows keyboard callback if we are. */ 196c041511dScube if (window->parent) { 197c041511dScube GetCursorPos(&point); 198c041511dScube ScreenToClient(hwnd, &point); 199c041511dScube hwnd = ChildWindowFromPoint(hwnd, point); 200c041511dScube window = __glutGetWindow(hwnd); 201c041511dScube } 202c041511dScube if (window->keyboard) { 203c041511dScube GetCursorPos(&point); 204c041511dScube ScreenToClient(window->win, &point); 205c041511dScube __glutSetWindow(window); 206c041511dScube __glutModifierMask = 0; 207c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 208c041511dScube __glutModifierMask |= ShiftMask; 209c041511dScube if (GetKeyState(VK_CONTROL) < 0) 210c041511dScube __glutModifierMask |= ControlMask; 211c041511dScube if (GetKeyState(VK_MENU) < 0) 212c041511dScube __glutModifierMask |= Mod1Mask; 213c041511dScube window->keyboard((unsigned char)wParam, point.x, point.y); 214c041511dScube __glutModifierMask = (unsigned int) ~0; 215c041511dScube } 216c041511dScube return 0; 217c041511dScube 218c041511dScube case WM_SYSKEYDOWN: 219c041511dScube case WM_KEYDOWN: 220c041511dScube window = __glutGetWindow(hwnd); 221c041511dScube if (!window) { 222c041511dScube break; 223c041511dScube } 224c041511dScube 225c041511dScube /* Bit 30 of lParam is set if key already held down. If 226c041511dScube we are ignoring auto repeated key strokes for the window, bail. */ 227c041511dScube if (window->ignoreKeyRepeat && (lParam & (1 << 30)) ) { 228c041511dScube break; 229c041511dScube } 230c041511dScube 231c041511dScube /* Win32 is dumb and sends these messages only to the parent 232c041511dScube window. Therefore, find out if we're in a child window and 233c041511dScube call the child windows keyboard callback if we are. */ 234c041511dScube if (window->parent) { 235c041511dScube GetCursorPos(&point); 236c041511dScube ScreenToClient(hwnd, &point); 237c041511dScube hwnd = ChildWindowFromPoint(hwnd, point); 238c041511dScube window = __glutGetWindow(hwnd); 239c041511dScube } 240c041511dScube if (window->special) { 241c041511dScube switch (wParam) { 242c041511dScube /* *INDENT-OFF* */ 243c041511dScube /* function keys */ 244c041511dScube case VK_F1: key = GLUT_KEY_F1; break; 245c041511dScube case VK_F2: key = GLUT_KEY_F2; break; 246c041511dScube case VK_F3: key = GLUT_KEY_F3; break; 247c041511dScube case VK_F4: key = GLUT_KEY_F4; break; 248c041511dScube case VK_F5: key = GLUT_KEY_F5; break; 249c041511dScube case VK_F6: key = GLUT_KEY_F6; break; 250c041511dScube case VK_F7: key = GLUT_KEY_F7; break; 251c041511dScube case VK_F8: key = GLUT_KEY_F8; break; 252c041511dScube case VK_F9: key = GLUT_KEY_F9; break; 253c041511dScube case VK_F10: key = GLUT_KEY_F10; break; 254c041511dScube case VK_F11: key = GLUT_KEY_F11; break; 255c041511dScube case VK_F12: key = GLUT_KEY_F12; break; 256c041511dScube /* directional keys */ 257c041511dScube case VK_LEFT: key = GLUT_KEY_LEFT; break; 258c041511dScube case VK_UP: key = GLUT_KEY_UP; break; 259c041511dScube case VK_RIGHT: key = GLUT_KEY_RIGHT; break; 260c041511dScube case VK_DOWN: key = GLUT_KEY_DOWN; break; 261c041511dScube /* *INDENT-ON* */ 262c041511dScube 263c041511dScube case VK_PRIOR: 264c041511dScube /* VK_PRIOR is Win32's Page Up */ 265c041511dScube key = GLUT_KEY_PAGE_UP; 266c041511dScube break; 267c041511dScube case VK_NEXT: 268c041511dScube /* VK_NEXT is Win32's Page Down */ 269c041511dScube key = GLUT_KEY_PAGE_DOWN; 270c041511dScube break; 271c041511dScube case VK_HOME: 272c041511dScube key = GLUT_KEY_HOME; 273c041511dScube break; 274c041511dScube case VK_END: 275c041511dScube key = GLUT_KEY_END; 276c041511dScube break; 277c041511dScube case VK_INSERT: 278c041511dScube key = GLUT_KEY_INSERT; 279c041511dScube break; 280c041511dScube case VK_DELETE: 281c041511dScube goto handleDelete; 282c041511dScube default: 283c041511dScube goto defproc; 284c041511dScube } 285c041511dScube GetCursorPos(&point); 286c041511dScube ScreenToClient(window->win, &point); 287c041511dScube __glutSetWindow(window); 288c041511dScube __glutModifierMask = 0; 289c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 290c041511dScube __glutModifierMask |= ShiftMask; 291c041511dScube if (GetKeyState(VK_CONTROL) < 0) 292c041511dScube __glutModifierMask |= ControlMask; 293c041511dScube if (GetKeyState(VK_MENU) < 0) 294c041511dScube __glutModifierMask |= Mod1Mask; 295c041511dScube window->special(key, point.x, point.y); 296c041511dScube __glutModifierMask = (unsigned int) ~0; 297c041511dScube } else if (window->keyboard) { 298c041511dScube /* Specially handle any keys that match ASCII values but 299c041511dScube do not generate Windows WM_SYSCHAR or WM_CHAR messages. */ 300c041511dScube switch (wParam) { 301c041511dScube case VK_DELETE: 302c041511dScube handleDelete: 303c041511dScube /* Delete is an ASCII character. */ 304c041511dScube GetCursorPos(&point); 305c041511dScube ScreenToClient(window->win, &point); 306c041511dScube __glutSetWindow(window); 307c041511dScube __glutModifierMask = 0; 308c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 309c041511dScube __glutModifierMask |= ShiftMask; 310c041511dScube if (GetKeyState(VK_CONTROL) < 0) 311c041511dScube __glutModifierMask |= ControlMask; 312c041511dScube if (GetKeyState(VK_MENU) < 0) 313c041511dScube __glutModifierMask |= Mod1Mask; 314c041511dScube window->keyboard((unsigned char) 127, point.x, point.y); 315c041511dScube __glutModifierMask = (unsigned int) ~0; 316c041511dScube return 0; 317c041511dScube default: 318c041511dScube /* Let the following WM_SYSCHAR or WM_CHAR message generate 319c041511dScube the keyboard callback. */ 320c041511dScube break; 321c041511dScube } 322c041511dScube } 323c041511dScube return 0; 324c041511dScube 325c041511dScube case WM_LBUTTONDOWN: 326c041511dScube button = GLUT_LEFT_BUTTON; 327c041511dScube case WM_MBUTTONDOWN: 328c041511dScube if (button < 0) 329c041511dScube button = GLUT_MIDDLE_BUTTON; 330c041511dScube case WM_RBUTTONDOWN: 331c041511dScube if (button < 0) 332c041511dScube button = GLUT_RIGHT_BUTTON; 333c041511dScube 334c041511dScube /* finish the menu if we get a button down message (user must have 335c041511dScube cancelled the menu). */ 336c041511dScube if (__glutMappedMenu) { 337c041511dScube /* TODO: take this out once the menu on middle mouse stuff works 338c041511dScube properly. */ 339c041511dScube if (button == GLUT_MIDDLE_BUTTON) 340c041511dScube return 0; 341c041511dScube GetCursorPos(&point); 342c041511dScube ScreenToClient(hwnd, &point); 343c041511dScube __glutItemSelected = NULL; 344c041511dScube __glutFinishMenu(hwnd, point.x, point.y); 345c041511dScube return 0; 346c041511dScube } 347c041511dScube 348c041511dScube /* set the capture so we can get mouse events outside the window */ 349c041511dScube SetCapture(hwnd); 350c041511dScube 351c041511dScube /* Win32 doesn't return the same numbers as X does when the mouse 352c041511dScube goes beyond the upper or left side of the window. roll the 353c041511dScube Win32's 0..2^16 pointer co-ord range to 0 +/- 2^15. */ 354c041511dScube x = LOWORD(lParam); 355c041511dScube y = HIWORD(lParam); 356c041511dScube if(x & 1 << 15) x -= (1 << 16); 357c041511dScube if(y & 1 << 15) y -= (1 << 16); 358c041511dScube 359c041511dScube window = __glutGetWindow(hwnd); 360c041511dScube if (window) { 361c041511dScube menu = __glutGetMenuByNum(window->menu[button]); 362c041511dScube if (menu) { 363c041511dScube point.x = LOWORD(lParam); point.y = HIWORD(lParam); 364c041511dScube ClientToScreen(window->win, &point); 365c041511dScube __glutMenuButton = button == GLUT_RIGHT_BUTTON ? TPM_RIGHTBUTTON : 366c041511dScube button == GLUT_LEFT_BUTTON ? TPM_LEFTBUTTON : 367c041511dScube 0x0001; 368c041511dScube __glutStartMenu(menu, window, point.x, point.y, x, y); 369c041511dScube } else if (window->mouse) { 370c041511dScube 371c041511dScube __glutSetWindow(window); 372c041511dScube __glutModifierMask = 0; 373c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on. */ 374c041511dScube __glutModifierMask |= ShiftMask; 375c041511dScube if (GetKeyState(VK_CONTROL) < 0) 376c041511dScube __glutModifierMask |= ControlMask; 377c041511dScube if (GetKeyState(VK_MENU) < 0) 378c041511dScube __glutModifierMask |= Mod1Mask; 379c041511dScube window->mouse(button, GLUT_DOWN, x, y); 380c041511dScube __glutModifierMask = (unsigned int)~0; 381c041511dScube } else { 382c041511dScube /* Stray mouse events. Ignore. */ 383c041511dScube } 384c041511dScube } 385c041511dScube return 0; 386c041511dScube 387c041511dScube case WM_LBUTTONUP: 388c041511dScube button = GLUT_LEFT_BUTTON; 389c041511dScube case WM_MBUTTONUP: 390c041511dScube if (button < 0) 391c041511dScube button = GLUT_MIDDLE_BUTTON; 392c041511dScube case WM_RBUTTONUP: 393c041511dScube if (button < 0) 394c041511dScube button = GLUT_RIGHT_BUTTON; 395c041511dScube 396c041511dScube /* Bail out if we're processing a menu. */ 397c041511dScube if (__glutMappedMenu) { 398c041511dScube GetCursorPos(&point); 399c041511dScube ScreenToClient(hwnd, &point); 400c041511dScube /* if we're getting the middle button up signal, then something 401c041511dScube on the menu was selected. */ 402c041511dScube if (button == GLUT_MIDDLE_BUTTON) { 403c041511dScube return 0; 404c041511dScube /* For some reason, the code below always returns -1 even 405c041511dScube though the point IS IN THE ITEM! Therefore, just bail out if 406c041511dScube we get a middle mouse up. The user must select using the 407c041511dScube left mouse button. Stupid Win32. */ 408c041511dScube#if 0 409c041511dScube int item = MenuItemFromPoint(hwnd, __glutHMenu, point); 410c041511dScube if (item != -1) 411c041511dScube __glutItemSelected = (GLUTmenuItem*)GetMenuItemID(__glutHMenu, item); 412c041511dScube else 413c041511dScube __glutItemSelected = NULL; 414c041511dScube __glutFinishMenu(hwnd, point.x, point.y); 415c041511dScube#endif 416c041511dScube } else { 417c041511dScube __glutItemSelected = NULL; 418c041511dScube __glutFinishMenu(hwnd, point.x, point.y); 419c041511dScube } 420c041511dScube return 0; 421c041511dScube } 422c041511dScube 423c041511dScube /* Release the mouse capture. */ 424c041511dScube ReleaseCapture(); 425c041511dScube 426c041511dScube window = __glutGetWindow(hwnd); 427c041511dScube if (window && window->mouse) { 428c041511dScube /* Win32 doesn't return the same numbers as X does when the 429c041511dScube mouse goes beyond the upper or left side of the window. roll 430c041511dScube the Win32's 0..2^16 pointer co-ord range to 0 +/- 2^15. */ 431c041511dScube x = LOWORD(lParam); 432c041511dScube y = HIWORD(lParam); 433c041511dScube if(x & 1 << 15) x -= (1 << 16); 434c041511dScube if(y & 1 << 15) y -= (1 << 16); 435c041511dScube 436c041511dScube __glutSetWindow(window); 437c041511dScube __glutModifierMask = 0; 438c041511dScube if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 439c041511dScube __glutModifierMask |= ShiftMask; 440c041511dScube if (GetKeyState(VK_CONTROL) < 0) 441c041511dScube __glutModifierMask |= ControlMask; 442c041511dScube if (GetKeyState(VK_MENU) < 0) 443c041511dScube __glutModifierMask |= Mod1Mask; 444c041511dScube window->mouse(button, GLUT_UP, x, y); 445c041511dScube __glutModifierMask = (unsigned int)~0; 446c041511dScube } else { 447c041511dScube /* Window might have been destroyed and all the 448c041511dScube events for the window may not yet be received. */ 449c041511dScube } 450c041511dScube return 0; 451c041511dScube 452c041511dScube case WM_ENTERMENULOOP: 453c041511dScube /* KLUDGE: create a timer that fires every 100 ms when we start a 454c041511dScube menu so that we can still process the idle & timer events (that 455c041511dScube way, the timers will fire during a menu pick and so will the 456c041511dScube idle func. */ 457c041511dScube SetTimer(hwnd, 1, 1, NULL); 458c041511dScube return 0; 459c041511dScube 460c041511dScube case WM_TIMER: 461c041511dScube#if 0 462c041511dScube /* If the timer id is 2, then this is the timer that is set up in 463c041511dScube the main glut message processing loop, and we don't want to do 464c041511dScube anything but acknowledge that we got it. It is used to prevent 465c041511dScube CPU spiking when an idle function is installed. */ 466c041511dScube if (wParam == 2) 467c041511dScube return 0; 468c041511dScube#endif 469c041511dScube 470c041511dScube /* only worry about the idle function and the timeouts, since 471c041511dScube these are the only events we expect to process during 472c041511dScube processing of a menu. */ 473c041511dScube /* we no longer process the idle functions (as outlined in the 474c041511dScube README), since drawing can't be done until the menu has 475c041511dScube finished...it's pretty lame when the animation goes on, but 476c041511dScube doesn't update, so you get this weird jerkiness. */ 477c041511dScube#if 0 478c041511dScube if (__glutIdleFunc) 479c041511dScube __glutIdleFunc(); 480c041511dScube#endif 481c041511dScube if (__glutTimerList) 482c041511dScube handleTimeouts(); 483c041511dScube return 0; 484c041511dScube 485c041511dScube case WM_EXITMENULOOP: 486c041511dScube /* nuke the above created timer...we don't need it anymore, since 487c041511dScube the menu is gone now. */ 488c041511dScube KillTimer(hwnd, 1); 489c041511dScube return 0; 490c041511dScube 491c041511dScube case WM_MENUSELECT: 492c041511dScube if (lParam != 0) 493c041511dScube __glutHMenu = (HMENU)lParam; 494c041511dScube return 0; 495c041511dScube 496c041511dScube case WM_COMMAND: 497c041511dScube if (__glutMappedMenu) { 498c041511dScube if (GetSubMenu(__glutHMenu, LOWORD(wParam))) 499c041511dScube __glutItemSelected = NULL; 500c041511dScube else 501c041511dScube __glutItemSelected = 502c041511dScube __glutGetUniqueMenuItem(__glutMappedMenu, LOWORD(wParam)); 503c041511dScube GetCursorPos(&point); 504c041511dScube ScreenToClient(hwnd, &point); 505c041511dScube __glutFinishMenu(hwnd, point.x, point.y); 506c041511dScube } 507c041511dScube return 0; 508c041511dScube 509c041511dScube case WM_MOUSEMOVE: 510c041511dScube if (!__glutMappedMenu) { 511c041511dScube window = __glutGetWindow(hwnd); 512c041511dScube if (window) { 513c041511dScube /* If motion function registered _and_ buttons held * 514c041511dScube down, call motion function... */ 515c041511dScube x = LOWORD(lParam); 516c041511dScube y = HIWORD(lParam); 517c041511dScube 518c041511dScube /* Win32 doesn't return the same numbers as X does when the 519c041511dScube mouse goes beyond the upper or left side of the window. 520c041511dScube roll the Win32's 0..2^16 pointer co-ord range to 0..+/-2^15. */ 521c041511dScube if(x & 1 << 15) x -= (1 << 16); 522c041511dScube if(y & 1 << 15) y -= (1 << 16); 523c041511dScube 524c041511dScube if (window->motion && wParam & 525c041511dScube (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) { 526c041511dScube __glutSetWindow(window); 527c041511dScube window->motion(x, y); 528c041511dScube } 529c041511dScube /* If passive motion function registered _and_ 530c041511dScube buttons not held down, call passive motion 531c041511dScube function... */ 532c041511dScube else if (window->passive && 533c041511dScube ((wParam & 534c041511dScube (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 535c041511dScube 0)) { 536c041511dScube __glutSetWindow(window); 537c041511dScube window->passive(x, y); 538c041511dScube } 539c041511dScube } 540c041511dScube } else { 541c041511dScube /* Motion events are thrown away when a pop up menu is 542c041511dScube active. */ 543c041511dScube } 544c041511dScube return 0; 545c041511dScube 546c041511dScube case WM_GETMINMAXINFO: 547c041511dScube /* this voodoo is brought to you by Win32 (again). It allows the 548c041511dScube window to be bigger than the screen, and smaller than 100x100 549c041511dScube (although it doesn't seem to help the y minimum). */ 550c041511dScube minmax = (LPMINMAXINFO)lParam; 5512590f9beSmrg#if 0 5522590f9beSmrg /* These two lines are disabled to fix incorrect handling of 5532590f9beSmrg * window maximization on Vista. See bug 23182. 5542590f9beSmrg */ 555c041511dScube minmax->ptMaxSize.x = __glutScreenWidth; 556c041511dScube minmax->ptMaxSize.y = __glutScreenHeight; 5572590f9beSmrg#endif 558c041511dScube minmax->ptMinTrackSize.x = 0; 559c041511dScube minmax->ptMinTrackSize.y = 0; 560c041511dScube minmax->ptMaxTrackSize.x = __glutScreenWidth + 561c041511dScube GetSystemMetrics(SM_CXSIZE) * 2; 562c041511dScube minmax->ptMaxTrackSize.y = __glutScreenHeight + 563c041511dScube GetSystemMetrics(SM_CXSIZE) * 2 + GetSystemMetrics(SM_CYCAPTION); 564c041511dScube return 0; 565c041511dScube 566c041511dScube case WM_SIZE: 567c041511dScube window = __glutGetWindow(hwnd); 568c041511dScube if (window) { 569c041511dScube width = LOWORD(lParam); 570c041511dScube height = HIWORD(lParam); 571c041511dScube if (width != window->width || height != window->height) { 572c041511dScube#if 0 /* Win32 GLUT does not support overlays for now. */ 573c041511dScube if (window->overlay) { 574c041511dScube XResizeWindow(__glutDisplay, window->overlay->win, width, height); 575c041511dScube } 576c041511dScube#endif 577c041511dScube window->width = width; 578c041511dScube window->height = height; 579c041511dScube __glutSetWindow(window); 580c041511dScube /* Do not execute OpenGL out of sequence with respect 581c041511dScube to the SetWindowPos request! */ 582c041511dScube GdiFlush(); 583c041511dScube window->reshape(width, height); 584c041511dScube window->forceReshape = FALSE; 585c041511dScube /* A reshape should be considered like posting a 586c041511dScube repair request. */ 587c041511dScube __glutPostRedisplay(window, GLUT_REPAIR_WORK); 588c041511dScube } 589c041511dScube } 590c041511dScube return 0; 591c041511dScube 592c041511dScube case WM_SETCURSOR: 593c041511dScube /* If the cursor is not in the client area, then we want to send 594c041511dScube this message to the default window procedure ('cause its 595c041511dScube probably in the border or title, and we don't handle that 596c041511dScube cursor. otherwise, set our cursor. Win32 makes us set the 597c041511dScube cursor every time the mouse moves (DUMB!). */ 598c041511dScube if(LOWORD(lParam) != HTCLIENT) { 599c041511dScube goto defproc; 600c041511dScube } 601c041511dScube window = __glutGetWindow(hwnd); 602c041511dScube if (window) { 603c041511dScube __glutSetCursor(window); 604c041511dScube } 605c041511dScube /* TODO: check out the info in DevStudio on WM_SETCURSOR in the 606c041511dScube DefaultAction section. */ 607c041511dScube return 1; 608c041511dScube 609c041511dScube case WM_SETFOCUS: 610c041511dScube window = __glutGetWindow(hwnd); 611c041511dScube if (window) { 612c041511dScube window->entryState = WM_SETFOCUS; 613c041511dScube if (window->entry) { 614c041511dScube __glutSetWindow(window); 615c041511dScube window->entry(GLUT_ENTERED); 616c041511dScube /* XXX Generation of fake passive notify? See how much 617c041511dScube work the X11 code does to support fake passive notify 618c041511dScube callbacks. */ 619c041511dScube } 620c041511dScube if (window->joystick && __glutCurrentWindow) { 621c041511dScube if (__glutCurrentWindow->joyPollInterval > 0) { 622c041511dScube MMRESULT result; 623c041511dScube 624c041511dScube /* Because Win32 will only let one window capture the 625c041511dScube joystick at a time, we must capture it when we get the 626c041511dScube focus and release it when we lose the focus. */ 627c041511dScube result = joySetCapture(__glutCurrentWindow->win, 628c041511dScube JOYSTICKID1, 0, TRUE); 629c041511dScube if (result != JOYERR_NOERROR) { 630c041511dScube return 0; 631c041511dScube } 632c041511dScube (void) joySetThreshold(JOYSTICKID1, 633c041511dScube __glutCurrentWindow->joyPollInterval); 634c041511dScube } 635c041511dScube } 636c041511dScube } 637c041511dScube return 0; 638c041511dScube 639c041511dScube case WM_KILLFOCUS: 640c041511dScube window = __glutGetWindow(hwnd); 641c041511dScube if (window) { 642c041511dScube window->entryState = WM_KILLFOCUS; 643c041511dScube if (window->entry) { 644c041511dScube __glutSetWindow(window); 645c041511dScube window->entry(GLUT_LEFT); 646c041511dScube } 647c041511dScube if (window->joystick && __glutCurrentWindow) { 648c041511dScube if (__glutCurrentWindow->joyPollInterval > 0) { 649c041511dScube /* Because Win32 will only let one window capture the 650c041511dScube joystick at a time, we must capture it when we get the 651c041511dScube focus and release it when we lose the focus. */ 652c041511dScube (void) joyReleaseCapture(JOYSTICKID1); 653c041511dScube } 654c041511dScube } 655c041511dScube } 656c041511dScube return 0; 657c041511dScube case WM_ACTIVATE: 658c041511dScube window = __glutGetWindow(hwnd); 659c041511dScube /* Make sure we re-select the correct palette if needed. */ 660c041511dScube if (LOWORD(wParam)) { 661c041511dScube PostMessage(hwnd, WM_PALETTECHANGED, 0, 0); 662c041511dScube } 663c041511dScube if (window) { 664c041511dScube int visState; 665c041511dScube 666c041511dScube /* HIWORD(wParam) is the minimized flag. */ 667c041511dScube visState = !HIWORD(wParam); 668c041511dScube updateWindowState(window, visState); 669c041511dScube } 670c041511dScube return 0; 671c041511dScube 672c041511dScube /* Colour Palette Management */ 673c041511dScube case WM_PALETTECHANGED: 674c041511dScube if (hwnd == (HWND)wParam) { 675c041511dScube /* Don't respond to the message that we sent! */ 676c041511dScube break; 677c041511dScube } 678c041511dScube /* fall through to WM_QUERYNEWPALETTE */ 679c041511dScube 680c041511dScube case WM_QUERYNEWPALETTE: 681c041511dScube window = __glutGetWindow(hwnd); 682c041511dScube if (window && window->colormap) { 683c041511dScube UnrealizeObject(window->colormap->cmap); 684c041511dScube SelectPalette(window->hdc, window->colormap->cmap, FALSE); 685c041511dScube RealizePalette(window->hdc); 686c041511dScube return TRUE; 687c041511dScube } 688c041511dScube return FALSE; 689c041511dScube 690c041511dScube case MM_JOY1MOVE: 691c041511dScube case MM_JOY1ZMOVE: 692c041511dScube window = __glutGetWindow(hwnd); 693c041511dScube if (window->joystick) { 694c041511dScube JOYINFOEX jix; 695c041511dScube int x, y, z; 696c041511dScube 697c041511dScube /* Because WIN32 only supports messages for X, Y, and Z 698c041511dScube translations, we must poll for the rest */ 699c041511dScube jix.dwSize = sizeof(jix); 700c041511dScube jix.dwFlags = JOY_RETURNALL; 701c041511dScube joyGetPosEx(JOYSTICKID1,&jix); 702c041511dScube 703c041511dScube#define SCALE(v) ((int) ((v - 32767)/32.768)) 704c041511dScube 705c041511dScube /* Convert to integer for scaling. */ 706c041511dScube x = jix.dwXpos; 707c041511dScube y = jix.dwYpos; 708c041511dScube z = jix.dwZpos; 709c041511dScube window->joystick(jix.dwButtons, SCALE(x), SCALE(y), SCALE(z)); 710c041511dScube 711c041511dScube return TRUE; 712c041511dScube } 713c041511dScube return FALSE; 714c041511dScube case MM_JOY1BUTTONDOWN: 715c041511dScube case MM_JOY1BUTTONUP: 716c041511dScube window = __glutGetWindow(hwnd); 717c041511dScube if (window->joystick) { 718c041511dScube JOYINFOEX jix; 719c041511dScube 720c041511dScube /* Because WIN32 only supports messages for X, Y, and Z 721c041511dScube translations, we must poll for the rest */ 722c041511dScube jix.dwSize = sizeof(jix); 723c041511dScube jix.dwFlags = JOY_RETURNALL; 724c041511dScube joyGetPosEx(JOYSTICKID1,&jix); 725c041511dScube 726c041511dScube return TRUE; 727c041511dScube } 728c041511dScube return FALSE; 729c041511dScube 730c041511dScube#if 0 731c041511dScube /* Miscellaneous messages (don't really need to enumerate them, 732c041511dScube but it's good to know what you're not getting sometimes). */ 733c041511dScube case WM_DISPLAYCHANGE: 734c041511dScube break; 735c041511dScube case WM_NCHITTEST: 736c041511dScube /* This event is generated by every mouse move event. */ 737c041511dScube goto defproc; 738c041511dScube case WM_NCMOUSEMOVE: 739c041511dScube goto defproc; 740c041511dScube case WM_NCACTIVATE: 741c041511dScube goto defproc; 742c041511dScube case WM_NCPAINT: 743c041511dScube goto defproc; 744c041511dScube case WM_NCCALCSIZE: 745c041511dScube goto defproc; 746c041511dScube case WM_NCCREATE: 747c041511dScube goto defproc; 748c041511dScube case WM_NCDESTROY: 749c041511dScube goto defproc; 750c041511dScube case WM_NCLBUTTONDOWN: 751c041511dScube goto defproc; 752c041511dScube case WM_SETTEXT: 753c041511dScube goto defproc; 754c041511dScube case WM_GETTEXT: 755c041511dScube goto defproc; 756c041511dScube case WM_ACTIVATEAPP: 757c041511dScube goto defproc; 758c041511dScube case WM_GETICON: 759c041511dScube goto defproc; 760c041511dScube case WM_ERASEBKGND: 761c041511dScube goto defproc; 762c041511dScube case WM_WINDOWPOSCHANGING: 763c041511dScube goto defproc; 764c041511dScube case WM_WINDOWPOSCHANGED: 765c041511dScube goto defproc; 766c041511dScube case WM_MOUSEACTIVATE: 767c041511dScube goto defproc; 768c041511dScube case WM_SHOWWINDOW: 769c041511dScube goto defproc; 770c041511dScube case WM_MOVING: 771c041511dScube goto defproc; 772c041511dScube case WM_MOVE: 773c041511dScube goto defproc; 774c041511dScube case WM_KEYUP: 775c041511dScube goto defproc; 776c041511dScube case WM_CAPTURECHANGED: 777c041511dScube goto defproc; 778c041511dScube case WM_SYSCOMMAND: 779c041511dScube goto defproc; 780c041511dScube case WM_ENTERSIZEMOVE: 781c041511dScube goto defproc; 782c041511dScube case WM_ENTERIDLE: 783c041511dScube goto defproc; 784c041511dScube#endif 785c041511dScube 786c041511dScube default: 787c041511dScube goto defproc; 788c041511dScube } 789c041511dScube 790c041511dScubedefproc: 791c041511dScube return DefWindowProc(hwnd, msg, wParam, lParam); 792c041511dScube} 793