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
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
36 #include <X11/Intrinsic.h>
37 #include "FvwmButtons.h"
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;
85 *** Give lots of info for this button: XPos, YPos, XPad, YPad, Frame(signed)
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
);
97 if(b
->flags
.b_Container
&& bFrame
)
102 if((b
->flags
.b_Container
|| b
->flags
.b_Swallow
) && bPadding
)
108 while((bPadding
|| bFrame
) && (b
=b
->parent
))
110 if(bFrame
&& b
->c
->flags
.b_Frame
)
115 if(bPadding
&& b
->c
->flags
.b_Padding
)
125 *** GetInternalSize()
127 void GetInternalSize(button_info
*b
,int *x
,int *y
,int *w
,int *h
)
131 buttonInfo(b
,x
,y
,&px
,&py
,&f
);
134 *w
=buttonWidth(b
)-2*(px
+f
);
135 *h
=buttonHeight(b
)-2*(py
+f
);
149 *** buttonFrameSigned()
150 *** Give the signed framewidth for this button.
152 int buttonFrameSigned(button_info
*b
)
156 if(b
->flags
.b_Container
) /* Containers usually gets 0 relief */
159 if(b
->c
->flags
.b_Frame
)
162 fprintf(stderr
,"%s: BUG: No relief width definition?\n",MyName
);
169 *** Give the x padding for this button
171 int buttonXPad(button_info
*b
)
173 if(b
->flags
.b_Padding
)
175 if(b
->flags
.b_Container
|| b
->flags
.b_Swallow
) /* Normally no padding for these */
178 if(b
->c
->flags
.b_Padding
)
181 fprintf(stderr
,"%s: BUG: No padding definition?\n",MyName
);
188 *** Give the y padding for this button
190 int buttonYPad(button_info
*b
)
192 if(b
->flags
.b_Padding
)
194 if(b
->flags
.b_Container
|| b
->flags
.b_Swallow
) /* Normally no padding for these */
197 if(b
->c
->flags
.b_Padding
)
200 fprintf(stderr
,"%s: BUG: No padding definition?\n",MyName
);
207 *** Give the font pointer for this button
209 FlocaleFont
*buttonFont(button_info
*b
)
214 if(b
->c
->flags
.b_Font
)
217 fprintf(stderr
,"%s: BUG: No font definition?\n",MyName
);
224 *** Give the foreground pixel of this button
226 Pixel
buttonFore(const button_info
*b
)
230 while ((b
=b
->parent
))
232 if(b
->c
->flags
.b_Fore
)
236 fprintf(stderr
,"%s: BUG: No foreground definition?\n",MyName
);
243 *** Give the background pixel of this button
245 Pixel
buttonBack(const button_info
*b
)
251 if(b
->c
->flags
.b_Back
)
255 fprintf(stderr
,"%s: BUG: No background definition?\n",MyName
);
262 *** Give the relief pixel of this button
264 Pixel
buttonHilite(button_info
*b
)
270 if(b
->c
->flags
.b_Back
)
274 fprintf(stderr
,"%s: BUG: No background definition?\n",MyName
);
281 *** Give the shadow pixel of this button
283 Pixel
buttonShadow(button_info
*b
)
289 if(b
->c
->flags
.b_Back
)
293 fprintf(stderr
,"%s: BUG: No background definition?\n",MyName
);
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
)
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
;
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
)
349 FvwmPicture
*buttonIcon (button_info
*b
)
351 if (b
->flags
.b_Hangon
)
353 if (b
->flags
.b_PressIcon
)
356 else if (b
== ActiveButton
&& b
->flags
.b_ActiveIcon
)
357 return b
->activeicon
;
358 else if (b
== CurrentButton
&& b
->flags
.b_PressIcon
)
361 /* b->icon == None if no icon specified */
365 unsigned short iconFlagSet (button_info
*b
)
367 if (b
->flags
.b_Hangon
)
369 if (b
->flags
.b_PressIcon
)
372 else if (b
== ActiveButton
&& b
->flags
.b_ActiveIcon
)
374 else if (b
== CurrentButton
&& b
->flags
.b_PressIcon
)
377 return (b
->flags
.b_Icon
? 1 : 0);
380 int buttonBackgroundButton(button_info
*b
, button_info
**r_b
)
382 button_info
*tmpb
, *pb
;
386 while(tmpb
->parent
!= NULL
&& !done
)
389 if (tmpb
->flags
.b_Container
)
391 if(tmpb
->c
->flags
.b_Colorset
)
395 else if (!(tmpb
->c
->flags
.b_IconParent
) &&
396 !(tmpb
->c
->flags
.b_ColorsetParent
))
402 else if (tmpb
->flags
.b_Swallow
&& buttonSwallowCount(b
) == 3 &&
403 tmpb
->flags
.b_Colorset
)
407 else if (tmpb
->flags
.b_Colorset
)
411 else if (!tmpb
->flags
.b_IconBack
&& !tmpb
->flags
.b_IconParent
412 && !tmpb
->flags
.b_Swallow
&&
413 !tmpb
->flags
.b_ColorsetParent
)
432 *** Give the swallowing flags for this button
434 byte
buttonSwallow(button_info
*b
)
437 if(b
->flags
.b_Swallow
|| b
->flags
.b_Panel
)
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
;
456 *** Give the justify flags for this button
458 byte
buttonJustify(button_info
*b
)
461 if(b
->flags
.b_Justify
)
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
;
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
)
489 /* needed to prevent a gcc -O3 bug */
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
);
500 while(ub
->c
->allocated_buttons
<=num
)
501 ub
->c
->allocated_buttons
+=32;
503 mymalloc(ub
->c
->allocated_buttons
*sizeof(button_info
*));
504 for(i
=old
;i
<ub
->c
->allocated_buttons
;i
++)
508 for(i
=0;i
<old
;i
++) bb
[i
]=ub
->c
->buttons
[i
];
509 free(ub
->c
->buttons
);
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
)
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
);
531 b
=(button_info
*)mymalloc(sizeof(button_info
));
532 ub
->c
->buttons
[num
]=b
;
534 memset((void *)b
, 0, sizeof(*b
));
536 b
->BWidth
= b
->BHeight
= 1;
537 b
->BPosX
= b
->BPosY
= 0;
551 if(b
->parent
!= NULL
)
553 if (b
->parent
->c
->flags
& b_Colorset
)
554 b
->flags
|= b_ColorsetParent
;
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");
588 b
->c
->back
=safestrdup("rgb:90/80/90");
589 b
->c
->fore
=safestrdup("black");
595 /* -------------------------- button administration ------------------------ */
599 *** Prepare the n fields in each button
601 void NumberButtons(button_info
*b
)
604 while(++i
<b
->c
->num_buttons
)
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
)
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
);
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",
636 fprintf(stderr
,"Button=%d num_rows=%d BPosY=%d\n",
637 i
,c
->num_rows
,b
->BPosY
);
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
);
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
])
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
;
684 *** Frees all but the upper left slot a button uses in it's container.
686 void ShrinkButton(button_info
*b
, container_info
*c
)
692 fprintf(stderr
,"error: shrink1: button is empty but shouldn't\n");
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
++)
703 l
= i
+j
+k
*c
->num_columns
;
704 if (c
->buttons
[l
] != b
)
706 fprintf(stderr
,"error: shrink2: button was stolen\n");
709 c
->buttons
[l
] = NULL
;
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
;
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)
747 if(c
->num_columns
==0)
748 c
->num_columns
=1+(actual_buttons_used
-1)/c
->num_rows
;
750 c
->num_rows
=1+(actual_buttons_used
-1)/c
->num_columns
;
751 while(c
->num_rows
* c
->num_columns
< actual_buttons_used
)
753 if (!c
->flags
.b_SizeFixed
)
755 while(c
->num_rows
*c
->num_columns
>=
756 actual_buttons_used
+ c
->num_columns
)
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
++)
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
++)
790 /* Shuffle subcontainers recursively */
791 if(b
&& b
->flags
.b_Container
)
795 /* Place fixed buttons as given in BPosX and BPosY */
796 for(i
=0;i
<num_items
;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
);
812 /* place floating buttons dynamically */
813 next_button_x
= next_button_y
= 0;
814 for(i
=0;i
<num_items
;i
++)
817 if (b
->flags
.b_PosFixed
) continue;
819 if (next_button_x
+b
->BWidth
>c
->num_columns
)
824 /* Search for next free position to accomodate button */
825 while (PlaceAndExpandButton(next_button_x
,next_button_y
,b
,ub
))
828 if (next_button_x
+b
->BWidth
>c
->num_columns
)
832 if (next_button_y
>=c
->num_rows
)
834 /* could not place button */
835 fprintf(stderr
,"%s: Button confusion! Quitting\n", MyName
);
842 /* shrink buttons in Container */
843 for(i
=0;i
<num_items
;i
++)
844 ShrinkButton(local_buttons
[i
], c
);
848 /* ----------------------------- button iterator --------------------------- */
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 */
861 /* Skip fake buttons */
862 while((*i
)<(*ub
)->c
->num_buttons
&& !(*ub
)->c
->buttons
[*i
])
864 /* End of contained buttons */
865 if((*i
)>=(*ub
)->c
->num_buttons
)
869 /* End of the world as we know it */
876 if((*i
)>=(*ub
)->c
->num_buttons
)
878 fprintf(stderr
,"%s: BUG: Couldn't return to uberbutton\n",MyName
);
881 NextButton(ub
,b
,i
,all
);
884 *b
=(*ub
)->c
->buttons
[*i
];
886 /* Found new container */
887 if((*b
)->flags
.b_Container
)
892 NextButton(ub
,b
,i
,all
);
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
)
909 if(!ub
|| button
<0 || button
>ub
->c
->num_buttons
)
911 if(ub
->c
->buttons
[button
])
913 yy
=button
/ub
->c
->num_columns
;
914 xx
=button
%ub
->c
->num_columns
;
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
;
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
)
938 if (!ub
->flags
.b_Container
)
942 i
= button_belongs_to(ub
, column
+ row
* ub
->c
->num_columns
);
948 return ub
->c
->buttons
[i
];
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
)
962 if (!ub
->flags
.b_Container
)
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)
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
);
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
)
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
);