Jitterbug no more.
[fvwm.git] / modules / FvwmButtons / button.c
blob33eaff64d3ab77ba283b91d571661ae110bab82a
1 /* -*-c-*- */
2 /*
3 * FvwmButtons, copyright 1996, Jarl Totland
5 * This module, and the entire GoodStuff program, and the concept for
6 * interfacing this module to the Window Manager, are all original work
7 * by Robert Nation
9 * Copyright 1993, Robert Nation. No guarantees or warantees or anything
10 * are provided or implied in any way whatsoever. Use this program at your
11 * own risk. Permission to use this program for any purpose is given,
12 * as long as the copyright is kept intact.
16 /* This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "config.h"
33 #include <unistd.h>
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <X11/Intrinsic.h>
37 #include "FvwmButtons.h"
38 #include "button.h"
40 extern char *MyName;
43 int buttonXPos(const button_info *b, int i)
45 int column = i % b->parent->c->num_columns;
47 return b->parent->c->xpos +
48 (b->parent->c->width * column / b->parent->c->num_columns);
51 int buttonYPos(const button_info *b, int i)
53 int row = i / b->parent->c->num_columns;
55 return b->parent->c->ypos +
56 (b->parent->c->height * row / b->parent->c->num_rows);
59 int buttonWidth(const button_info *b)
61 int column = b->n % b->parent->c->num_columns;
62 int column2 = column + b->BWidth;
64 return (b->parent->c->width * column2 / b->parent->c->num_columns) -
65 (b->parent->c->width * column / b->parent->c->num_columns);
68 int buttonHeight(const button_info *b)
70 int row = b->n / b->parent->c->num_columns;
71 int row2 = row + b->BHeight;
73 return (b->parent->c->height * row2 / b->parent->c->num_rows) -
74 (b->parent->c->height * row / b->parent->c->num_rows);
77 int buttonSwallowCount(button_info *b)
79 return (b->flags.b_Swallow || b->flags.b_Panel) ? (b->swallow & b_Count) : 0;
83 /**
84 *** buttonInfo()
85 *** Give lots of info for this button: XPos, YPos, XPad, YPad, Frame(signed)
86 **/
87 void buttonInfo(const button_info *b, int *x, int *y, int *px, int *py, int *f)
89 ushort bPadding = (b->flags.b_Padding ? 0 : 1);
90 ushort bFrame = (b->flags.b_Frame ? 0 : 1);
91 *x=buttonXPos(b,b->n);
92 *y=buttonYPos(b,b->n);
93 *px=b->xpad;
94 *py=b->ypad;
95 *f=b->framew;
97 if(b->flags.b_Container && bFrame)
99 *f=0;
100 bFrame = 0;
102 if((b->flags.b_Container || b->flags.b_Swallow) && bPadding)
104 *px=*py=0;
105 bPadding = 0;
108 while((bPadding || bFrame) && (b=b->parent))
110 if(bFrame && b->c->flags.b_Frame)
112 *f=b->c->framew;
113 bFrame = 0;
115 if(bPadding && b->c->flags.b_Padding)
117 *px=b->c->xpad;
118 *py=b->c->ypad;
119 bPadding = 0;
125 *** GetInternalSize()
127 void GetInternalSize(button_info *b,int *x,int *y,int *w,int *h)
129 int f;
130 int px,py;
131 buttonInfo(b,x,y,&px,&py,&f);
132 f=abs(f);
134 *w=buttonWidth(b)-2*(px+f);
135 *h=buttonHeight(b)-2*(py+f);
137 *x+=f+px;
138 *y+=f+py;
140 if (*w < 1)
141 *w = 1;
142 if (*h < 1)
143 *h = 1;
145 return;
149 *** buttonFrameSigned()
150 *** Give the signed framewidth for this button.
152 int buttonFrameSigned(button_info *b)
154 if(b->flags.b_Frame)
155 return b->framew;
156 if(b->flags.b_Container) /* Containers usually gets 0 relief */
157 return 0;
158 while((b=b->parent))
159 if(b->c->flags.b_Frame)
160 return b->c->framew;
161 #ifdef DEBUG
162 fprintf(stderr,"%s: BUG: No relief width definition?\n",MyName);
163 #endif
164 return 0;
168 *** buttonXPad()
169 *** Give the x padding for this button
171 int buttonXPad(button_info *b)
173 if(b->flags.b_Padding)
174 return b->xpad;
175 if(b->flags.b_Container || b->flags.b_Swallow) /* Normally no padding for these */
176 return 0;
177 while((b=b->parent))
178 if(b->c->flags.b_Padding)
179 return b->c->xpad;
180 #ifdef DEBUG
181 fprintf(stderr,"%s: BUG: No padding definition?\n",MyName);
182 #endif
183 return 0;
187 *** buttonYPad()
188 *** Give the y padding for this button
190 int buttonYPad(button_info *b)
192 if(b->flags.b_Padding)
193 return b->ypad;
194 if(b->flags.b_Container || b->flags.b_Swallow) /* Normally no padding for these */
195 return 0;
196 while((b=b->parent))
197 if(b->c->flags.b_Padding)
198 return b->c->ypad;
199 #ifdef DEBUG
200 fprintf(stderr,"%s: BUG: No padding definition?\n",MyName);
201 #endif
202 return 0;
206 *** buttonFont()
207 *** Give the font pointer for this button
209 FlocaleFont *buttonFont(button_info *b)
211 if(b->flags.b_Font)
212 return b->Ffont;
213 while((b=b->parent))
214 if(b->c->flags.b_Font)
215 return b->c->Ffont;
216 #ifdef DEBUG
217 fprintf(stderr,"%s: BUG: No font definition?\n",MyName);
218 #endif
219 return None;
223 *** buttonFore()
224 *** Give the foreground pixel of this button
226 Pixel buttonFore(const button_info *b)
228 if(b->flags.b_Fore)
229 return b->fc;
230 while ((b=b->parent))
232 if(b->c->flags.b_Fore)
233 return b->c->fc;
235 #ifdef DEBUG
236 fprintf(stderr,"%s: BUG: No foreground definition?\n",MyName);
237 #endif
238 return None;
242 *** buttonBack()
243 *** Give the background pixel of this button
245 Pixel buttonBack(const button_info *b)
247 if(b->flags.b_Back)
248 return b->bc;
249 while((b=b->parent))
251 if(b->c->flags.b_Back)
252 return b->c->bc;
254 #ifdef DEBUG
255 fprintf(stderr,"%s: BUG: No background definition?\n",MyName);
256 #endif
257 return None;
261 *** buttonHilite()
262 *** Give the relief pixel of this button
264 Pixel buttonHilite(button_info *b)
266 if(b->flags.b_Back)
267 return b->hc;
268 while((b=b->parent))
270 if(b->c->flags.b_Back)
271 return b->c->hc;
273 #ifdef DEBUG
274 fprintf(stderr,"%s: BUG: No background definition?\n",MyName);
275 #endif
276 return None;
280 *** buttonShadow()
281 *** Give the shadow pixel of this button
283 Pixel buttonShadow(button_info *b)
285 if(b->flags.b_Back)
286 return b->sc;
287 while((b=b->parent))
289 if(b->c->flags.b_Back)
290 return b->c->sc;
292 #ifdef DEBUG
293 fprintf(stderr,"%s: BUG: No background definition?\n",MyName);
294 #endif
295 return None;
298 int buttonColorset(button_info *b)
300 if (b->flags.b_Hangon)
302 if (b->flags.b_PressColorset)
303 return b->pressColorset;
304 if (UberButton->c->flags.b_PressColorset)
305 return UberButton->c->pressColorset;
307 else if (b == ActiveButton && b->flags.b_ActiveColorset)
308 return b->activeColorset;
309 else if (b == ActiveButton && UberButton->c->flags.b_ActiveColorset)
310 return UberButton->c->activeColorset;
311 else if (b == CurrentButton && b->flags.b_PressColorset)
312 return b->pressColorset;
313 else if (b == CurrentButton && UberButton->c->flags.b_PressColorset)
314 return UberButton->c->pressColorset;
316 if (b->flags.b_Colorset)
317 return b->colorset;
318 else if (b->flags.b_Container && b->c->flags.b_Colorset)
319 return b->c->colorset;
320 while ((b = b->parent))
322 if (b->c->flags.b_Colorset)
323 return b->c->colorset;
325 return -1;
328 char *buttonTitle (button_info *b)
330 if (b->flags.b_Hangon)
332 if (b->flags.b_PressTitle)
333 return b->pressTitle;
335 /* If this is the current active button but no explicit ActiveTitle was
336 specified, use the Title (if there is one).
337 Similarly for PressTitle. */
338 else if (b == ActiveButton && b->flags.b_ActiveTitle)
339 return b->activeTitle;
340 else if (b == CurrentButton && b->flags.b_PressTitle)
341 return b->pressTitle;
343 if (b->flags.b_Title)
344 return b->title;
346 return NULL;
349 FvwmPicture *buttonIcon (button_info *b)
351 if (b->flags.b_Hangon)
353 if (b->flags.b_PressIcon)
354 return b->pressicon;
356 else if (b == ActiveButton && b->flags.b_ActiveIcon)
357 return b->activeicon;
358 else if (b == CurrentButton && b->flags.b_PressIcon)
359 return b->pressicon;
361 /* b->icon == None if no icon specified */
362 return b->icon;
365 unsigned short iconFlagSet (button_info *b)
367 if (b->flags.b_Hangon)
369 if (b->flags.b_PressIcon)
370 return 1;
372 else if (b == ActiveButton && b->flags.b_ActiveIcon)
373 return 1;
374 else if (b == CurrentButton && b->flags.b_PressIcon)
375 return 1;
377 return (b->flags.b_Icon ? 1 : 0);
380 int buttonBackgroundButton(button_info *b, button_info **r_b)
382 button_info *tmpb, *pb;
383 Bool done = False;
385 tmpb = pb = b;
386 while(tmpb->parent != NULL && !done)
388 pb = tmpb;
389 if (tmpb->flags.b_Container)
391 if(tmpb->c->flags.b_Colorset)
393 done = True;
395 else if (!(tmpb->c->flags.b_IconParent) &&
396 !(tmpb->c->flags.b_ColorsetParent))
398 done = True;
402 else if (tmpb->flags.b_Swallow && buttonSwallowCount(b) == 3 &&
403 tmpb->flags.b_Colorset)
405 done = True;
407 else if (tmpb->flags.b_Colorset)
409 done = True;
411 else if (!tmpb->flags.b_IconBack && !tmpb->flags.b_IconParent
412 && !tmpb->flags.b_Swallow &&
413 !tmpb->flags.b_ColorsetParent)
415 done = True;
417 tmpb = tmpb->parent;
420 if (done)
422 if (r_b != NULL)
423 *r_b = pb;
424 return True;
426 return False;
431 *** buttonSwallow()
432 *** Give the swallowing flags for this button
434 byte buttonSwallow(button_info *b)
436 byte s=0,t=0;
437 if(b->flags.b_Swallow || b->flags.b_Panel)
439 s=b->swallow;
440 t=b->swallow_mask;
442 while((b=b->parent))
444 if(b->c->flags.b_Swallow || b->c->flags.b_Panel)
446 s&=~(b->c->swallow_mask&~t);
447 s|=(b->c->swallow&b->c->swallow_mask&~t);
448 t|=b->c->swallow_mask;
451 return s;
455 *** buttonJustify()
456 *** Give the justify flags for this button
458 byte buttonJustify(button_info *b)
460 byte j=1,i=0;
461 if(b->flags.b_Justify)
463 i=b->justify_mask;
464 j=b->justify;
466 while((b=b->parent))
468 if(b->c->flags.b_Justify)
470 j&=~(b->c->justify_mask&~i);
471 j|=(b->c->justify&b->c->justify_mask&~i);
472 i|=b->c->justify_mask;
475 return j;
478 /* ---------------------------- button creation ---------------------------- */
481 *** alloc_buttonlist()
482 *** Makes sure the list of butten_info's is long enough, if not it reallocates
483 *** a longer one. This happens in steps of 32. Inital length is 0.
485 void alloc_buttonlist(button_info *ub,int num)
487 button_info **bb;
488 int i;
489 /* needed to prevent a gcc -O3 bug */
490 volatile int old;
492 if(num>=ub->c->allocated_buttons)
494 old=ub->c->allocated_buttons;
495 if(num<old || old>(old+32)) /* test for num<old or for signed overflow */
497 fprintf(stderr,"%s: Too many buttons, integer overflow\n",MyName);
498 exit(1);
500 while(ub->c->allocated_buttons<=num)
501 ub->c->allocated_buttons+=32;
502 bb=(button_info**)
503 mymalloc(ub->c->allocated_buttons*sizeof(button_info*));
504 for(i=old;i<ub->c->allocated_buttons;i++)
505 bb[i]=NULL;
506 if(ub->c->buttons)
508 for(i=0;i<old;i++) bb[i]=ub->c->buttons[i];
509 free(ub->c->buttons);
511 ub->c->buttons=bb;
516 *** alloc_button()
517 *** Allocates memory for a new button struct. Calles alloc_buttonlist to
518 *** assure enough space is present. Also initiates most elements of the struct.
520 button_info *alloc_button(button_info *ub,int num)
522 button_info *b;
523 if(num>=ub->c->allocated_buttons)
524 alloc_buttonlist(ub,num);
525 if(ub->c->buttons[num])
527 fprintf(stderr,"%s: Allocated button twice, report bug twice\n",MyName);
528 exit(2);
531 b=(button_info*)mymalloc(sizeof(button_info));
532 ub->c->buttons[num]=b;
534 memset((void *)b, 0, sizeof(*b));
535 b->swallow = 0;
536 b->BWidth = b->BHeight = 1;
537 b->BPosX = b->BPosY = 0;
538 b->parent = ub;
539 b->n = -1;
540 b->IconWin = 0;
541 b->PanelWin = 0;
543 b->framew = 1;
544 b->xpad = 2;
545 b->ypad = 4;
546 b->w=1;
547 b->h=1;
548 b->bw=1;
550 #if 0
551 if(b->parent != NULL)
553 if (b->parent->c->flags & b_Colorset)
554 b->flags |= b_ColorsetParent;
556 #endif
558 return(b);
562 *** MakeContainer()
563 *** Allocs and sets the container-specific fields of a button.
565 void MakeContainer(button_info *b)
567 b->c=(container_info*)mymalloc(sizeof(container_info));
568 memset((void *)b->c, 0, sizeof(container_info));
569 b->flags.b_Container = 1;
570 if(b->parent != NULL)
572 if (b->parent->c->flags.b_IconBack || b->parent->c->flags.b_IconParent)
573 b->c->flags.b_IconParent = 1;
574 if (b->parent->c->flags.b_Colorset ||
575 b->parent->c->flags.b_ColorsetParent)
576 b->c->flags.b_ColorsetParent = 1;
578 else /* This applies to the UberButton */
580 b->c->flags.b_Font = 1;
581 b->c->flags.b_Padding = 1;
582 b->c->flags.b_Frame = 1;
583 b->c->flags.b_Back = 1;
584 b->c->flags.b_Fore = 1;
585 b->c->font_string=safestrdup("fixed");
586 b->c->xpad=2;
587 b->c->ypad=4;
588 b->c->back=safestrdup("rgb:90/80/90");
589 b->c->fore=safestrdup("black");
590 b->c->framew=2;
595 /* -------------------------- button administration ------------------------ */
598 *** NumberButtons()
599 *** Prepare the n fields in each button
601 void NumberButtons(button_info *b)
603 int i=-1;
604 while(++i<b->c->num_buttons)
605 if(b->c->buttons[i])
607 b->c->buttons[i]->n=i;
608 if(b->c->buttons[i]->flags.b_Container)
609 NumberButtons(b->c->buttons[i]);
614 *** PlaceAndExpandButton()
615 *** Places a button in it's container and claims all needed slots.
617 char PlaceAndExpandButton(int x, int y, button_info *b, button_info *ub)
619 int i,j,k;
620 container_info *c=ub->c;
622 i = x+y*c->num_columns;
623 if (x>=c->num_columns || x<0)
625 fprintf(stderr,"%s: Button out of horizontal range. Quitting.\n",MyName);
626 fprintf(stderr,"Button=%d num_columns=%d BPosX=%d\n",
627 i,c->num_columns,b->BPosX);
628 exit(1);
630 if (y>=c->num_rows || y<0)
632 if (b->flags.b_PosFixed || !ub->c->flags.b_SizeSmart || y<0)
634 fprintf(stderr,"%s: Button out of vertical range. Quitting.\n",
635 MyName);
636 fprintf(stderr,"Button=%d num_rows=%d BPosY=%d\n",
637 i,c->num_rows,b->BPosY);
638 exit(1);
640 c->num_rows=y+b->BHeight;
641 c->num_buttons=c->num_columns*c->num_rows;
642 alloc_buttonlist(ub,c->num_buttons);
644 if(x+b->BWidth>c->num_columns)
646 fprintf(stderr,"%s: Button too wide. giving up\n",MyName);
647 fprintf(stderr,"Button=%d num_columns=%d bwidth=%d w=%d\n",
648 i,c->num_columns,b->BWidth,x);
649 b->BWidth = c->num_columns-x;
651 if(y+b->BHeight>c->num_rows)
653 if (c->flags.b_SizeSmart)
655 c->num_rows=y+b->BHeight;
656 c->num_buttons=c->num_columns*c->num_rows;
657 alloc_buttonlist(ub,c->num_buttons);
659 else
661 fprintf(stderr,"%s: Button too tall. Giving up\n",MyName);
662 fprintf(stderr,"Button=%d num_rows=%d bheight=%d h=%d\n",
663 i,c->num_rows,b->BHeight,y);
664 b->BHeight = c->num_rows-y;
668 /* check if buttons are free */
669 for(k=0;k<b->BHeight;k++)
670 for(j=0;j<b->BWidth;j++)
671 if (c->buttons[i+j+k*c->num_columns])
672 return 1;
673 /* claim all buttons */
674 for(k=0;k<b->BHeight;k++)
675 for(j=0;j<b->BWidth;j++)
676 c->buttons[i+j+k*c->num_columns] = b;
677 b->BPosX = x;
678 b->BPosY = y;
679 return 0;
683 *** ShrinkButton()
684 *** Frees all but the upper left slot a button uses in it's container.
686 void ShrinkButton(button_info *b, container_info *c)
688 int i,j,k,l;
690 if (!b)
692 fprintf(stderr,"error: shrink1: button is empty but shouldn't\n");
693 exit(1);
695 i = b->BPosX+b->BPosY*c->num_columns;
696 /* free all buttons but the upper left corner */
697 for(k=0;k<b->BHeight;k++)
699 for(j=0;j<b->BWidth;j++)
701 if(j||k)
703 l = i+j+k*c->num_columns;
704 if (c->buttons[l] != b)
706 fprintf(stderr,"error: shrink2: button was stolen\n");
707 exit(1);
709 c->buttons[l] = NULL;
716 *** ShuffleButtons()
717 *** Orders and sizes the buttons in the UberButton, corrects num_rows and
718 *** num_columns in containers.
720 void ShuffleButtons(button_info *ub)
722 int i,actual_buttons_used;
723 int next_button_x, next_button_y, num_items;
724 button_info *b;
725 button_info **local_buttons;
726 container_info *c=ub->c;
728 /* make local copy of buttons in ub */
729 num_items = c->num_buttons;
730 local_buttons=(button_info**)mymalloc(sizeof(button_info)*num_items);
731 for(i=0;i<num_items;i++)
733 local_buttons[i] = c->buttons[i];
734 c->buttons[i] = NULL;
737 /* Allow for multi-width/height buttons */
738 actual_buttons_used = 0;
739 for(i=0;i<num_items;i++)
740 actual_buttons_used+=local_buttons[i]->BWidth*local_buttons[i]->BHeight;
742 if (!c->flags.b_SizeFixed||!(c->num_rows)||!(c->num_columns))
744 /* Size and create the window */
745 if(c->num_rows==0 && c->num_columns==0)
746 c->num_rows=2;
747 if(c->num_columns==0)
748 c->num_columns=1+(actual_buttons_used-1)/c->num_rows;
749 if(c->num_rows==0)
750 c->num_rows=1+(actual_buttons_used-1)/c->num_columns;
751 while(c->num_rows * c->num_columns < actual_buttons_used)
752 c->num_columns++;
753 if (!c->flags.b_SizeFixed)
755 while(c->num_rows*c->num_columns >=
756 actual_buttons_used + c->num_columns)
757 c->num_rows--;
761 if (c->flags.b_SizeSmart)
763 /* Set rows/columns to at least the height/width of largest button */
764 for(i=0;i<num_items;i++)
766 b=local_buttons[i];
767 if (c->num_rows<b->BHeight)
768 c->num_rows=b->BHeight;
769 if (c->num_columns<b->BWidth)
770 c->num_columns=b->BWidth;
771 if (b->flags.b_PosFixed && c->num_columns<b->BWidth+b->BPosX)
772 c->num_columns=b->BWidth+b->BPosX;
773 if (b->flags.b_PosFixed && c->num_columns<b->BWidth-b->BPosX)
774 c->num_columns=b->BWidth-b->BPosX;
775 if (b->flags.b_PosFixed && c->num_rows<b->BHeight+b->BPosY)
776 c->num_rows=b->BHeight+b->BPosY;
777 if (b->flags.b_PosFixed && c->num_rows<b->BHeight-b->BPosY)
778 c->num_rows=b->BHeight-b->BPosY;
782 /* this was buggy before */
783 c->num_buttons = c->num_rows*c->num_columns;
784 alloc_buttonlist(ub,c->num_buttons);
786 /* Shuffle subcontainers */
787 for(i=0;i<num_items;i++)
789 b=local_buttons[i];
790 /* Shuffle subcontainers recursively */
791 if(b && b->flags.b_Container)
792 ShuffleButtons(b);
795 /* Place fixed buttons as given in BPosX and BPosY */
796 for(i=0;i<num_items;i++)
798 b=local_buttons[i];
799 if (!b->flags.b_PosFixed) continue;
800 /* recalculate position for negative offsets */
801 if (b->BPosX<0) b->BPosX=b->BPosX+c->num_columns-b->BWidth+1;
802 if (b->BPosY<0) b->BPosY=b->BPosY+c->num_rows-b->BHeight+1;
803 /* Move button if position given by user */
804 if (PlaceAndExpandButton(b->BPosX,b->BPosY,b,ub))
806 fprintf(stderr, "%s: Overlapping fixed buttons. Quitting.\n",MyName);
807 fprintf(stderr, "Button=%d, x=%d, y=%d\n", i,b->BPosX,b->BPosY);
808 exit(1);
812 /* place floating buttons dynamically */
813 next_button_x = next_button_y = 0;
814 for(i=0;i<num_items;i++)
816 b=local_buttons[i];
817 if (b->flags.b_PosFixed) continue;
819 if (next_button_x+b->BWidth>c->num_columns)
821 next_button_y++;
822 next_button_x=0;
824 /* Search for next free position to accomodate button */
825 while (PlaceAndExpandButton(next_button_x,next_button_y,b,ub))
827 next_button_x++;
828 if (next_button_x+b->BWidth>c->num_columns)
830 next_button_y++;
831 next_button_x=0;
832 if (next_button_y>=c->num_rows)
834 /* could not place button */
835 fprintf(stderr,"%s: Button confusion! Quitting\n", MyName);
836 exit(1);
842 /* shrink buttons in Container */
843 for(i=0;i<num_items;i++)
844 ShrinkButton(local_buttons[i], c);
845 free(local_buttons);
848 /* ----------------------------- button iterator --------------------------- */
851 *** NextButton()
852 *** Iterator to traverse buttontree. Start it with first argument a pointer
853 *** to the root UberButton, and the index int set to -1. Each subsequent call
854 *** gives the pointer to uberbutton, button and button index within uberbutton.
855 *** If all, also returns containers, apart from the UberButton.
857 button_info *NextButton(button_info **ub,button_info **b,int *i,int all)
859 /* Get next button */
860 (*i)++;
861 /* Skip fake buttons */
862 while((*i)<(*ub)->c->num_buttons && !(*ub)->c->buttons[*i])
863 (*i)++;
864 /* End of contained buttons */
865 if((*i)>=(*ub)->c->num_buttons)
867 *b=*ub;
868 *ub=(*b)->parent;
869 /* End of the world as we know it */
870 if(!(*ub))
872 *b=NULL;
873 return *b;
875 *i=(*b)->n;
876 if((*i)>=(*ub)->c->num_buttons)
878 fprintf(stderr,"%s: BUG: Couldn't return to uberbutton\n",MyName);
879 exit(2);
881 NextButton(ub,b,i,all);
882 return *b;
884 *b=(*ub)->c->buttons[*i];
886 /* Found new container */
887 if((*b)->flags.b_Container)
889 *i=-1;
890 *ub=*b;
891 if(!all)
892 NextButton(ub,b,i,all);
893 return *b;
895 return *b;
898 /* --------------------------- button navigation --------------------------- */
901 *** button_belongs_to()
902 *** Function that finds out which button a given position belongs to.
903 *** Returns -1 if not part of any, button if a proper button.
905 int button_belongs_to(button_info *ub,int button)
907 int x,y,xx,yy;
908 button_info *b;
909 if(!ub || button<0 || button>ub->c->num_buttons)
910 return -1;
911 if(ub->c->buttons[button])
912 return button;
913 yy=button/ub->c->num_columns;
914 xx=button%ub->c->num_columns;
915 for(y=yy;y>=0;y--)
917 for(x=xx;x>=0;x--)
919 b=ub->c->buttons[x+y*ub->c->num_columns];
920 if(b && (x+b->BWidth > xx) && (y+b->BHeight > yy))
922 return x+y*ub->c->num_columns;
926 return -1;
930 *** get_xy_button()
931 *** Function that returns the button that covers the given row/column in the
932 *** button matrix. Returns NULL if none.
934 button_info *get_xy_button(button_info *ub, int row, int column)
936 int i;
938 if (!ub->flags.b_Container)
940 return NULL;
942 i = button_belongs_to(ub, column + row * ub->c->num_columns);
943 if (i == -1)
945 return NULL;
948 return ub->c->buttons[i];
952 *** select_button()
953 *** Given (x,y) and uberbutton, returns pointer to referred button, or NULL
955 button_info *select_button(button_info *ub,int x,int y)
957 int i;
958 int row;
959 int column;
960 button_info *b;
962 if (!ub->flags.b_Container)
963 return ub;
965 x -= buttonXPad(ub) + buttonFrame(ub);
966 y -= buttonYPad(ub) + buttonFrame(ub);
968 if(x >= ub->c->width || x < 0 || y >= ub->c->height || y < 0)
969 return ub;
971 column = x * ub->c->num_columns / ub->c->width;
972 row = y * ub->c->num_rows / ub->c->height;
973 i = button_belongs_to(ub, column + row * ub->c->num_columns);
974 if (i == -1)
975 return ub;
976 b = ub->c->buttons[i];
978 return select_button(
979 b, x + ub->c->xpos - buttonXPos(b, i),
980 y + ub->c->ypos - buttonYPos(b, i));
983 void get_button_root_geometry(rectangle *r, const button_info *b)
985 int x;
986 int y;
987 int f;
988 Window win;
990 r->width = buttonWidth(b);
991 r->height = buttonHeight(b);
992 buttonInfo(b, &r->x, &r->y, &x, &y, &f);
993 XTranslateCoordinates(
994 Dpy, MyWindow, Root, r->x, r->y, &r->x, &r->y, &win);
996 return;