OSDN Git Service

configure: allow C{,XX}FLAGS override
[android-x86/external-mesa.git] / src / glut / glx / win32_menu.c
1
2 /* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
3 /* Copyright (c) Nate Robins, 1997. */
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 /* This file completely re-implements glut_menu.c and glut_menu2.c
10    for Win32.  Note that neither glut_menu.c nor glut_menu2.c are
11    compiled into Win32 GLUT. */
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <assert.h>
18
19 #include "glutint.h"
20
21 void (GLUTCALLBACK *__glutMenuStatusFunc) (int, int, int);
22 GLUTmenuItem *__glutItemSelected;
23 unsigned __glutMenuButton;
24
25 static GLUTmenu **menuList = NULL;
26 static int menuListSize = 0;
27 static UINT uniqueMenuHandler = 1;
28
29 /* DEPRICATED, use glutMenuStatusFunc instead. */
30 void GLUTAPIENTRY
31 glutMenuStateFunc(GLUTmenuStateCB menuStateFunc)
32 {
33   __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;
34 }
35
36 void GLUTAPIENTRY
37 glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc)
38 {
39   __glutMenuStatusFunc = menuStatusFunc;
40 }
41
42 void
43 __glutSetMenu(GLUTmenu * menu)
44 {
45   __glutCurrentMenu = menu;
46 }
47
48 static void
49 unmapMenu(GLUTmenu * menu)
50 {
51   if (menu->cascade) {
52     unmapMenu(menu->cascade);
53     menu->cascade = NULL;
54   }
55   menu->anchor = NULL;
56   menu->highlighted = NULL;
57 }
58
59 void
60 __glutFinishMenu(Window win, int x, int y)
61 {
62
63   unmapMenu(__glutMappedMenu);
64
65   /* XXX Put in a GdiFlush just in case.  Probably unnecessary. -mjk  */
66   GdiFlush();
67
68   if (__glutMenuStatusFunc) {
69     __glutSetWindow(__glutMenuWindow);
70     __glutSetMenu(__glutMappedMenu);
71
72     /* Setting __glutMappedMenu to NULL permits operations that
73        change menus or destroy the menu window again. */
74     __glutMappedMenu = NULL;
75
76     __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE, x, y);
77   }
78   /* Setting __glutMappedMenu to NULL permits operations that
79      change menus or destroy the menu window again. */
80   __glutMappedMenu = NULL;
81
82   /* If an item is selected and it is not a submenu trigger,
83      generate menu callback. */
84   if (__glutItemSelected && !__glutItemSelected->isTrigger) {
85     __glutSetWindow(__glutMenuWindow);
86     /* When menu callback is triggered, current menu should be
87        set to the callback menu. */
88     __glutSetMenu(__glutItemSelected->menu);
89     __glutItemSelected->menu->select(__glutItemSelected->value);
90   }
91   __glutMenuWindow = NULL;
92 }
93
94 static void
95 mapMenu(GLUTmenu * menu, int x, int y)
96 {
97   TrackPopupMenu((HMENU) menu->win, TPM_LEFTALIGN |
98     ((__glutMenuButton == TPM_RIGHTBUTTON) ? TPM_RIGHTBUTTON : TPM_LEFTBUTTON),
99     x, y, 0, __glutCurrentWindow->win, NULL);
100 }
101
102 void
103 __glutStartMenu(GLUTmenu * menu, GLUTwindow * window,
104                 int x, int y, int x_win, int y_win)
105 {
106   assert(__glutMappedMenu == NULL);
107   __glutMappedMenu = menu;
108   __glutMenuWindow = window;
109   __glutItemSelected = NULL;
110   if (__glutMenuStatusFunc) {
111     __glutSetMenu(menu);
112     __glutSetWindow(window);
113     __glutMenuStatusFunc(GLUT_MENU_IN_USE, x_win, y_win);
114   }
115   mapMenu(menu, x, y);
116 }
117
118 GLUTmenuItem *
119 __glutGetUniqueMenuItem(GLUTmenu * menu, UINT unique)
120 {
121   GLUTmenuItem *item;
122   int i;
123
124   i = menu->num;
125   item = menu->list;
126   while (item) {
127     if (item->unique == unique) {
128       return item;
129     }
130     if (item->isTrigger) {
131       GLUTmenuItem *subitem;
132       subitem = __glutGetUniqueMenuItem(menuList[item->value], unique);
133       if (subitem) {
134         return subitem;
135       }
136     }
137     i--;
138     item = item->next;
139   }
140   return NULL;
141 }
142
143 GLUTmenuItem *
144 __glutGetMenuItem(GLUTmenu * menu, Window win, int *which)
145 {
146   GLUTmenuItem *item;
147   int i;
148
149   i = menu->num;
150   item = menu->list;
151   while (item) {
152     if (item->win == win) {
153       *which = i;
154       return item;
155     }
156     if (item->isTrigger) {
157       GLUTmenuItem *subitem;
158
159       subitem = __glutGetMenuItem(menuList[item->value],
160         win, which);
161       if (subitem) {
162         return subitem;
163       }
164     }
165     i--;
166     item = item->next;
167   }
168   return NULL;
169 }
170
171 GLUTmenu *
172 __glutGetMenu(Window win)
173 {
174   GLUTmenu *menu;
175
176   menu = __glutMappedMenu;
177   while (menu) {
178     if (win == menu->win) {
179       return menu;
180     }
181     menu = menu->cascade;
182   }
183   return NULL;
184 }
185
186 GLUTmenu *
187 __glutGetMenuByNum(int menunum)
188 {
189   if (menunum < 1 || menunum > menuListSize) {
190     return NULL;
191   }
192   return menuList[menunum - 1];
193 }
194
195 static int
196 getUnusedMenuSlot(void)
197 {
198   int i;
199
200   /* Look for allocated, unused slot. */
201   for (i = 0; i < menuListSize; i++) {
202     if (!menuList[i]) {
203       return i;
204     }
205   }
206   /* Allocate a new slot. */
207   menuListSize++;
208   if (menuList) {
209     menuList = (GLUTmenu **)
210       realloc(menuList, menuListSize * sizeof(GLUTmenu *));
211   } else {
212     /* XXX Some realloc's do not correctly perform a malloc
213        when asked to perform a realloc on a NULL pointer,
214        though the ANSI C library spec requires this. */
215     menuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *));
216   }
217   if (!menuList) {
218     __glutFatalError("out of memory.");
219   }
220   menuList[menuListSize - 1] = NULL;
221   return menuListSize - 1;
222 }
223
224 static void
225 menuModificationError(void)
226 {
227   /* XXX Remove the warning after GLUT 3.0. */
228   __glutWarning("The following is a new check for GLUT 3.0; update your code.");
229   __glutFatalError("menu manipulation not allowed while menus in use.");
230 }
231
232 int GLUTAPIENTRY
233 glutCreateMenu(GLUTselectCB selectFunc)
234 {
235   GLUTmenu *menu;
236   int menuid;
237
238   if (__glutMappedMenu) {
239     menuModificationError();
240   }
241   menuid = getUnusedMenuSlot();
242   menu = (GLUTmenu *) malloc(sizeof(GLUTmenu));
243   if (!menu) {
244     __glutFatalError("out of memory.");
245   }
246   menu->id = menuid;
247   menu->num = 0;
248   menu->submenus = 0;
249   menu->select = selectFunc;
250   menu->list = NULL;
251   menu->cascade = NULL;
252   menu->highlighted = NULL;
253   menu->anchor = NULL;
254   menu->win = (HWND) CreatePopupMenu();
255   menuList[menuid] = menu;
256   __glutSetMenu(menu);
257   return menuid + 1;
258 }
259
260 int GLUTAPIENTRY
261 __glutCreateMenuWithExit(GLUTselectCB selectFunc, void (__cdecl *exitfunc)(int))
262 {
263   __glutExitFunc = exitfunc;
264   return glutCreateMenu(selectFunc);
265 }
266
267 void GLUTAPIENTRY
268 glutDestroyMenu(int menunum)
269 {
270   GLUTmenu *menu = __glutGetMenuByNum(menunum);
271   GLUTmenuItem *item, *next;
272
273   if (__glutMappedMenu) {
274     menuModificationError();
275   }
276   assert(menu->id == menunum - 1);
277   DestroyMenu( (HMENU) menu->win);
278   menuList[menunum - 1] = NULL;
279   /* free all menu entries */
280   item = menu->list;
281   while (item) {
282     assert(item->menu == menu);
283     next = item->next;
284     free(item->label);
285     free(item);
286     item = next;
287   }
288   if (__glutCurrentMenu == menu) {
289     __glutCurrentMenu = NULL;
290   }
291   free(menu);
292 }
293
294 int GLUTAPIENTRY
295 glutGetMenu(void)
296 {
297   if (__glutCurrentMenu) {
298     return __glutCurrentMenu->id + 1;
299   } else {
300     return 0;
301   }
302 }
303
304 void GLUTAPIENTRY
305 glutSetMenu(int menuid)
306 {
307   GLUTmenu *menu;
308
309   if (menuid < 1 || menuid > menuListSize) {
310     __glutWarning("glutSetMenu attempted on bogus menu.");
311     return;
312   }
313   menu = menuList[menuid - 1];
314   if (!menu) {
315     __glutWarning("glutSetMenu attempted on bogus menu.");
316     return;
317   }
318   __glutSetMenu(menu);
319 }
320
321 static void
322 setMenuItem(GLUTmenuItem * item, const char *label,
323             int value, Bool isTrigger)
324 {
325   GLUTmenu *menu;
326
327   menu = item->menu;
328   item->label = __glutStrdup(label);
329   if (!item->label) {
330     __glutFatalError("out of memory.");
331   }
332   item->isTrigger = isTrigger;
333   item->len = (int) strlen(label);
334   item->value = value;
335   item->unique = uniqueMenuHandler++;
336   if (isTrigger) {
337     AppendMenu((HMENU) menu->win, MF_POPUP, (UINT)item->win, label);
338   } else {
339     AppendMenu((HMENU) menu->win, MF_STRING, item->unique, label);
340   }
341 }
342
343 void GLUTAPIENTRY
344 glutAddMenuEntry(const char *label, int value)
345 {
346   GLUTmenuItem *entry;
347
348   if (__glutMappedMenu) {
349     menuModificationError();
350   }
351   entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
352   if (!entry) {
353     __glutFatalError("out of memory.");
354   }
355   entry->menu = __glutCurrentMenu;
356   setMenuItem(entry, label, value, FALSE);
357   __glutCurrentMenu->num++;
358   entry->next = __glutCurrentMenu->list;
359   __glutCurrentMenu->list = entry;
360 }
361
362 void GLUTAPIENTRY
363 glutAddSubMenu(const char *label, int menu)
364 {
365   GLUTmenuItem *submenu;
366   GLUTmenu     *popupmenu;
367
368   if (__glutMappedMenu) {
369     menuModificationError();
370   }
371   submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
372   if (!submenu) {
373     __glutFatalError("out of memory.");
374   }
375   __glutCurrentMenu->submenus++;
376   submenu->menu = __glutCurrentMenu;
377   popupmenu = __glutGetMenuByNum(menu);
378   if (popupmenu) {
379     submenu->win = popupmenu->win;
380   }
381   setMenuItem(submenu, label, /* base 0 */ menu - 1, TRUE);
382   __glutCurrentMenu->num++;
383   submenu->next = __glutCurrentMenu->list;
384   __glutCurrentMenu->list = submenu;
385 }
386
387 void GLUTAPIENTRY
388 glutChangeToMenuEntry(int num, const char *label, int value)
389 {
390   GLUTmenuItem *item;
391   int i;
392
393   if (__glutMappedMenu) {
394     menuModificationError();
395   }
396   i = __glutCurrentMenu->num;
397   item = __glutCurrentMenu->list;
398   while (item) {
399     if (i == num) {
400       if (item->isTrigger) {
401         /* If changing a submenu trigger to a menu entry, we
402            need to account for submenus.  */
403         item->menu->submenus--;
404         /* Nuke the Win32 menu. */
405         DestroyMenu((HMENU) item->win);
406       }
407       free(item->label);
408
409       item->label = strdup(label);
410       if (!item->label)
411         __glutFatalError("out of memory");
412       item->isTrigger = FALSE;
413       item->len = (int) strlen(label);
414       item->value = value;
415       item->unique = uniqueMenuHandler++;
416       ModifyMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1,
417         MF_BYPOSITION | MFT_STRING, item->unique, label);
418
419       return;
420     }
421     i--;
422     item = item->next;
423   }
424   __glutWarning("Current menu has no %d item.", num);
425 }
426
427 void GLUTAPIENTRY
428 glutChangeToSubMenu(int num, const char *label, int menu)
429 {
430   GLUTmenu *popupmenu;
431   GLUTmenuItem *item;
432   int i;
433
434   if (__glutMappedMenu) {
435     menuModificationError();
436   }
437   i = __glutCurrentMenu->num;
438   item = __glutCurrentMenu->list;
439   while (item) {
440     if (i == num) {
441       if (!item->isTrigger) {
442         /* If changing a menu entry to as submenu trigger, we
443            need to account for submenus.  */
444         item->menu->submenus++;
445         item->win = (HWND) CreatePopupMenu();
446       }
447       free(item->label);
448       
449       item->label = strdup(label);
450       if (!item->label)
451         __glutFatalError("out of memory");
452       item->isTrigger = TRUE;
453       item->len = (int) strlen(label);
454       item->value = menu - 1;
455       item->unique = uniqueMenuHandler++;
456       popupmenu = __glutGetMenuByNum(menu);
457       if (popupmenu)
458         item->win = popupmenu->win;
459       ModifyMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1,
460         MF_BYPOSITION | MF_POPUP, (UINT) item->win, label);
461       return;
462     }
463     i--;
464     item = item->next;
465   }
466   __glutWarning("Current menu has no %d item.", num);
467 }
468
469 void GLUTAPIENTRY
470 glutRemoveMenuItem(int num)
471 {
472   GLUTmenuItem *item, **prev;
473   int i;
474
475   if (__glutMappedMenu) {
476     menuModificationError();
477   }
478   i = __glutCurrentMenu->num;
479   prev = &__glutCurrentMenu->list;
480   item = __glutCurrentMenu->list;
481   while (item) {
482     if (i == num) {
483       /* Found the menu item in list to remove. */
484       __glutCurrentMenu->num--;
485
486       /* Patch up menu's item list. */
487       *prev = item->next;
488
489       RemoveMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION);
490
491       free(item->label);
492       free(item);
493       return;
494     }
495     i--;
496     prev = &item->next;
497     item = item->next;
498   }
499   __glutWarning("Current menu has no %d item.", num);
500 }
501
502 void GLUTAPIENTRY
503 glutAttachMenu(int button)
504 {
505   if (__glutCurrentWindow == __glutGameModeWindow) {
506     __glutWarning("cannot attach menus in game mode.");
507     return;
508   }
509   if (__glutMappedMenu) {
510     menuModificationError();
511   }
512   if (__glutCurrentWindow->menu[button] < 1) {
513     __glutCurrentWindow->buttonUses++;
514   }
515   __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;
516 }
517
518 void GLUTAPIENTRY
519 glutDetachMenu(int button)
520 {
521   if (__glutMappedMenu) {
522     menuModificationError();
523   }
524   if (__glutCurrentWindow->menu[button] > 0) {
525     __glutCurrentWindow->buttonUses--;
526     __glutCurrentWindow->menu[button] = 0;
527   }
528 }
529