1: /* $Header: XMenuActivate.c,v 10.16 86/02/01 16:14:11 tony Rel $ */
2: /* Copyright Massachusetts Institute of Technology 1985 */
3:
4: /*
5: * XMenu: MIT Project Athena, X Window system menu package
6: *
7: * XMenuActivate - Maps a given menu to the display and activates
8: * the menu for user selection. The user is allowed to
9: * specify which pane and selection will be current,
10: * the X and Y location of the menu (relative to the
11: * parent window) and the mouse button event mask that
12: * will be used to identify a selection request.
13: *
14: * A menu selection is shown to be current by placing
15: * a highlight box around the selection as the mouse
16: * cursor enters its active region. Inactive selections
17: * will not be highlited. As the mouse cursor moved
18: * from one menu pane to another menu pane the pane being
19: * entered is raised and made current and the pane being
20: * left is lowered.
21: *
22: * Anytime XMenuActivate returns, the p_num and
23: * s_num are left at their last known values (i.e.,
24: * the last known current pane and selection indices).
25: * The following are the defined return states:
26: *
27: * 1) If at any time an error occurs the data
28: * pointer is left untouched and XM_FAILURE
29: * is returned.
30: *
31: * 2) When a selection request is recieved (i.e.,
32: * when the specified mouse event occurs) the
33: * data pointer will be set to the data
34: * associated with the particular selection
35: * current at the time of the selection request
36: * and XM_SUCCESS is returned.
37: *
38: * 3) If no selection was current at the time a
39: * selection request is made the data pointer
40: * will be left untouched and XM_NO_SELECT will
41: * be returned.
42: *
43: * 4) If the selection that was current at the time
44: * a selection request is made is not an active
45: * selection the data pointer will be left
46: * untouched and XM_IA_SELECT will be returned.
47: *
48: * Author: Tony Della Fera, DEC
49: * January 13, 1986
50: *
51: */
52:
53: #include "XMenuInternal.h"
54:
55:
56: XMenuActivate(menu, p_num, s_num, x_pos, y_pos, event_mask, data)
57: register XMenu *menu; /* Menu to activate. */
58: int *p_num; /* Pane number selected. */
59: int *s_num; /* Selection number selected. */
60: int x_pos; /* X coordinate of menu position. */
61: int y_pos; /* Y coordinate of menu position. */
62: int event_mask; /* Mouse button event mask. */
63: char **data; /* Pointer to return data value. */
64: {
65: register int i; /* Loop counter. */
66: int status; /* X routine call status. */
67: int orig_x; /* Upper left menu origin X coord. */
68: int orig_y; /* Upper left menu origin Y coord. */
69: int save_x; /* Upper left X of save region. */
70: int save_y; /* Upper left Y of save region. */
71: int save_w; /* Width of pixmap save region. */
72: int save_h; /* Height of pixmap save region. */
73: int save_w_offscr; /* Pixmap save width off screen. */
74: int save_h_offscr; /* Pixmap save height off screen. */
75: int x, y; /* Dummy X and Y arguments. */
76: int ret_val; /* Return value. */
77:
78: register XMPane *p_ptr; /* Current XMPane. */
79: register XMPane *event_xmp; /* Event XMPane pointer. */
80: register XMPane *cur_p; /* Current pane. */
81: register XMSelect *cur_s; /* Current selection. */
82: XMWindow *event_xmw; /* Event XMWindow pointer. */
83: XEvent event; /* X input event. */
84: XCrossingEvent *xc_event; /* X window crossing event. */
85: Window xc_window; /* X window crossing event window. */
86:
87: Pixmap save_pixmap; /* Pixmap to save bits under menu. */
88:
89: Bool saved = TRUE; /* Pixmap save succeeded. */
90: Bool selection = FALSE; /* Selection has been made. */
91: Bool forward = TRUE; /* Moving forward in the pane list. */
92: Bool p_lock = TRUE; /* Pane entrance lock. */
93: Bool s_lock = TRUE; /* Selection entrance lock. */
94:
95: /*
96: * Are the position arguments are positive?
97: */
98: if ((x_pos <= 0) || (y_pos <= 0)) {
99: _XMErrorCode = XME_ARG_BOUNDS;
100: return(XM_FAILURE);
101: }
102:
103: /*
104: * If there are no panes in the menu then return failure
105: * beacuse the menu is not initialized.
106: */
107: if (menu->p_count == 0) {
108: _XMErrorCode = XME_NOT_INIT;
109: return(XM_FAILURE);
110: }
111:
112: /*
113: * Find the desired current pane.
114: */
115: cur_p = _XMGetPanePtr(menu, *p_num);
116: if (cur_p == NULL) return(XM_FAILURE);
117:
118: /*
119: * Find the desired current selection.
120: */
121: cur_s = _XMGetSelectionPtr(cur_p, *s_num);
122: if (cur_s == NULL) return(XM_FAILURE);
123:
124: /*
125: * Check to see that the menu's dependencies have been
126: * recomputed and are up to date. If not, do it now.
127: */
128: if (menu->recompute) XMenuRecompute(menu);
129:
130: /*
131: * If the current pane is active then activate it.
132: */
133: if (cur_p->active) {
134: cur_p->activated = 1;
135: XChangeBackground(cur_p->window, menu->bkgnd_pixmap);
136: }
137:
138: /*
139: * Compute the new menu origin such that the cursor hot point lies
140: * in the center of the desired current pane and selection.
141: */
142: _XMTransToOrigin(menu, cur_p, cur_s, x_pos, y_pos, &orig_x, &orig_y);
143:
144: /*
145: * Then move all the panes into position relative to the newly
146: * computed origin.
147: */
148: for (
149: p_ptr = menu->p_list->next;
150: p_ptr != menu->p_list;
151: p_ptr = p_ptr->next
152: ){
153: XMoveWindow(
154: p_ptr->window,
155: orig_x + p_ptr->window_x,
156: orig_y + p_ptr->window_y
157: );
158: }
159:
160: /*<
161: * If server freeze mode is selected...
162: */
163: if (menu->freeze) {
164: /*
165: * Compute pixmap save region.
166: */
167: save_x = max(orig_x, 0);
168: save_y = max(orig_y, 0);
169: save_w_offscr = (orig_x + menu->width) - DisplayWidth();
170: save_h_offscr = (orig_y + menu->height) - DisplayHeight();
171: if (save_w_offscr < 0) save_w = menu->width;
172: else save_w = menu->width - save_w_offscr;
173: if (save_h_offscr < 0) save_h = menu->height;
174: else save_h = menu->height - save_h_offscr;
175:
176: /*
177: * Grab the X server.
178: */
179: XGrabServer();
180:
181: /*
182: * Save the bits under where the menu will be.
183: */
184: save_pixmap = XPixmapSave(
185: menu->parent,
186: save_x, save_y,
187: save_w, save_h
188: );
189: if (save_pixmap == _X_FAILURE) saved = FALSE;
190: }
191: else {
192: saved = FALSE;
193: }
194:
195: /*
196: * Synchronize the X buffers and the event queue.
197: * From here on, all events in the queue that don't belong to
198: * XMenu are send back to the application via an application
199: * provided event handler or discarded if the application has
200: * not provided an event handler.
201: */
202: XSync(0);
203:
204: /*
205: * Grab the mouse for menu input.
206: */
207: status = XGrabMouse(menu->parent, menu->mouse_cursor, event_mask);
208: if (status == _X_FAILURE) {
209: _XMErrorCode = XME_GRAB_MOUSE;
210: return(XM_FAILURE);
211: }
212:
213: /*
214: * Map the menu panes.
215: */
216: for (
217: p_ptr = menu->p_list->prev;
218: p_ptr != menu->p_list;
219: p_ptr = p_ptr->prev
220: ){
221: if (p_ptr == cur_p) break;
222: XMapWindow(p_ptr->window);
223: }
224: for (
225: p_ptr = menu->p_list->next;
226: p_ptr != menu->p_list;
227: p_ptr = p_ptr->next
228: ){
229: if (p_ptr == cur_p) break;
230: XMapWindow(p_ptr->window);
231: }
232: XMapWindow(cur_p->window);
233:
234: /*
235: * Clear the current selection.
236: */
237: cur_s = NULL;
238:
239: /*
240: * Begin event processing loop.
241: */
242: while (1) {
243: /*
244: * Fetch the next event.
245: */
246: XNextEvent(&event);
247: /*
248: * Dispatch on the event type.
249: */
250: switch (event.type) {
251: case :
252: event_xmp = (XMPane *)XLookUpAssoc(
253: menu->assoc_tab, event.window
254: );
255: if (event_xmp == NULL) {
256: if (_XMEventHandler) (*_XMEventHandler)(&event);
257: break;
258: }
259: if (event_xmp == cur_p) {
260: _XMRefreshPane(menu, cur_p);
261: }
262: else _XMRefreshPaneText(menu, event_xmp);
263: break;
264: case :
265: event_xmw = (XMWindow *)XLookUpAssoc(
266: menu->assoc_tab,
267: event.window
268: );
269: if (event_xmw == NULL) break;
270: if (event_xmw->type == SELECTION) {
271: /*
272: * We have entered a selection.
273: */
274: cur_s = (XMSelect *)event_xmw;
275: /*
276: * If the pane we are in is active and the
277: * selection entered is active then activate
278: * the selection.
279: */
280: if (cur_p->active && cur_s->active) {
281: cur_s->activated = 1;
282: _XMRefreshSelection(menu, cur_s);
283: }
284: }
285: else {
286: /*
287: * We have entered a pane.
288: */
289: xc_event = (XCrossingEvent *)&event;
290: status = XInterpretLocator(
291: menu->parent,
292: &x, &y,
293: &xc_window,
294: xc_event->location
295: );
296: if (status == _X_FAILURE) {
297: _XMErrorCode = XME_INTERP_LOC;
298: return(XM_FAILURE);
299: }
300: event_xmp = (XMPane *)XLookUpAssoc(
301: menu->assoc_tab,
302: xc_window
303: );
304: if (event_xmp->window == cur_p->window) break;
305: if (event_xmp->serial > cur_p->serial) forward = TRUE;
306: else forward = FALSE;
307: p_ptr = cur_p;
308: while(1) {
309: if (forward) p_ptr = p_ptr->next;
310: else p_ptr = p_ptr->prev;
311: /*
312: * If the new pane is an active pane then
313: * activate it.
314: */
315: if (p_ptr->active) {
316: p_ptr->activated = 1;
317: XChangeBackground(
318: p_ptr->window,
319: menu->bkgnd_pixmap
320: );
321: XClear(p_ptr->window);
322: }
323: /*
324: * Raise the new pane.
325: */
326: XRaiseWindow(p_ptr->window);
327: /*
328: * If the previous current pane was activated
329: * deactivate it.
330: */
331: if (cur_p->activated) {
332: cur_p->activated = 0;
333: XChangeBackground(
334: cur_p->window,
335: menu->inact_pixmap
336: );
337: _XMRefreshPaneText(menu, cur_p);
338: }
339: /*
340: * Make the new pane the current pane.
341: */
342: cur_p = p_ptr;
343: /*
344: * If we have cycled through to the event
345: * pane we are done.
346: */
347: if (p_ptr->window == event_xmp->window) break;
348: }
349: }
350: break;
351: case :
352: event_xmw = (XMWindow *)XLookUpAssoc(
353: menu->assoc_tab,
354: event.window
355: );
356: if (event_xmw == NULL) break;
357: /*
358: * If the current selection was activated then
359: * deactivate it.
360: */
361: if (cur_s->activated) {
362: cur_s->activated = 0;
363: _XMRefreshSelection(menu, cur_s);
364: }
365: cur_s = NULL;
366: break;
367: case :
368: case :
369: *p_num = cur_p->serial;
370: /*
371: * Check to see if there is a current selecion.
372: */
373: if (cur_s != NULL) {
374: /*
375: * Set the selection number to the current selection.
376: */
377: *s_num = cur_s->serial;
378: /*
379: * If the current selection was activated then
380: * we have a valid selection otherwise we have
381: * an inactive selection.
382: */
383: if (cur_s->activated) {
384: *data = cur_s->data;
385: ret_val = XM_SUCCESS;
386: }
387: else {
388: ret_val = XM_IA_SELECT;
389: }
390: }
391: else {
392: /*
393: * No selection was current.
394: */
395: ret_val = XM_NO_SELECT;
396: }
397: selection = TRUE;
398: break;
399: default:
400: if (_XMEventHandler) (*_XMEventHandler)(&event);
401: }
402: /*
403: * If a selection has been made, break out of the event loop.
404: */
405: if (selection == TRUE) break;
406: }
407:
408: /*
409: * Unmap the menu.
410: */
411: if (saved) {
412: for (
413: p_ptr = menu->p_list->next;
414: p_ptr != menu->p_list;
415: p_ptr = p_ptr->next
416: ) {
417: XUnmapTransparent(p_ptr->window);
418: }
419: }
420: else {
421: for (
422: p_ptr = menu->p_list->next;
423: p_ptr != menu->p_list;
424: p_ptr = p_ptr->next
425: ) {
426: XUnmapWindow(p_ptr->window);
427: }
428: }
429:
430: /*
431: * Ungrab the mouse.
432: */
433: XUngrabMouse();
434:
435: /*
436: * Restore bits under where the menu was if we managed
437: * to save them and free the pixmap.
438: */
439: if (saved) {
440: XPixmapPut(
441: menu->parent,
442: 0, 0,
443: save_x, save_y,
444: save_w, save_h,
445: save_pixmap,
446: GXcopy, AllPlanes
447: );
448: XFreePixmap(save_pixmap);
449: }
450:
451: /*
452: * Ungrab the X server.
453: */
454: if (menu->freeze) XUngrabServer();
455:
456: /*
457: * If there is a current selection deactivate it.
458: */
459: if (cur_s != NULL) cur_s->activated = 0;
460:
461: /*
462: * Deactivate the current pane.
463: */
464: cur_p->activated = 0;
465: XChangeBackground(cur_p->window, menu->inact_pixmap);
466:
467: /*
468: * Synchronize the X buffers and the event queue.
469: */
470: XSync(0);
471:
472: /*
473: * Now discard any extraneous events.
474: */
475: while (QLength()) {
476: /*
477: * Fetch the next event.
478: */
479: XNextEvent(&event);
480:
481: /*
482: * Dispatch on the event type.
483: */
484: switch (event.type) {
485: case ExposeWindow:
486: case EnterWindow:
487: case LeaveWindow:
488: case ButtonPressed:
489: case ButtonReleased:
490: event_xmp = (XMPane *)XLookUpAssoc(
491: menu->assoc_tab,
492: event.window
493: );
494: if ((event_xmp == NULL) && (_XMEventHandler != NULL))
495: (*_XMEventHandler)(&event);
496: break;
497: default:
498: if (_XMEventHandler) (*_XMEventHandler)(&event);
499: }
500: }
501:
502: /*
503: * Return successfully.
504: */
505: _XMErrorCode = XME_NO_ERROR;
506: return(ret_val);
507: }