|
|
1.1 ! root 1: /* $Header: XMenuActivate.c,v 10.19 86/07/11 16:50:09 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: * Since X processes events in an asynchronous manner ! 49: * it is likely that XMenuActivate will encounter ! 50: * a "foreign event" while it is executing. Foreign ! 51: * events are handled in one of three ways: ! 52: * ! 53: * 1) The event is discarded. This is the default ! 54: * mode and requires no action on the part of the ! 55: * application. ! 56: * ! 57: * 2) The application has identified an asynchronous ! 58: * event handler that will be called and the ! 59: * foreign event handed off to it. Note: ! 60: * AEQ mode disables this mode temporarily. ! 61: * ! 62: * 3) The application has enabled asynchronous event ! 63: * queueing mode. In this mode all foreign events ! 64: * will be queued up untill XMenuActivate ! 65: * terminates; at which time they will be ! 66: * returned to the X event queue. As long as ! 67: * AEQ mode is enabled any asynchronous event ! 68: * handler as temporarily disabled. ! 69: * ! 70: * Any events encountered while taking down the menu ! 71: * (i.e., exposure events from occluded windows) will ! 72: * automatically be returned to the X event queue after ! 73: * XMenuActivate has cleaned the queue of any of its own ! 74: * events that are no longer needed. ! 75: * ! 76: * Author: Tony Della Fera, DEC ! 77: * March 12, 1986 ! 78: * ! 79: */ ! 80: ! 81: #include "XMenuInternal.h" ! 82: ! 83: int ! 84: XMenuActivate(menu, p_num, s_num, x_pos, y_pos, event_mask, data) ! 85: register XMenu *menu; /* Menu to activate. */ ! 86: int *p_num; /* Pane number selected. */ ! 87: int *s_num; /* Selection number selected. */ ! 88: int x_pos; /* X coordinate of menu position. */ ! 89: int y_pos; /* Y coordinate of menu position. */ ! 90: int event_mask; /* Mouse button event mask. */ ! 91: char **data; /* Pointer to return data value. */ ! 92: { ! 93: register int i; /* Loop counter. */ ! 94: int status; /* X routine call status. */ ! 95: int orig_x; /* Upper left menu origin X coord. */ ! 96: int orig_y; /* Upper left menu origin Y coord. */ ! 97: int save_x; /* Upper left X of save region. */ ! 98: int save_y; /* Upper left Y of save region. */ ! 99: int save_w; /* Width of pixmap save region. */ ! 100: int save_h; /* Height of pixmap save region. */ ! 101: int save_w_offscr; /* Pixmap save width off screen. */ ! 102: int save_h_offscr; /* Pixmap save height off screen. */ ! 103: int x, y; /* Dummy X and Y arguments. */ ! 104: int ret_val; /* Return value. */ ! 105: ! 106: register XMPane *p_ptr; /* Current XMPane. */ ! 107: register XMPane *event_xmp; /* Event XMPane pointer. */ ! 108: register XMPane *cur_p; /* Current pane. */ ! 109: register XMSelect *cur_s; /* Current selection. */ ! 110: XMWindow *event_xmw; /* Event XMWindow pointer. */ ! 111: XEvent event; /* X input event. */ ! 112: XCrossingEvent *xc_event; /* X window crossing event. */ ! 113: Window xc_window; /* X window crossing event window. */ ! 114: ! 115: Pixmap save_pixmap; /* Pixmap to save bits under menu. */ ! 116: ! 117: Bool saved = TRUE; /* Pixmap save succeeded. */ ! 118: Bool selection = FALSE; /* Selection has been made. */ ! 119: Bool forward = TRUE; /* Moving forward in the pane list. */ ! 120: Bool p_lock = TRUE; /* Pane entrance lock. */ ! 121: Bool s_lock = TRUE; /* Selection entrance lock. */ ! 122: ! 123: /* ! 124: * Define and allocate a foreign event queue to hold events ! 125: * that don't belong to XMenu. These events are later restored ! 126: * to the X event queue. ! 127: */ ! 128: typedef struct _xmeventque { ! 129: XEvent event; ! 130: struct _xmeventque *next; ! 131: } XMEventQue; ! 132: ! 133: XMEventQue *feq = NULL; /* Foreign event queue. */ ! 134: XMEventQue *feq_tmp; /* Foreign event queue temporary. */ ! 135: ! 136: /* ! 137: * Are the position arguments are positive? ! 138: */ ! 139: if ((x_pos <= 0) || (y_pos <= 0)) { ! 140: _XMErrorCode = XME_ARG_BOUNDS; ! 141: return(XM_FAILURE); ! 142: } ! 143: ! 144: /* ! 145: * If there are no panes in the menu then return failure ! 146: * beacuse the menu is not initialized. ! 147: */ ! 148: if (menu->p_count == 0) { ! 149: _XMErrorCode = XME_NOT_INIT; ! 150: return(XM_FAILURE); ! 151: } ! 152: ! 153: /* ! 154: * Find the desired current pane. ! 155: */ ! 156: cur_p = _XMGetPanePtr(menu, *p_num); ! 157: if (cur_p == NULL) return(XM_FAILURE); ! 158: ! 159: /* ! 160: * Find the desired current selection. ! 161: * If the current selection index is out of range a null current selection ! 162: * will be assumed and the cursor will be placed in the current pane ! 163: * header. ! 164: */ ! 165: cur_s = _XMGetSelectionPtr(cur_p, *s_num); ! 166: ! 167: /* ! 168: * Check to see that the menu's dependencies have been ! 169: * recomputed and are up to date. If not, do it now. ! 170: */ ! 171: if (menu->recompute) XMenuRecompute(menu); ! 172: ! 173: /* ! 174: * If the current pane is active then activate it. ! 175: */ ! 176: if (cur_p->active) { ! 177: cur_p->activated = 1; ! 178: XChangeBackground(cur_p->window, menu->bkgnd_pixmap); ! 179: } ! 180: ! 181: /* ! 182: * Compute the new menu origin such that the cursor hot point lies ! 183: * in the center of the desired current pane and selection. ! 184: */ ! 185: _XMTransToOrigin(menu, cur_p, cur_s, x_pos, y_pos, &orig_x, &orig_y); ! 186: ! 187: /* ! 188: * Then move all the panes into position relative to the newly ! 189: * computed origin. ! 190: */ ! 191: for ( ! 192: p_ptr = menu->p_list->next; ! 193: p_ptr != menu->p_list; ! 194: p_ptr = p_ptr->next ! 195: ){ ! 196: XMoveWindow( ! 197: p_ptr->window, ! 198: orig_x + p_ptr->window_x, ! 199: orig_y + p_ptr->window_y ! 200: ); ! 201: } ! 202: ! 203: /*< ! 204: * If server freeze mode is selected... ! 205: */ ! 206: if (menu->freeze) { ! 207: /* ! 208: * Compute pixmap save region. ! 209: */ ! 210: save_x = max(orig_x, 0); ! 211: save_y = max(orig_y, 0); ! 212: save_w_offscr = (orig_x + menu->width) - DisplayWidth(); ! 213: save_h_offscr = (orig_y + menu->height) - DisplayHeight(); ! 214: if (save_w_offscr < 0) save_w = menu->width; ! 215: else save_w = menu->width - save_w_offscr; ! 216: if (save_h_offscr < 0) save_h = menu->height; ! 217: else save_h = menu->height - save_h_offscr; ! 218: ! 219: /* ! 220: * Grab the X server. ! 221: */ ! 222: XGrabServer(); ! 223: ! 224: /* ! 225: * Save the bits under where the menu will be. ! 226: */ ! 227: save_pixmap = XPixmapSave( ! 228: menu->parent, ! 229: save_x, save_y, ! 230: save_w, save_h ! 231: ); ! 232: if (save_pixmap == _X_FAILURE) saved = FALSE; ! 233: } ! 234: else { ! 235: saved = FALSE; ! 236: } ! 237: ! 238: /* ! 239: * Synchronize the X buffers and the event queue. ! 240: * From here on, all events in the queue that don't belong to ! 241: * XMenu are send back to the application via an application ! 242: * provided event handler or discarded if the application has ! 243: * not provided an event handler. ! 244: */ ! 245: XSync(0); ! 246: ! 247: /* ! 248: * Grab the mouse for menu input. ! 249: */ ! 250: status = XGrabMouse(menu->parent, menu->mouse_cursor, event_mask); ! 251: if (status == _X_FAILURE) { ! 252: _XMErrorCode = XME_GRAB_MOUSE; ! 253: return(XM_FAILURE); ! 254: } ! 255: ! 256: /* ! 257: * Map the menu panes. ! 258: */ ! 259: for ( ! 260: p_ptr = menu->p_list->prev; ! 261: p_ptr != menu->p_list; ! 262: p_ptr = p_ptr->prev ! 263: ){ ! 264: if (p_ptr == cur_p) break; ! 265: XMapWindow(p_ptr->window); ! 266: } ! 267: for ( ! 268: p_ptr = menu->p_list->next; ! 269: p_ptr != menu->p_list; ! 270: p_ptr = p_ptr->next ! 271: ){ ! 272: if (p_ptr == cur_p) break; ! 273: XMapWindow(p_ptr->window); ! 274: } ! 275: XMapWindow(cur_p->window); ! 276: ! 277: /* ! 278: * Clear the current selection. ! 279: */ ! 280: cur_s = NULL; ! 281: ! 282: /* ! 283: * Begin event processing loop. ! 284: */ ! 285: while (1) { ! 286: /* ! 287: * Fetch the next event. ! 288: */ ! 289: XNextEvent(&event); ! 290: /* ! 291: * Dispatch on the event type. ! 292: */ ! 293: switch (event.type) { ! 294: case ExposeWindow: ! 295: event_xmp = (XMPane *)XLookUpAssoc( ! 296: menu->assoc_tab, event.window ! 297: ); ! 298: if (event_xmp == NULL) { ! 299: /* ! 300: * If AEQ mode is enabled then queue the event. ! 301: */ ! 302: if (menu->aeq) { ! 303: feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue)); ! 304: if (feq_tmp == NULL) { ! 305: _XMErrorCode = XME_CALLOC; ! 306: return(XM_FAILURE); ! 307: } ! 308: feq_tmp->event = event; ! 309: feq_tmp->next = feq; ! 310: feq = feq_tmp; ! 311: } ! 312: else if (_XMEventHandler) (*_XMEventHandler)(&event); ! 313: break; ! 314: } ! 315: if (event_xmp == cur_p) { ! 316: _XMRefreshPane(menu, cur_p); ! 317: } ! 318: else _XMRefreshPaneText(menu, event_xmp); ! 319: break; ! 320: case EnterWindow: ! 321: event_xmw = (XMWindow *)XLookUpAssoc( ! 322: menu->assoc_tab, ! 323: event.window ! 324: ); ! 325: if (event_xmw == NULL) break; ! 326: if (event_xmw->type == SELECTION) { ! 327: /* ! 328: * We have entered a selection. ! 329: */ ! 330: cur_s = (XMSelect *)event_xmw; ! 331: /* ! 332: * If the pane we are in is active and the ! 333: * selection entered is active then activate ! 334: * the selection. ! 335: */ ! 336: if (cur_p->active && cur_s->active) { ! 337: cur_s->activated = 1; ! 338: _XMRefreshSelection(menu, cur_s); ! 339: } ! 340: } ! 341: else { ! 342: /* ! 343: * We have entered a pane. ! 344: */ ! 345: xc_event = (XCrossingEvent *)&event; ! 346: status = XInterpretLocator( ! 347: menu->parent, ! 348: &x, &y, ! 349: &xc_window, ! 350: xc_event->location ! 351: ); ! 352: if (status == _X_FAILURE) { ! 353: _XMErrorCode = XME_INTERP_LOC; ! 354: return(XM_FAILURE); ! 355: } ! 356: event_xmp = (XMPane *)XLookUpAssoc( ! 357: menu->assoc_tab, ! 358: xc_window ! 359: ); ! 360: if (event_xmp->window == cur_p->window) break; ! 361: if (event_xmp->serial > cur_p->serial) forward = TRUE; ! 362: else forward = FALSE; ! 363: p_ptr = cur_p; ! 364: while(1) { ! 365: if (forward) p_ptr = p_ptr->next; ! 366: else p_ptr = p_ptr->prev; ! 367: /* ! 368: * If the new pane is an active pane then ! 369: * activate it. ! 370: */ ! 371: if (p_ptr->active) { ! 372: p_ptr->activated = 1; ! 373: XChangeBackground( ! 374: p_ptr->window, ! 375: menu->bkgnd_pixmap ! 376: ); ! 377: XClear(p_ptr->window); ! 378: } ! 379: /* ! 380: * Raise the new pane. ! 381: */ ! 382: XRaiseWindow(p_ptr->window); ! 383: /* ! 384: * If the previous current pane was activated ! 385: * deactivate it. ! 386: */ ! 387: if (cur_p->activated) { ! 388: cur_p->activated = 0; ! 389: XChangeBackground( ! 390: cur_p->window, ! 391: menu->inact_pixmap ! 392: ); ! 393: _XMRefreshPaneText(menu, cur_p); ! 394: } ! 395: /* ! 396: * Make the new pane the current pane. ! 397: */ ! 398: cur_p = p_ptr; ! 399: /* ! 400: * If we have cycled through to the event ! 401: * pane we are done. ! 402: */ ! 403: if (p_ptr->window == event_xmp->window) break; ! 404: } ! 405: } ! 406: break; ! 407: case LeaveWindow: ! 408: event_xmw = (XMWindow *)XLookUpAssoc( ! 409: menu->assoc_tab, ! 410: event.window ! 411: ); ! 412: if (event_xmw == NULL) break; ! 413: /* ! 414: * If the current selection was activated then ! 415: * deactivate it. ! 416: */ ! 417: if (cur_s->activated) { ! 418: cur_s->activated = 0; ! 419: _XMRefreshSelection(menu, cur_s); ! 420: } ! 421: cur_s = NULL; ! 422: break; ! 423: case ButtonPressed: ! 424: case ButtonReleased: ! 425: *p_num = cur_p->serial; ! 426: /* ! 427: * Check to see if there is a current selecion. ! 428: */ ! 429: if (cur_s != NULL) { ! 430: /* ! 431: * Set the selection number to the current selection. ! 432: */ ! 433: *s_num = cur_s->serial; ! 434: /* ! 435: * If the current selection was activated then ! 436: * we have a valid selection otherwise we have ! 437: * an inactive selection. ! 438: */ ! 439: if (cur_s->activated) { ! 440: *data = cur_s->data; ! 441: ret_val = XM_SUCCESS; ! 442: } ! 443: else { ! 444: ret_val = XM_IA_SELECT; ! 445: } ! 446: } ! 447: else { ! 448: /* ! 449: * No selection was current. ! 450: */ ! 451: ret_val = XM_NO_SELECT; ! 452: } ! 453: selection = TRUE; ! 454: break; ! 455: default: ! 456: /* ! 457: * If AEQ mode is enabled then queue the event. ! 458: */ ! 459: if (menu->aeq) { ! 460: feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue)); ! 461: if (feq_tmp == NULL) { ! 462: _XMErrorCode = XME_CALLOC; ! 463: return(XM_FAILURE); ! 464: } ! 465: feq_tmp->event = event; ! 466: feq_tmp->next = feq; ! 467: feq = feq_tmp; ! 468: } ! 469: else if (_XMEventHandler) (*_XMEventHandler)(&event); ! 470: } ! 471: /* ! 472: * If a selection has been made, break out of the event loop. ! 473: */ ! 474: if (selection == TRUE) break; ! 475: } ! 476: ! 477: /* ! 478: * Unmap the menu. ! 479: */ ! 480: if (saved) { ! 481: for ( ! 482: p_ptr = menu->p_list->next; ! 483: p_ptr != menu->p_list; ! 484: p_ptr = p_ptr->next ! 485: ) { ! 486: XUnmapTransparent(p_ptr->window); ! 487: } ! 488: } ! 489: else { ! 490: for ( ! 491: p_ptr = menu->p_list->next; ! 492: p_ptr != menu->p_list; ! 493: p_ptr = p_ptr->next ! 494: ) { ! 495: XUnmapWindow(p_ptr->window); ! 496: } ! 497: } ! 498: ! 499: /* ! 500: * Ungrab the mouse. ! 501: */ ! 502: XUngrabMouse(); ! 503: ! 504: /* ! 505: * Restore bits under where the menu was if we managed ! 506: * to save them and free the pixmap. ! 507: */ ! 508: if (saved) { ! 509: XPixmapPut( ! 510: menu->parent, ! 511: 0, 0, ! 512: save_x, save_y, ! 513: save_w, save_h, ! 514: save_pixmap, ! 515: GXcopy, AllPlanes ! 516: ); ! 517: XFreePixmap(save_pixmap); ! 518: } ! 519: ! 520: /* ! 521: * Ungrab the X server. ! 522: */ ! 523: if (menu->freeze) XUngrabServer(); ! 524: ! 525: /* ! 526: * If there is a current selection deactivate it. ! 527: */ ! 528: if (cur_s != NULL) cur_s->activated = 0; ! 529: ! 530: /* ! 531: * Deactivate the current pane. ! 532: */ ! 533: cur_p->activated = 0; ! 534: XChangeBackground(cur_p->window, menu->inact_pixmap); ! 535: ! 536: /* ! 537: * Synchronize the X buffers and the X event queue. ! 538: */ ! 539: XSync(0); ! 540: ! 541: /* ! 542: * Dispatch any events remaining on the queue. ! 543: */ ! 544: while (QLength()) { ! 545: /* ! 546: * Fetch the next event. ! 547: */ ! 548: XNextEvent(&event); ! 549: ! 550: /* ! 551: * Discard any events left on the queue that belong to XMenu. ! 552: * All others are held and then returned to the event queue. ! 553: */ ! 554: switch (event.type) { ! 555: case ExposeWindow: ! 556: case EnterWindow: ! 557: case LeaveWindow: ! 558: case ButtonPressed: ! 559: case ButtonReleased: ! 560: /* ! 561: * Does this event belong to one of XMenu's windows? ! 562: * If so, discard it and process the next event. ! 563: * If not fall through and treat it as a foreign event. ! 564: */ ! 565: event_xmp = (XMPane *)XLookUpAssoc( ! 566: menu->assoc_tab, ! 567: event.window ! 568: ); ! 569: if (event_xmp != NULL) continue; ! 570: default: ! 571: /* ! 572: * This is a foreign event. ! 573: * Queue it for later return to the X event queue. ! 574: */ ! 575: feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue)); ! 576: if (feq_tmp == NULL) { ! 577: _XMErrorCode = XME_CALLOC; ! 578: return(XM_FAILURE); ! 579: } ! 580: feq_tmp->event = event; ! 581: feq_tmp->next = feq; ! 582: feq = feq_tmp; ! 583: } ! 584: } ! 585: ! 586: /* ! 587: * Return any foreign events that were queued to the X event queue. ! 588: */ ! 589: while (feq != NULL) { ! 590: feq_tmp = feq; ! 591: XPutBackEvent(&feq_tmp->event); ! 592: feq = feq_tmp->next; ! 593: free((char *)feq_tmp); ! 594: } ! 595: ! 596: /* ! 597: * Return successfully. ! 598: */ ! 599: _XMErrorCode = XME_NO_ERROR; ! 600: return(ret_val); ! 601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.