|
|
1.1 ! root 1: /* $Header: Activate.c,v 1.14 87/09/10 20:30:01 chris Exp $ */ ! 2: /* Copyright Massachusetts Institute of Technology 1985 */ ! 3: ! 4: #include <X11/copyright.h> ! 5: ! 6: /* ! 7: * XMenu: MIT Project Athena, X Window system menu package ! 8: * ! 9: * XMenuActivate - Maps a given menu to the display and activates ! 10: * the menu for user selection. The user is allowed to ! 11: * specify which pane and selection will be current, ! 12: * the X and Y location of the menu (relative to the ! 13: * parent window) and the mouse button event mask that ! 14: * will be used to identify a selection request. ! 15: * ! 16: * A menu selection is shown to be current by placing ! 17: * a highlight box around the selection as the mouse ! 18: * cursor enters its active region. Inactive selections ! 19: * will not be highlited. As the mouse cursor moved ! 20: * from one menu pane to another menu pane the pane being ! 21: * entered is raised and made current and the pane being ! 22: * left is lowered. ! 23: * ! 24: * Anytime XMenuActivate returns, the p_num and ! 25: * s_num are left at their last known values (i.e., ! 26: * the last known current pane and selection indices). ! 27: * The following are the defined return states: ! 28: * ! 29: * 1) If at any time an error occurs the data ! 30: * pointer is left untouched and XM_FAILURE ! 31: * is returned. ! 32: * ! 33: * 2) When a selection request is recieved (i.e., ! 34: * when the specified mouse event occurs) the ! 35: * data pointer will be set to the data ! 36: * associated with the particular selection ! 37: * current at the time of the selection request ! 38: * and XM_SUCCESS is returned. ! 39: * ! 40: * 3) If no selection was current at the time a ! 41: * selection request is made the data pointer ! 42: * will be left untouched and XM_NO_SELECT will ! 43: * be returned. ! 44: * ! 45: * 4) If the selection that was current at the time ! 46: * a selection request is made is not an active ! 47: * selection the data pointer will be left ! 48: * untouched and XM_IA_SELECT will be returned. ! 49: * ! 50: * Since X processes events in an asynchronous manner ! 51: * it is likely that XMenuActivate will encounter ! 52: * a "foreign event" while it is executing. Foreign ! 53: * events are handled in one of three ways: ! 54: * ! 55: * 1) The event is discarded. This is the default ! 56: * mode and requires no action on the part of the ! 57: * application. ! 58: * ! 59: * 2) The application has identified an asynchronous ! 60: * event handler that will be called and the ! 61: * foreign event handed off to it. Note: ! 62: * AEQ mode disables this mode temporarily. ! 63: * ! 64: * 3) The application has enabled asynchronous event ! 65: * queueing mode. In this mode all foreign events ! 66: * will be queued up untill XMenuActivate ! 67: * terminates; at which time they will be ! 68: * returned to the X event queue. As long as ! 69: * AEQ mode is enabled any asynchronous event ! 70: * handler as temporarily disabled. ! 71: * ! 72: * Any events encountered while taking down the menu ! 73: * (i.e., exposure events from occluded windows) will ! 74: * automatically be returned to the X event queue after ! 75: * XMenuActivate has cleaned the queue of any of its own ! 76: * events that are no longer needed. ! 77: * ! 78: * Author: Tony Della Fera, DEC ! 79: * March 12, 1986 ! 80: * ! 81: */ ! 82: ! 83: #include "XMenuInternal.h" ! 84: ! 85: int ! 86: XMenuActivate(display, menu, p_num, s_num, x_pos, y_pos, event_mask, data) ! 87: register Display *display; /* Display to put menu on. */ ! 88: register XMenu *menu; /* Menu to activate. */ ! 89: int *p_num; /* Pane number selected. */ ! 90: int *s_num; /* Selection number selected. */ ! 91: int x_pos; /* X coordinate of menu position. */ ! 92: int y_pos; /* Y coordinate of menu position. */ ! 93: unsigned int event_mask; /* Mouse button event mask. */ ! 94: char **data; /* Pointer to return data value. */ ! 95: { ! 96: int status; /* X routine call status. */ ! 97: int orig_x; /* Upper left menu origin X coord. */ ! 98: int orig_y; /* Upper left menu origin Y coord. */ ! 99: int ret_val; /* Return value. */ ! 100: ! 101: register XMPane *p_ptr; /* Current XMPane. */ ! 102: register XMPane *event_xmp; /* Event XMPane pointer. */ ! 103: register XMPane *cur_p; /* Current pane. */ ! 104: register XMSelect *cur_s; /* Current selection. */ ! 105: XMWindow *event_xmw; /* Event XMWindow pointer. */ ! 106: XEvent event; /* X input event. */ ! 107: XEvent peek_event; /* X input peek ahead event. */ ! 108: ! 109: Bool selection = False; /* Selection has been made. */ ! 110: Bool forward = True; /* Moving forward in the pane list. */ ! 111: ! 112: Window root, child; ! 113: int root_x, root_y, win_x, win_y; ! 114: unsigned int mask; ! 115: ! 116: /* ! 117: * Define and allocate a foreign event queue to hold events ! 118: * that don't belong to XMenu. These events are later restored ! 119: * to the X event queue. ! 120: */ ! 121: typedef struct _xmeventque { ! 122: XEvent event; ! 123: struct _xmeventque *next; ! 124: } XMEventQue; ! 125: ! 126: XMEventQue *feq = NULL; /* Foreign event queue. */ ! 127: XMEventQue *feq_tmp; /* Foreign event queue temporary. */ ! 128: ! 129: /* ! 130: * If there are no panes in the menu then return failure ! 131: * because the menu is not initialized. ! 132: */ ! 133: if (menu->p_count == 0) { ! 134: _XMErrorCode = XME_NOT_INIT; ! 135: return(XM_FAILURE); ! 136: } ! 137: ! 138: /* ! 139: * Find the desired current pane. ! 140: */ ! 141: cur_p = _XMGetPanePtr(menu, *p_num); ! 142: if (cur_p == NULL) { ! 143: return(XM_FAILURE); ! 144: } ! 145: cur_p->activated = cur_p->active; ! 146: ! 147: /* ! 148: * Find the desired current selection. ! 149: * If the current selection index is out of range a null current selection ! 150: * will be assumed and the cursor will be placed in the current pane ! 151: * header. ! 152: */ ! 153: cur_s = _XMGetSelectionPtr(cur_p, *s_num); ! 154: ! 155: /* ! 156: * Compute origin of menu so that cursor is in ! 157: * Correct pane and selection. ! 158: */ ! 159: _XMTransToOrigin(display, ! 160: menu, ! 161: cur_p, cur_s, ! 162: x_pos, y_pos, ! 163: &orig_x, &orig_y); ! 164: menu->x_pos = orig_x; /* Store X and Y coords of menu. */ ! 165: menu->y_pos = orig_y; ! 166: ! 167: if (XMenuRecompute(display, menu) == XM_FAILURE) { ! 168: return(XM_FAILURE); ! 169: } ! 170: ! 171: /* ! 172: * Flush the window creation queue. ! 173: * This batches all window creates since lazy evaluation ! 174: * is more efficient than individual evaluation. ! 175: * This routine also does an XFlush(). ! 176: */ ! 177: if (_XMWinQueFlush(display, menu, cur_p, cur_s) == _FAILURE) { ! 178: return(XM_FAILURE); ! 179: } ! 180: ! 181: /* ! 182: * Make sure windows are in correct order (in case we were passed ! 183: * an already created menu in incorrect order.) ! 184: */ ! 185: for(p_ptr = menu->p_list->next; p_ptr != cur_p; p_ptr = p_ptr->next) ! 186: XRaiseWindow(display, p_ptr->window); ! 187: for(p_ptr = menu->p_list->prev; p_ptr != cur_p->prev; p_ptr = p_ptr->prev) ! 188: XRaiseWindow(display, p_ptr->window); ! 189: ! 190: /* ! 191: * Make sure all selection windows are mapped. ! 192: */ ! 193: for ( ! 194: p_ptr = menu->p_list->next; ! 195: p_ptr != menu->p_list; ! 196: p_ptr = p_ptr->next ! 197: ){ ! 198: XMapSubwindows(display, p_ptr->window); ! 199: } ! 200: ! 201: /* ! 202: * Synchronize the X buffers and the event queue. ! 203: * From here on, all events in the queue that don't belong to ! 204: * XMenu are sent back to the application via an application ! 205: * provided event handler or discarded if the application has ! 206: * not provided an event handler. ! 207: */ ! 208: XSync(display, 0); ! 209: ! 210: /* ! 211: * Grab the mouse for menu input. ! 212: */ ! 213: ! 214: status = XGrabPointer( ! 215: display, ! 216: menu->parent, ! 217: True, ! 218: event_mask, ! 219: GrabModeAsync, ! 220: GrabModeAsync, ! 221: None, ! 222: menu->mouse_cursor, ! 223: CurrentTime ! 224: ); ! 225: if (status == _X_FAILURE) { ! 226: _XMErrorCode = XME_GRAB_MOUSE; ! 227: return(XM_FAILURE); ! 228: } ! 229: ! 230: /* ! 231: * Map the menu panes. ! 232: */ ! 233: XMapWindow(display, cur_p->window); ! 234: for (p_ptr = menu->p_list->next; ! 235: p_ptr != cur_p; ! 236: p_ptr = p_ptr->next) ! 237: XMapWindow(display, p_ptr->window); ! 238: for (p_ptr = cur_p->next; ! 239: p_ptr != menu->p_list; ! 240: p_ptr = p_ptr->next) ! 241: XMapWindow(display, p_ptr->window); ! 242: ! 243: XRaiseWindow(display, cur_p->window); /* Make sure current */ ! 244: /* pane is on top. */ ! 245: ! 246: cur_s = NULL; /* Clear current selection. */ ! 247: ! 248: /* ! 249: * Begin event processing loop. ! 250: */ ! 251: while (1) { ! 252: XNextEvent(display, &event); /* Get next event. */ ! 253: switch (event.type) { /* Dispatch on the event type. */ ! 254: case Expose: ! 255: event_xmp = (XMPane *)XLookUpAssoc(display, ! 256: menu->assoc_tab, ! 257: event.xexpose.window); ! 258: if (event_xmp == NULL) { ! 259: /* ! 260: * If AEQ mode is enabled then queue the event. ! 261: */ ! 262: if (menu->aeq) { ! 263: feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue)); ! 264: if (feq_tmp == NULL) { ! 265: _XMErrorCode = XME_CALLOC; ! 266: return(XM_FAILURE); ! 267: } ! 268: feq_tmp->event = event; ! 269: feq_tmp->next = feq; ! 270: feq = feq_tmp; ! 271: } ! 272: else if (_XMEventHandler) (*_XMEventHandler)(&event); ! 273: break; ! 274: } ! 275: if (event_xmp->activated) { ! 276: XSetWindowBackground(display, ! 277: event_xmp->window, ! 278: menu->bkgnd_color); ! 279: } ! 280: else { ! 281: XSetWindowBackgroundPixmap(display, ! 282: event_xmp->window, ! 283: menu->inact_pixmap); ! 284: } ! 285: _XMRefreshPane(display, menu, event_xmp); ! 286: break; ! 287: case EnterNotify: ! 288: /* ! 289: * First wait a small period of time, and see ! 290: * if another EnterNotify event follows hard on the ! 291: * heels of this one. i.e., the user is simply ! 292: * "passing through". If so, ignore this one. ! 293: */ ! 294: ! 295: event_xmw = (XMWindow *)XLookUpAssoc(display, ! 296: menu->assoc_tab, ! 297: event.xcrossing.window); ! 298: if (event_xmw == NULL) break; ! 299: if (event_xmw->type == SELECTION) { ! 300: /* ! 301: * We have entered a selection. ! 302: */ ! 303: if (XPending(display) == 0) usleep(150000); ! 304: if (XPending(display) != 0) { ! 305: XPeekEvent(display, &peek_event); ! 306: if(peek_event.type == LeaveNotify) { ! 307: break; ! 308: } ! 309: } ! 310: cur_s = (XMSelect *)event_xmw; ! 311: /* ! 312: * If the pane we are in is active and the ! 313: * selection entered is active then activate ! 314: * the selection. ! 315: */ ! 316: if (cur_p->active && cur_s->active) { ! 317: cur_s->activated = 1; ! 318: _XMRefreshSelection(display, menu, cur_s); ! 319: } ! 320: } ! 321: else { ! 322: /* ! 323: * We have entered a pane. ! 324: */ ! 325: if (XPending(display) == 0) usleep(150000); ! 326: if (XPending(display) != 0) { ! 327: XPeekEvent(display, &peek_event); ! 328: if (peek_event.type == EnterNotify) break; ! 329: } ! 330: XQueryPointer(display, ! 331: menu->parent, ! 332: &root, &child, ! 333: &root_x, &root_y, ! 334: &win_x, &win_y, ! 335: &mask); ! 336: event_xmp = (XMPane *)XLookUpAssoc(display, ! 337: menu->assoc_tab, ! 338: child); ! 339: if (event_xmp == NULL) break; ! 340: if (event_xmp == cur_p) break; ! 341: if (event_xmp->serial > cur_p->serial) forward = True; ! 342: else forward = False; ! 343: p_ptr = cur_p; ! 344: while (p_ptr != event_xmp) { ! 345: if (forward) p_ptr = p_ptr->next; ! 346: else p_ptr = p_ptr->prev; ! 347: XRaiseWindow(display, p_ptr->window); ! 348: } ! 349: if (cur_p->activated) { ! 350: cur_p->activated = False; ! 351: XSetWindowBackgroundPixmap(display, ! 352: cur_p->window, ! 353: menu->inact_pixmap); ! 354: _XMRefreshPane(display, menu, cur_p); ! 355: } ! 356: if (event_xmp->active) event_xmp->activated = True; ! 357: cur_p = event_xmp; ! 358: } ! 359: break; ! 360: case LeaveNotify: ! 361: event_xmw = (XMWindow *)XLookUpAssoc( ! 362: display, ! 363: menu->assoc_tab, ! 364: event.xcrossing.window ! 365: ); ! 366: if (event_xmw == NULL) break; ! 367: if(cur_s == NULL) break; ! 368: ! 369: /* ! 370: * If the current selection was activated then ! 371: * deactivate it. ! 372: */ ! 373: if (cur_s->activated) { ! 374: cur_s->activated = False; ! 375: _XMRefreshSelection(display, menu, cur_s); ! 376: } ! 377: cur_s = NULL; ! 378: break; ! 379: ! 380: case ButtonPress: ! 381: case ButtonRelease: ! 382: *p_num = cur_p->serial; ! 383: /* ! 384: * Check to see if there is a current selecion. ! 385: */ ! 386: if (cur_s != NULL) { ! 387: /* ! 388: * Set the selection number to the current selection. ! 389: */ ! 390: *s_num = cur_s->serial; ! 391: /* ! 392: * If the current selection was activated then ! 393: * we have a valid selection otherwise we have ! 394: * an inactive selection. ! 395: */ ! 396: if (cur_s->activated) { ! 397: *data = cur_s->data; ! 398: ret_val = XM_SUCCESS; ! 399: } ! 400: else { ! 401: ret_val = XM_IA_SELECT; ! 402: } ! 403: } ! 404: else { ! 405: /* ! 406: * No selection was current. ! 407: */ ! 408: ret_val = XM_NO_SELECT; ! 409: } ! 410: selection = True; ! 411: break; ! 412: default: ! 413: /* ! 414: * If AEQ mode is enabled then queue the event. ! 415: */ ! 416: if (menu->aeq) { ! 417: feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue)); ! 418: if (feq_tmp == NULL) { ! 419: _XMErrorCode = XME_CALLOC; ! 420: return(XM_FAILURE); ! 421: } ! 422: feq_tmp->event = event; ! 423: feq_tmp->next = feq; ! 424: feq = feq_tmp; ! 425: } ! 426: else if (_XMEventHandler) (*_XMEventHandler)(&event); ! 427: } ! 428: /* ! 429: * If a selection has been made, break out of the event loop. ! 430: */ ! 431: if (selection == True) break; ! 432: } ! 433: ! 434: /* ! 435: * Unmap the menu. ! 436: */ ! 437: for ( p_ptr = menu->p_list->next; ! 438: p_ptr != menu->p_list; ! 439: p_ptr = p_ptr->next) ! 440: { ! 441: XUnmapWindow(display, p_ptr->window); ! 442: } ! 443: ! 444: /* ! 445: * Ungrab the mouse. ! 446: */ ! 447: XUngrabPointer(display, CurrentTime); ! 448: ! 449: /* ! 450: * Restore bits under where the menu was if we managed ! 451: * to save them and free the pixmap. ! 452: */ ! 453: ! 454: /* ! 455: * If there is a current selection deactivate it. ! 456: */ ! 457: if (cur_s != NULL) cur_s->activated = 0; ! 458: ! 459: /* ! 460: * Deactivate the current pane. ! 461: */ ! 462: cur_p->activated = 0; ! 463: XSetWindowBackgroundPixmap(display, cur_p->window, menu->inact_pixmap); ! 464: ! 465: /* ! 466: * Synchronize the X buffers and the X event queue. ! 467: */ ! 468: XSync(display, 0); ! 469: ! 470: /* ! 471: * Dispatch any events remaining on the queue. ! 472: */ ! 473: while (QLength(display)) { ! 474: /* ! 475: * Fetch the next event. ! 476: */ ! 477: XNextEvent(display, &event); ! 478: ! 479: /* ! 480: * Discard any events left on the queue that belong to XMenu. ! 481: * All others are held and then returned to the event queue. ! 482: */ ! 483: switch (event.type) { ! 484: case Expose: ! 485: case EnterNotify: ! 486: case LeaveNotify: ! 487: case ButtonPress: ! 488: case ButtonRelease: ! 489: /* ! 490: * Does this event belong to one of XMenu's windows? ! 491: * If so, discard it and process the next event. ! 492: * If not fall through and treat it as a foreign event. ! 493: */ ! 494: event_xmp = (XMPane *)XLookUpAssoc( ! 495: display, ! 496: menu->assoc_tab, ! 497: event.xbutton.window ! 498: ); ! 499: if (event_xmp != NULL) continue; ! 500: default: ! 501: /* ! 502: * This is a foreign event. ! 503: * Queue it for later return to the X event queue. ! 504: */ ! 505: feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue)); ! 506: if (feq_tmp == NULL) { ! 507: _XMErrorCode = XME_CALLOC; ! 508: return(XM_FAILURE); ! 509: } ! 510: feq_tmp->event = event; ! 511: feq_tmp->next = feq; ! 512: feq = feq_tmp; ! 513: } ! 514: } ! 515: /* ! 516: * Return any foreign events that were queued to the X event queue. ! 517: */ ! 518: while (feq != NULL) { ! 519: feq_tmp = feq; ! 520: XPutBackEvent(display, &feq_tmp->event); ! 521: feq = feq_tmp->next; ! 522: free((char *)feq_tmp); ! 523: } ! 524: ! 525: /* ! 526: * Return successfully. ! 527: */ ! 528: _XMErrorCode = XME_NO_ERROR; ! 529: return(ret_val); ! 530: ! 531: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.