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