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