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: int
  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 ExposeWindow:
 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 EnterWindow:
 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 LeaveWindow:
 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 ButtonPressed:
 368:         case ButtonReleased:
 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: }
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1664
Valid CSS Valid XHTML 1.0 Strict