1/* Copyright Massachusetts Institute of Technology 1985 */ 2 3#include "copyright.h" 4 5/* 6Copyright (C) 1993, 1996, 2001, 2002, 2003, 2004, 2005, 2006, 7 2007 Free Software Foundation, Inc. 8 9This program is free software; you can redistribute it and/or modify 10it under the terms of the GNU General Public License as published by 11the Free Software Foundation; either version 2, or (at your option) 12any later version. 13 14This program is distributed in the hope that it will be useful, 15but WITHOUT ANY WARRANTY; without even the implied warranty of 16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17GNU General Public License for more details. 18 19You should have received a copy of the GNU General Public License 20along with this program; see the file COPYING. If not, write to the 21Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22Boston, MA 02110-1301, USA. */ 23 24 25/* 26 * XMenu: MIT Project Athena, X Window system menu package 27 * 28 * XMenuInternal.c - XMenu internal (not user visible) routines. 29 * 30 * Author: Tony Della Fera, DEC 31 * November, 1985 32 * 33 */ 34 35#include <config.h> 36#include "XMenuInt.h" 37 38/* 39 * Toggle color macro. 40 */ 41#define toggle_color(x) \ 42 ((x) == menu->bkgnd_color ? menu->s_frg_color : menu->bkgnd_color) 43 44/* 45 * Internal Window creation queue sizes. 46 */ 47#define S_QUE_SIZE 300 48#define P_QUE_SIZE 20 49#define BUFFER_SIZE (S_QUE_SIZE >= P_QUE_SIZE ? S_QUE_SIZE : P_QUE_SIZE) 50 51 52/* 53 * XMWinQue - Internal window creation queue datatype. 54 */ 55typedef struct _xmwinquedef { 56 int sq_size; 57 XMSelect *sq[S_QUE_SIZE]; 58 XMSelect **sq_ptr; 59 int pq_size; 60 XMPane *pq[P_QUE_SIZE]; 61 XMPane **pq_ptr; 62} XMWinQue; 63 64/* 65 * _XMWinQue - Internal static window creation queue. 66 */ 67static Bool _XMWinQueIsInit = False; 68static XMWinQue _XMWinQue; 69 70/* 71 * _XMErrorCode - Global XMenu error code. 72 */ 73int _XMErrorCode = XME_NO_ERROR; 74/* 75 * _XMErrorList - Global XMenu error code description strings. 76 */ 77char * 78_XMErrorList[XME_CODE_COUNT] = { 79 "No error", /* XME_NO_ERROR */ 80 "Menu not initialized", /* XME_NOT_INIT */ 81 "Argument out of bounds", /* XME_ARG_BOUNDS */ 82 "Pane not found", /* XME_P_NOT_FOUND */ 83 "Selection not found", /* XME_S_NOT_FOUND */ 84 "Invalid menu style parameter", /* XME_STYLE_PARAM */ 85 "Unable to grab mouse", /* XME_GRAB_MOUSE */ 86 "Unable to interpret locator", /* XME_INTERP_LOC */ 87 "Unable to calloc memory", /* XME_CALLOC */ 88 "Unable to create XAssocTable", /* XME_CREATE_ASSOC */ 89 "Unable to store bitmap", /* XME_STORE_BITMAP */ 90 "Unable to make tile pixmaps", /* XME_MAKE_TILES */ 91 "Unable to make pixmap", /* XME_MAKE_PIXMAP */ 92 "Unable to create cursor", /* XME_CREATE_CURSOR */ 93 "Unable to open font", /* XME_OPEN_FONT */ 94 "Unable to create windows", /* XME_CREATE_WINDOW */ 95 "Unable to create transparencies", /* XME_CREATE_TRANSP */ 96}; 97 98/* 99 * _XMEventHandler - Internal event handler variable. 100 */ 101int (*_XMEventHandler)() = NULL; 102 103 104 105/* 106 * _XMWinQueInit - Internal routine to initialize the window 107 * queue. 108 */ 109_XMWinQueInit() 110{ 111 /* 112 * If the queue is not initialized initialize it. 113 */ 114 if (!_XMWinQueIsInit) { 115 /* 116 * Blank the queue structure. 117 */ 118 register int i; 119 120 for (i = 0; i < S_QUE_SIZE; i++) 121 _XMWinQue.sq[i] = 0; 122 123 for (i = 0; i < P_QUE_SIZE; i++) 124 _XMWinQue.pq[i] = 0; 125 126 _XMWinQue.sq_size = _XMWinQue.pq_size = 0; 127 128 /* 129 * Initialize the next free location pointers. 130 */ 131 _XMWinQue.sq_ptr = _XMWinQue.sq; 132 _XMWinQue.pq_ptr = _XMWinQue.pq; 133 } 134} 135 136 137 138/* 139 * _XMWinQueAddPane - Internal routine to add a pane to the pane 140 * window queue. 141 */ 142int 143_XMWinQueAddPane(display, menu, p_ptr) 144 register Display *display; 145 register XMenu *menu; /* Menu being manipulated. */ 146 register XMPane *p_ptr; /* XMPane being queued. */ 147{ 148 /* 149 * If the queue is currently full then flush it. 150 */ 151 if (_XMWinQue.pq_size == P_QUE_SIZE) { 152 if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE); 153 } 154 155 /* 156 * Insert the new XMPane pointer and increment the queue pointer 157 * and the queue size. 158 */ 159 *_XMWinQue.pq_ptr = p_ptr; 160 _XMWinQue.pq_ptr++; 161 _XMWinQue.pq_size++; 162 163 /* 164 * All went well, return successfully. 165 */ 166 _XMErrorCode = XME_NO_ERROR; 167 return(_SUCCESS); 168} 169 170 171 172/* 173 * _XMWinQueAddSelection - Internal routine to add a selection to 174 * the selection window queue. 175 */ 176int 177_XMWinQueAddSelection(display, menu, s_ptr) 178 register Display *display; 179 register XMenu *menu; /* Menu being manipulated. */ 180 register XMSelect *s_ptr; /* XMSelection being queued. */ 181{ 182 /* 183 * If this entry will overflow the queue then flush it. 184 */ 185 if (_XMWinQue.sq_size == S_QUE_SIZE) { 186 if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE); 187 } 188 189 /* 190 * Insert the new XMSelect pointer and increment the queue pointer 191 * and the queue size. 192 */ 193 *_XMWinQue.sq_ptr = s_ptr; 194 _XMWinQue.sq_ptr++; 195 _XMWinQue.sq_size++; 196 197 /* 198 * All went well, return successfully. 199 */ 200 _XMErrorCode = XME_NO_ERROR; 201 return(_SUCCESS); 202} 203 204 205 206/* 207 * _XMWinQueFlush - Internal routine to flush the pane and 208 * selection window queues. 209 */ 210int 211_XMWinQueFlush(display, menu, pane, select) 212 register Display *display; 213 register XMenu *menu; /* Menu being manipulated. */ 214 register XMPane *pane; /* Current pane. */ 215{ 216 register int pq_index; /* Pane queue index. */ 217 register int sq_index; /* Selection queue index. */ 218 register XMPane *p_ptr; /* XMPane pointer. */ 219 register XMSelect *s_ptr; /* XMSelect pointer. */ 220 unsigned long valuemask; /* Which attributes to set. */ 221 XSetWindowAttributes *attributes; /* Attributes to be set. */ 222 223 /* 224 * If the pane window queue is not empty... 225 */ 226 227 if (_XMWinQue.pq_size > 0) { 228 /* 229 * set up attributes for pane window to be created. 230 */ 231 valuemask = (CWBackPixmap | CWBorderPixel | CWOverrideRedirect); 232 attributes = (XSetWindowAttributes *)malloc(sizeof(XSetWindowAttributes)); 233 attributes->border_pixel = menu->p_bdr_color; 234 attributes->background_pixmap = menu->inact_pixmap; 235 attributes->override_redirect = True; 236 237 /* 238 * Create all the pending panes in order, so that the 239 * current pane will be on top, with the others 240 * stacked appropriately under it. 241 */ 242 for (pq_index = _XMWinQue.pq_size - 1; 243 pq_index >= 0; 244 pq_index--) 245 { 246 p_ptr = _XMWinQue.pq[pq_index]; /* Retrieve next pane. */ 247 if (p_ptr == pane) break; 248 p_ptr->window = XCreateWindow(display, 249 menu->parent, 250 p_ptr->window_x, 251 p_ptr->window_y, 252 p_ptr->window_w, 253 p_ptr->window_h, 254 menu->p_bdr_width, 255 CopyFromParent, 256 InputOutput, 257 CopyFromParent, 258 valuemask, 259 attributes); 260 XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr); 261 XSelectInput(display, p_ptr->window, menu->p_events); 262 } 263 for (pq_index = 0; 264 pq_index < _XMWinQue.pq_size; 265 pq_index++) 266 { 267 p_ptr = _XMWinQue.pq[pq_index]; /* Retrieve next pane. */ 268 p_ptr->window = XCreateWindow(display, 269 menu->parent, 270 p_ptr->window_x, 271 p_ptr->window_y, 272 p_ptr->window_w, 273 p_ptr->window_h, 274 menu->p_bdr_width, 275 CopyFromParent, 276 InputOutput, 277 CopyFromParent, 278 valuemask, 279 attributes); 280 XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr); 281 XSelectInput(display, p_ptr->window, menu->p_events); 282 if (p_ptr == pane) break; 283 } 284 285 /* 286 * Reset the pane queue pointer and size. 287 */ 288 _XMWinQue.pq_size = 0; 289 _XMWinQue.pq_ptr = _XMWinQue.pq; 290 } 291 292 /* 293 * If the selection window queue is not empty... 294 */ 295 296 if (_XMWinQue.sq_size > 0) { 297 298 for (sq_index = 0; sq_index < _XMWinQue.sq_size; sq_index++) { 299 /* 300 * Retrieve the XMSelect pointer. 301 */ 302 s_ptr = _XMWinQue.sq[sq_index]; 303 s_ptr->window = XCreateWindow(display, 304 s_ptr->parent_p->window, 305 s_ptr->window_x, 306 s_ptr->window_y, 307 s_ptr->window_w, 308 s_ptr->window_h, 309 0, /* border width*/ 310 CopyFromParent, 311 InputOnly, 312 CopyFromParent, 313 0, 314 attributes); 315 316 /* 317 * Insert the new window id and its 318 * associated XMSelect structure into the 319 * association table. 320 */ 321 XMakeAssoc(display, menu->assoc_tab, s_ptr->window, s_ptr); 322 XSelectInput(display, s_ptr->window, menu->s_events); 323 } 324 325 /* 326 * Reset the selection queue pointer and size. 327 */ 328 _XMWinQue.sq_size = 0; 329 _XMWinQue.sq_ptr = _XMWinQue.sq; 330 } 331 332 /* 333 * Flush X's internal queues. 334 */ 335 XFlush(display); 336 337 /* 338 * All went well, return successfully. 339 */ 340 _XMErrorCode = XME_NO_ERROR; 341 return(_SUCCESS); 342} 343 344 345 346/* 347 * _XMGetPanePtr - Given a menu pointer and a pane index number, return 348 * a pane pointer that points to the indexed pane. 349 */ 350XMPane * 351_XMGetPanePtr(menu, p_num) 352 register XMenu *menu; /* Menu to find the pane in. */ 353 register int p_num; /* Index number of pane to find. */ 354{ 355 register XMPane *p_ptr; /* Pane pointer to be returned. */ 356 register int i; /* Loop counter. */ 357 358 /* 359 * Is the pane number out of range? 360 */ 361 if ((p_num < 0) || (p_num > (menu->p_count - 1))) { 362 _XMErrorCode = XME_P_NOT_FOUND; 363 return(NULL); 364 } 365 366 /* 367 * Find the right pane. 368 */ 369 p_ptr = menu->p_list->next; 370 for (i = 0; i < p_num; i++) p_ptr = p_ptr->next; 371 372 /* 373 * Return successfully. 374 */ 375 _XMErrorCode = XME_NO_ERROR; 376 return(p_ptr); 377} 378 379 380 381/* 382 * _XMGetSelectionPtr - Given pane pointer and a selection index number, 383 * return a selection pointer that points to the 384 * indexed selection. 385 */ 386XMSelect * 387_XMGetSelectionPtr(p_ptr, s_num) 388 register XMPane *p_ptr; /* Pane to find the selection in. */ 389 register int s_num; /* Index number of the selection to find. */ 390{ 391 register XMSelect *s_ptr; /* Selection pointer to be returned. */ 392 register int i; /* Loop counter. */ 393 394 /* 395 * Is the selection number out of range? 396 */ 397 if ((s_num < 0) || (s_num > (p_ptr->s_count - 1))) { 398 _XMErrorCode = XME_S_NOT_FOUND; 399 return(NULL); 400 } 401 402 /* 403 * Find the right selection. 404 */ 405 s_ptr = p_ptr->s_list->next; 406 for (i = 0; i < s_num; i++) s_ptr = s_ptr->next; 407 408 /* 409 * Return successfully. 410 */ 411 _XMErrorCode = XME_NO_ERROR; 412 return(s_ptr); 413} 414 415 416 417/* 418 * _XMRecomputeGlobals - Internal subroutine to recompute menu wide 419 * global values. 420 */ 421_XMRecomputeGlobals(display, menu) 422 register Display *display; /*X11 display variable. */ 423 register XMenu *menu; /* Menu object to compute from. */ 424{ 425 register XMPane *p_ptr; /* Pane pointer. */ 426 register XMSelect *s_ptr; /* Selection pointer. */ 427 428 register int max_p_label = 0; /* Maximum pane label width. */ 429 register int max_s_label = 0; /* Maximum selection label width. */ 430 register int s_count = 0; /* Maximum selection count. */ 431 432 int p_s_pad; /* Pane <-> selection padding. */ 433 int p_s_diff; /* Pane <-> selection separation. */ 434 435 int p_height; /* Pane window height. */ 436 int p_width; /* Pane window width. */ 437 int s_width; /* Selection window width. */ 438 439 int screen; /* DefaultScreen holder. */ 440 441 /* 442 * For each pane... 443 */ 444 for ( 445 p_ptr = menu->p_list->next; 446 p_ptr != menu->p_list; 447 p_ptr = p_ptr->next 448 ){ 449 450 /* 451 * Recompute maximum pane label width. 452 */ 453 max_p_label = max(max_p_label, p_ptr->label_width); 454 455 /* 456 * Recompute maximum selection count. 457 */ 458 s_count = max(s_count, p_ptr->s_count); 459 460 /* 461 * For each selection in the current pane... 462 */ 463 for ( 464 s_ptr = p_ptr->s_list->next; 465 s_ptr != p_ptr->s_list; 466 s_ptr = s_ptr->next 467 ){ 468 469 /* 470 * Recompute maximum selection label width. 471 */ 472 max_s_label = max(max_s_label, s_ptr->label_width); 473 } 474 } 475 476 /* 477 * Recompute pane height. 478 */ 479 p_height = (menu->flag_height << 1) + (menu->s_y_off * s_count); 480 481 /* 482 * Recompute horizontal padding between the pane window and the 483 * selection windows. 484 */ 485 p_s_pad = menu->p_x_off << 1; 486 487 /* 488 * Recompute pane and selection window widths. 489 * This is done by first computing the window sizes from the maximum 490 * label widths. If the spacing between the selection window and the 491 * containing pane window is less than the pane selection padding value 492 * (twice the pane X offset) then change the size of the pane to be 493 * the size of the selection window plus the padding. If, however the 494 * spacing between the selection window and the containing pane window 495 * is more than the pane selection padding value increase the size of 496 * the selection to its maximum possible value (the pane width minus 497 * the pane selection padding value). 498 */ 499 p_width = max_p_label + p_s_pad; 500 s_width = max_s_label + (menu->s_fnt_pad << 1) + (menu->s_bdr_width << 1); 501 p_s_diff = p_width - s_width; 502 if (p_s_diff < p_s_pad) { 503 p_width = s_width + p_s_pad; 504 } 505 else if (p_s_diff > p_s_pad) { 506 s_width = p_width - p_s_pad; 507 } 508 509 /* 510 * Reset menu wide global values. 511 */ 512 menu->s_count = s_count; 513 menu->p_height = p_height; 514 menu->p_width = p_width; 515 menu->s_width = s_width; 516 517 /* 518 * Ensure that the origin of the menu is placed so that 519 * None of the panes ore selections are off the screen. 520 */ 521 screen = DefaultScreen(display); 522 if (menu->x_pos + menu->width > DisplayWidth(display, screen)) 523 menu->x_pos = DisplayWidth(display, screen) - menu->width; 524 else if (menu->x_pos < 0) menu->x_pos = 0; 525 if(menu->y_pos + menu->height > DisplayHeight(display, screen)) 526 menu->y_pos = DisplayHeight(display, screen) - menu->height; 527 else if (menu->y_pos < 0) menu->y_pos = 0; 528} 529 530 531/* 532 * _XMRecomputePane - Internal subroutine to recompute pane 533 * window dependencies. 534 */ 535int 536_XMRecomputePane(display, menu, p_ptr, p_num) 537 register Display *display; /* Standard X display variable. */ 538 register XMenu *menu; /* Menu object being recomputed. */ 539 register XMPane *p_ptr; /* Pane pointer. */ 540 register int p_num; /* Pane sequence number. */ 541{ 542 register int window_x; /* Recomputed window X coordinate. */ 543 register int window_y; /* Recomputed window Y coordinate. */ 544 545 unsigned long change_mask; /* Value mask to reconfigure window. */ 546 XWindowChanges *changes; /* Values to use in configure window. */ 547 548 register Bool config_p = False; /* Reconfigure pane window? */ 549 550 /* 551 * Update the pane serial number. 552 */ 553 p_ptr->serial = p_num; 554 555 /* 556 * Recompute window X and Y coordinates. 557 */ 558 switch (menu->menu_style) { 559 case LEFT: 560 window_x = menu->p_x_off * ((menu->p_count - 1) - p_num); 561 window_y = menu->p_y_off * ((menu->p_count - 1) - p_num); 562 break; 563 case RIGHT: 564 window_x = menu->p_x_off * p_num; 565 window_y = menu->p_y_off * ((menu->p_count - 1) - p_num); 566 break; 567 case CENTER: 568 window_x = 0; 569 window_y = menu->p_y_off * ((menu->p_count - 1) - p_num); 570 break; 571 default: 572 /* Error! Invalid style parameter. */ 573 _XMErrorCode = XME_STYLE_PARAM; 574 return(_FAILURE); 575 } 576 window_x += menu->x_pos; 577 window_y += menu->y_pos; 578 579 /* 580 * If the newly compute pane coordinates differ from the 581 * current coordinates, reset the current coordinates and 582 * reconfigure the pane. 583 */ 584 if ( 585 (window_x != p_ptr->window_x) || 586 (window_y != p_ptr->window_y) 587 ){ 588 /* 589 * Reset the coordinates and schedule 590 * the pane for reconfiguration. 591 */ 592 p_ptr->window_x = window_x; 593 p_ptr->window_y = window_y; 594 config_p = True; 595 } 596 597 /* 598 * If the local pane width and height differs from the 599 * menu pane width and height, reset the local values. 600 */ 601 if ( 602 (p_ptr->window_w != menu->p_width) || 603 (p_ptr->window_h != menu->p_height) 604 ){ 605 /* 606 * Reset window width and height and schedule 607 * the pane for reconfiguration. 608 */ 609 p_ptr->window_w = menu->p_width; 610 p_ptr->window_h = menu->p_height; 611 config_p = True; 612 } 613 614 /* 615 * If we need to reconfigure the pane window do it now. 616 */ 617 if (config_p == True) { 618 /* 619 * If the pane window has already been created then 620 * reconfigure the existing window, otherwise queue 621 * it for creation with the new configuration. 622 */ 623 if (p_ptr->window) { 624 change_mask = (CWX | CWY | CWWidth | CWHeight); 625 changes = (XWindowChanges *)malloc(sizeof(XWindowChanges)); 626 changes->x = p_ptr->window_x; 627 changes->y = p_ptr->window_y; 628 changes->width = p_ptr->window_w; 629 changes->height = p_ptr->window_h; 630 631 XConfigureWindow( 632 display, 633 p_ptr->window, 634 change_mask, 635 changes 636 ); 637 free(changes); 638 639 } 640 else { 641 if (_XMWinQueAddPane(display, menu, p_ptr) == _FAILURE) { 642 return(_FAILURE); 643 } 644 } 645 } 646 647 /* 648 * Recompute label X position. 649 */ 650 switch (menu->p_style) { 651 case LEFT: 652 p_ptr->label_x = menu->p_x_off + menu->p_fnt_pad; 653 break; 654 case RIGHT: 655 p_ptr->label_x = menu->p_width - 656 (p_ptr->label_width + menu->p_x_off + menu->p_fnt_pad); 657 break; 658 case CENTER: 659 p_ptr->label_x = (menu->p_width - p_ptr->label_width) >> 1; 660 break; 661 default: 662 /* Error! Invalid style parameter. */ 663 _XMErrorCode = XME_STYLE_PARAM; 664 return(_FAILURE); 665 } 666 /* 667 * Recompute label Y positions. 668 */ 669 p_ptr->label_uy = menu->p_fnt_pad + menu->p_fnt_info->max_bounds.ascent; 670 p_ptr->label_ly = (menu->p_height - menu->p_fnt_pad - menu->p_fnt_info->max_bounds.descent); 671 672 /* 673 * All went well, return successfully. 674 */ 675 _XMErrorCode = XME_NO_ERROR; 676 return(_SUCCESS); 677} 678 679 680 681/* 682 * _XMRecomputeSelection - Internal subroutine to recompute 683 * selection window dependencies. 684 */ 685int 686_XMRecomputeSelection(display, menu, s_ptr, s_num) 687 register Display *display; 688 register XMenu *menu; /* Menu object being recomputed. */ 689 register XMSelect *s_ptr; /* Selection pointer. */ 690 register int s_num; /* Selection sequence number. */ 691{ 692 register Bool config_s = False; /* Reconfigure selection window? */ 693 XWindowChanges *changes; /* Values to change in configure. */ 694 unsigned long change_mask; /* Value mask for XConfigureWindow. */ 695 696 /* 697 * If the selection serial numbers are out of order, begin 698 * resequencing selections. Recompute selection window coordinates 699 * and serial number. 700 * 701 * When selections are created they are given a serial number of 702 * -1, this causes this routine to give a new selection 703 * its initial coordinates and serial number. 704 */ 705 if (s_ptr->serial != s_num) { 706 /* 707 * Fix the sequence number. 708 */ 709 s_ptr->serial = s_num; 710 /* 711 * Recompute window X and Y coordinates. 712 */ 713 s_ptr->window_x = menu->s_x_off; 714 s_ptr->window_y = menu->flag_height + (menu->s_y_off * s_num); 715 /* 716 * We must reconfigure the window. 717 */ 718 config_s = True; 719 } 720 721 /* 722 * If the local selection width and height differs from the 723 * menu selection width and height, reset the local values. 724 */ 725 if ( 726 (s_ptr->window_w != menu->s_width) || 727 (s_ptr->window_h != menu->s_height) 728 ){ 729 /* 730 * We must reconfigure the window. 731 */ 732 config_s = True; 733 /* 734 * Reset window width and height. 735 */ 736 s_ptr->window_w = menu->s_width; 737 s_ptr->window_h = menu->s_height; 738 } 739 740 /* 741 * If we need to reconfigure the selection window do it now. 742 */ 743 if (config_s == True) { 744 /* 745 * If the selection window has already been created then 746 * reconfigure the existing window, otherwise queue it 747 * for creation with the new configuration. 748 */ 749 if (s_ptr->window) { 750 changes = (XWindowChanges *)malloc(sizeof(XWindowChanges)); 751 change_mask = (CWX | CWY | CWWidth | CWHeight); 752 changes = (XWindowChanges *)malloc(sizeof(XWindowChanges)); 753 changes->x = s_ptr->window_x; 754 changes->y = s_ptr->window_y; 755 changes->width = s_ptr->window_w; 756 changes->height = s_ptr->window_h; 757 758 XConfigureWindow( 759 display, 760 s_ptr->window, 761 change_mask, 762 changes 763 ); 764 free(changes); 765 766 } 767 else { 768 if (_XMWinQueAddSelection(display, menu, s_ptr) == _FAILURE) { 769 return(_FAILURE); 770 } 771 } 772 } 773 774 /* 775 * Recompute label X position. 776 */ 777 switch (menu->s_style) { 778 case LEFT: 779 s_ptr->label_x = menu->s_bdr_width + menu->s_fnt_pad + s_ptr->window_x; 780 break; 781 case RIGHT: 782 s_ptr->label_x = s_ptr->window_x + menu->s_width - 783 (s_ptr->label_width + menu->s_bdr_width + menu->s_fnt_pad); 784 break; 785 case CENTER: 786 s_ptr->label_x = s_ptr->window_x + ((menu->s_width - s_ptr->label_width) >> 1); 787 break; 788 default: 789 /* Error! Invalid style parameter. */ 790 _XMErrorCode = XME_STYLE_PARAM; 791 return(_FAILURE); 792 } 793 /* 794 * Recompute label Y position. 795 */ 796 s_ptr->label_y = s_ptr->window_y + menu->s_fnt_info->max_bounds.ascent + menu->s_fnt_pad + menu->s_bdr_width; 797 798 /* 799 * All went well, return successfully. 800 */ 801 _XMErrorCode = XME_NO_ERROR; 802 return(_SUCCESS); 803} 804 805 806 807/* 808 * _XMTransToOrigin - Internal subroutine to translate the point at 809 * the center of the current pane and selection to the 810 * the menu origin. 811 * 812 * WARNING! ****** Be certain that all menu dependencies have been 813 * recomputed before calling this routine or 814 * unpredictable results will follow. 815 */ 816_XMTransToOrigin(display, menu, p_ptr, s_ptr, x_pos, y_pos, orig_x, orig_y) 817 Display *display; /* Not used. Included for consistency. */ 818 register XMenu *menu; /* Menu being computed against. */ 819 register XMPane *p_ptr; /* Current pane pointer. */ 820 register XMSelect *s_ptr; /* Current selection pointer. */ 821 int x_pos; /* X coordinate of point to translate. */ 822 int y_pos; /* Y coordinate of point to translate. */ 823 int *orig_x; /* Return value X coord. of the menu origin. */ 824 int *orig_y; /* Return value Y coord. of the menu origin. */ 825{ 826 register int l_orig_x; /* Local X coordinate of the menu origin. */ 827 register int l_orig_y; /* Local Y coordinate of the menu origin. */ 828 829 /* 830 * Translate the menu origin such that the cursor hot point will be in the 831 * center of the desired current selection and pane. 832 * If the current selection pointer is NULL then assume that the hot point 833 * will be in the center of the current pane flag. 834 */ 835 836 if (s_ptr == NULL) { 837 /* 838 * Translate from the center of the pane flag to the upper left 839 * of the current pane window. 840 */ 841 l_orig_x = x_pos - (menu->p_width >> 1) - menu->p_bdr_width; 842 l_orig_y = y_pos - (menu->flag_height >> 1) - menu->p_bdr_width; 843 } 844 else { 845 /* 846 * First translate from the center of the current selection 847 * to the upper left of the current selection window. 848 */ 849 l_orig_x = x_pos - (menu->s_width >> 1); 850 l_orig_y = y_pos - (menu->s_height >> 1); 851 852 /* 853 * Then translate to the upper left of the current pane window. 854 */ 855 l_orig_x -= (s_ptr->window_x + menu->p_bdr_width); 856 l_orig_y -= (s_ptr->window_y + menu->p_bdr_width); 857 } 858 859 /* 860 * Finally translate to the upper left of the menu. 861 */ 862 l_orig_x -= (p_ptr->window_x - menu->x_pos); 863 l_orig_y -= (p_ptr->window_y - menu->y_pos); 864 865 /* 866 * Set the return values. 867 */ 868 *orig_x = l_orig_x; 869 *orig_y = l_orig_y; 870} 871 872/* 873 * _XMRefreshPane - Internal subroutine to completely refresh 874 * the contents of a pane. 875 */ 876_XMRefreshPane(display, menu, pane) 877 register Display *display; 878 register XMenu *menu; 879 register XMPane *pane; 880{ 881 register XMSelect *s_list = pane->s_list; 882 register XMSelect *s_ptr; 883 884 /* 885 * First clear the pane. 886 */ 887 XClearWindow(display, pane->window); 888 if (!pane->activated) { 889 XFillRectangle(display, 890 pane->window, 891 menu->inverse_select_GC, 892 pane->label_x - menu->p_fnt_pad, 893 pane->label_uy - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad, 894 pane->label_width + (menu->p_fnt_pad << 1), 895 menu->flag_height); 896 897 XFillRectangle(display, 898 pane->window, 899 menu->inverse_select_GC, 900 pane->label_x - menu->p_fnt_pad, 901 pane->label_ly - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad, 902 pane->label_width + (menu->p_fnt_pad << 1), 903 menu->flag_height); 904 } 905 if (!pane->active) { 906 XDrawString(display, 907 pane->window, 908 menu->inact_GC, 909 pane->label_x, pane->label_uy, 910 pane->label, pane->label_length); 911 XDrawString(display, 912 pane->window, 913 menu->inact_GC, 914 pane->label_x, pane->label_ly, 915 pane->label, pane->label_length); 916 } 917 else { 918 XDrawString(display, 919 pane->window, 920 menu->pane_GC, 921 pane->label_x, pane->label_uy, 922 pane->label, pane->label_length); 923 XDrawString(display, 924 pane->window, 925 menu->pane_GC, 926 pane->label_x, pane->label_ly, 927 pane->label, pane->label_length); 928 929 /* 930 * Finally refresh each selection if the pane is activated. 931 */ 932 if (pane->activated) { 933 for (s_ptr = s_list->next; s_ptr != s_list; s_ptr = s_ptr->next) 934 _XMRefreshSelection(display, menu, s_ptr); 935 } 936 } 937} 938 939 940 941 942/* 943 * _XMRefreshSelection - Internal subroutine that refreshes 944 * a single selection window. 945 */ 946_XMRefreshSelection(display, menu, select) 947 register Display *display; 948 register XMenu *menu; 949 register XMSelect *select; 950{ 951 register int width = select->window_w; 952 register int height = select->window_h; 953 register int bdr_width = menu->s_bdr_width; 954 955 if (select->type == SEPARATOR) { 956 XDrawLine(display, 957 select->parent_p->window, 958 menu->normal_select_GC, 959 select->window_x, 960 select->window_y + height / 2, 961 select->window_x + width, 962 select->window_y + height / 2); 963 } 964 else if (select->activated) { 965 if (menu->menu_mode == INVERT) { 966 XFillRectangle(display, 967 select->parent_p->window, 968 menu->normal_select_GC, 969 select->window_x, select->window_y, 970 width, height); 971 XDrawString(display, 972 select->parent_p->window, 973 menu->inverse_select_GC, 974 select->label_x, 975 select->label_y, 976 select->label, select->label_length); 977 } 978 else { 979 /* 980 * Using BOX mode. 981 * Since most drawing routines with arbitrary width lines 982 * are slow compared to raster-ops lets use a raster-op to 983 * draw the boxes. 984 */ 985 986 XDrawRectangle(display, 987 select->parent_p->window, 988 menu->normal_select_GC, 989 select->window_x + (bdr_width >> 1), 990 select->window_y + (bdr_width >> 1 ), 991 width - bdr_width, 992 height - bdr_width); 993 XDrawString(display, 994 select->parent_p->window, 995 menu->normal_select_GC, 996 select->label_x, 997 select->label_y, 998 select->label, select->label_length); 999 } 1000 } 1001 else { 1002 XClearArea(display, 1003 select->parent_p->window, 1004 select->window_x, select->window_y, 1005 width, height, 1006 False); 1007 if (select->active) { 1008 XDrawString(display, 1009 select->parent_p->window, 1010 menu->normal_select_GC, 1011 select->label_x, 1012 select->label_y, 1013 select->label, select->label_length); 1014 } 1015 else { 1016 XDrawString(display, 1017 select->parent_p->window, 1018 menu->inact_GC, 1019 select->label_x, 1020 select->label_y, 1021 select->label, select->label_length); 1022 } 1023 } 1024} 1025 1026/* arch-tag: 3ac61957-0852-4e72-8b88-7dfab1a5dee9 1027 (do not change this comment) */ 1028