/* FvwmButtons v2.0.41-plural-Z-alpha, copyright 1996, Jarl Totland * This module, and the entire GoodStuff program, and the concept for * interfacing this module to the Window Manager, are all original work * by Robert Nation * * Copyright 1993, Robert Nation. No guarantees or warantees or anything * are provided or implied in any way whatsoever. Use this program at your * own risk. Permission to use this program for any purpose is given, * as long as the copyright is kept intact. */ #include #include #include #include #include #include "FvwmButtons.h" extern char *MyName; /** *** buttonInfo() *** Give lots of info for this button: XPos, YPos, XPad, YPad, Frame(signed) **/ void buttonInfo(button_info *b,int *x,int *y,int *px,int *py,int *f) { ushort w=b_Padding|b_Frame; *x=buttonXPos(b,b->n); *y=buttonYPos(b,b->n); *px=b->xpad; *py=b->ypad; *f=b->framew; w&=~(b->flags&(b_Frame|b_Padding)); if(b->flags&b_Container && w&b_Frame) { *f=0; w&=~b_Frame; } if((b->flags&b_Container || b->flags&b_Swallow) && w&b_Padding) { *px=*py=0; w&=~b_Padding; } while(w && (b=b->parent)) { if(w&b_Frame && b->c->flags&b_Frame) { *f=b->c->framew; w&=~b_Frame; } if(w&b_Padding && b->c->flags&b_Padding) { *px=b->c->xpad; *py=b->c->ypad; w&=~b_Padding; } } } /** *** GetInternalSize() **/ void GetInternalSize(button_info *b,int *x,int *y,int *w,int *h) { int f; int px,py; buttonInfo(b,x,y,&px,&py,&f); f=abs(f); *w=buttonWidth(b)-2*(px+f); *h=buttonHeight(b)-2*(py+f); *x+=f+px; *y+=f+py; if(*w<=1 || *h<=1) *w=*h=1; } /** *** buttonFrameSigned() *** Give the signed framewidth for this button. **/ int buttonFrameSigned(button_info *b) { if(b->flags&b_Frame) return b->framew; if(b->flags&b_Container) /* Containers usually gets 0 relief */ return 0; while((b=b->parent)) if(b->c->flags&b_Frame) return b->c->framew; #ifdef DEBUG fprintf(stderr,"%s: BUG: No relief width definition?\n",MyName); #endif return 0; } /** *** buttonXPad() *** Give the x padding for this button **/ int buttonXPad(button_info *b) { if(b->flags&b_Padding) return b->xpad; if(b->flags&(b_Container|b_Swallow)) /* Normally no padding for these */ return 0; while((b=b->parent)) if(b->c->flags&b_Padding) return b->c->xpad; #ifdef DEBUG fprintf(stderr,"%s: BUG: No padding definition?\n",MyName); #endif return 0; } /** *** buttonYPad() *** Give the y padding for this button **/ int buttonYPad(button_info *b) { if(b->flags&b_Padding) return b->ypad; if(b->flags&(b_Container|b_Swallow)) /* Normally no padding for these */ return 0; while((b=b->parent)) if(b->c->flags&b_Padding) return b->c->ypad; #ifdef DEBUG fprintf(stderr,"%s: BUG: No padding definition?\n",MyName); #endif return 0; } /** *** buttonFont() *** Give the font pointer for this button **/ XFontStruct *buttonFont(button_info *b) { if(b->flags&b_Font) return b->font; while((b=b->parent)) if(b->c->flags&b_Font) return b->c->font; #ifdef DEBUG fprintf(stderr,"%s: BUG: No font definition?\n",MyName); #endif return None; } /** *** buttonFore() *** Give the foreground pixel of this button **/ Pixel buttonFore(button_info *b) { if(b->flags&b_Fore) return b->fc; while((b=b->parent)) if(b->c->flags&b_Fore) return b->c->fc; #ifdef DEBUG fprintf(stderr,"%s: BUG: No foreground definition?\n",MyName); #endif return None; } /** *** buttonBack() *** Give the background pixel of this button **/ Pixel buttonBack(button_info *b) { if(b->flags&b_Back) return b->bc; while((b=b->parent)) if(b->c->flags&b_Back) return b->c->bc; #ifdef DEBUG fprintf(stderr,"%s: BUG: No background definition?\n",MyName); #endif return None; } /** *** buttonHilite() *** Give the relief pixel of this button **/ Pixel buttonHilite(button_info *b) { if(b->flags&b_Back) return b->hc; while((b=b->parent)) if(b->c->flags&b_Back) return b->c->hc; #ifdef DEBUG fprintf(stderr,"%s: BUG: No background definition?\n",MyName); #endif return None; } /** *** buttonShadow() *** Give the shadow pixel of this button **/ Pixel buttonShadow(button_info *b) { if(b->flags&b_Back) return b->sc; while((b=b->parent)) if(b->c->flags&b_Back) return b->c->sc; #ifdef DEBUG fprintf(stderr,"%s: BUG: No background definition?\n",MyName); #endif return None; } /** *** buttonSwallow() *** Give the swallowing flags for this button **/ byte buttonSwallow(button_info *b) { byte s=0,t=0; if(b->flags&b_Swallow) { s=b->swallow; t=b->swallow_mask; } while((b=b->parent)) if(b->c->flags&b_Swallow) { s&=~(b->c->swallow_mask&~t); s|=(b->c->swallow&b->c->swallow_mask&~t); t|=b->c->swallow_mask; } return s; } /** *** buttonJustify() *** Give the justify flags for this button **/ byte buttonJustify(button_info *b) { byte j=1,i=0; if(b->flags&b_Justify) { i=b->justify_mask; j=b->justify; } while((b=b->parent)) if(b->c->flags&b_Justify) { j&=~(b->c->justify_mask&~i); j|=(b->c->justify&b->c->justify_mask&~i); i|=b->c->justify_mask; } return j; } /* ---------------------------- button creation ---------------------------- */ /** *** alloc_buttonlist() *** Makes sure the list of butten_info's is long enough, if not it reallocates *** a longer one. This happens in steps of 32. Inital length is 0. **/ void alloc_buttonlist(button_info *ub,int num) { button_info **bb; int i,old; if(num>=ub->c->allocated_buttons) { old=ub->c->allocated_buttons; if(numc->allocated_buttons<=num) ub->c->allocated_buttons+=32; bb=(button_info**) mymalloc(ub->c->allocated_buttons*sizeof(button_info*)); for(i=old;ic->allocated_buttons;i++) bb[i]=NULL; if(ub->c->buttons) { for(i=0;ic->buttons[i]; free(ub->c->buttons); } ub->c->buttons=bb; } } /** *** alloc_button() *** Allocates memory for a new button struct. Calles alloc_buttonlist to *** assure enough space is present. Also initiates most elements of the struct. **/ button_info *alloc_button(button_info *ub,int num) { button_info *b; if(num>=ub->c->allocated_buttons) alloc_buttonlist(ub,num); if(ub->c->buttons[num]) { fprintf(stderr,"%s: Allocated button twice, report bug twice\n",MyName); exit(2); } b=(button_info*)mymalloc(sizeof(button_info)); ub->c->buttons[num]=b; b->flags = 0; b->swallow = 0; b->BWidth = b->BHeight = 1; b->parent = ub; b->n = -1; b->framew = 1; b->xpad = 2; b->ypad = 4; b->w=1; b->h=1; b->bw=1; return(b); } /** *** MakeContainer() *** Allocs and sets the container-specific fields of a button. **/ void MakeContainer(button_info *b) { b->c=(container_info*)mymalloc(sizeof(container_info)); b->flags|=b_Container; b->c->buttons=NULL; b->c->num_buttons=0; b->c->num_rows=0; b->c->num_columns=0; b->c->allocated_buttons=0; b->c->xpos=0; b->c->ypos=0; if(b->parent != NULL) b->c->flags=0; else /* This applies to the UberButton */ { b->c->flags=b_Font|b_Padding|b_Frame|b_Back|b_Fore; b->c->font_string=strdup("fixed"); b->c->xpad=2; b->c->ypad=4; b->c->back=strdup("#908090"); b->c->fore=strdup("black"); b->c->framew=2; } } /* -------------------------- button administration ------------------------ */ /** *** NumberButtons() *** Prepare the n fields in each button **/ void NumberButtons(button_info *b) { int i=-1; while(++ic->num_buttons) if(b->c->buttons[i]) { b->c->buttons[i]->n=i; if(b->c->buttons[i]->flags&b_Container) NumberButtons(b->c->buttons[i]); } } /** *** ShuffleButtons() *** Orders and sizes the buttons in the UberButton, corrects num_rows and *** num_columns in containers. **/ void ShuffleButtons(button_info *ub) { int i,j,k,tb,sb; int actual_buttons_used,first_avail_button; button_info *b; container_info *c=ub->c; /* Allow for multi-width/height buttons */ actual_buttons_used = 0; for(i=0;inum_buttons;i++) actual_buttons_used+=c->buttons[i]->BWidth*c->buttons[i]->BHeight; first_avail_button = c->num_buttons; alloc_buttonlist(ub,actual_buttons_used); c->num_buttons=actual_buttons_used; /* Size and create the window */ if(c->num_rows==0 && c->num_columns==0) c->num_rows=2; if(c->num_columns==0) c->num_columns=1+(c->num_buttons-1)/c->num_rows; if(c->num_rows==0) c->num_rows=1+(c->num_buttons-1)/c->num_columns; while(c->num_rows * c->num_columns < c->num_buttons) c->num_columns++; while(c->num_rows * c->num_columns >= c->num_buttons + c->num_columns) c->num_rows--; for(i=0;inum_buttons;i++) { b=c->buttons[i]; /* Shuffle subcontainers recursively */ if(b && b->flags&b_Container) ShuffleButtons(b); if(b && (b->BHeight>1 || b->BWidth>1)) { /* If not enough room underneath, give up */ if((c->num_rows - (i/c->num_columns)) < b->BHeight) { fprintf(stderr,"%s: Button too tall. Giving up\n",MyName); fprintf(stderr,"Button=%d num_rows=%d bheight=%d h=%d\n", i,c->num_rows,b->BHeight, c->num_rows-(i/c->num_columns)); b->BHeight=c->num_rows-(i/c->num_columns); } if((c->num_columns - (i%c->num_columns)) < b->BWidth) { fprintf(stderr,"%s: Button too wide. Giving up.\n",MyName); fprintf(stderr,"Button=%d num_columns=%d bwidth=%d w=%d\n", i,c->num_columns,b->BWidth, c->num_columns-(i%c->num_rows)); b->BWidth=c->num_columns-(i%c->num_rows); } for(k=0;kBHeight;k++) for(j=0;jBWidth;j++) { if((j>0)||(k>0)) { /* Is there a button in the way for our UberButton? */ if(c->buttons[i+j+k*c->num_columns]) { first_avail_button = i+j+k*c->num_columns+1; /* Find first button not in use, not already claimed, and not be the one we want to swap it with */ while((first_avail_buttonnum_buttons)&& (first_avail_button == i+j+k*c->num_columns|| c->buttons[first_avail_button]|| (button_belongs_to(ub,first_avail_button)<=i && button_belongs_to(ub,first_avail_button)!=-1))) first_avail_button++; if(first_avail_button >= c->num_buttons) { fprintf(stderr,"%s: Button confusion! Quitting\n", MyName); exit(1); } /* The patched swapping here was done by palme@elphy.irz.hu-berlin.de */ /* Slide the offending buttons nearer the end */ tb=first_avail_button; sb=tb-1; while(sb>=i+j+k*c->num_columns) { /* Skip buttons which belongs to UberButtons */ while(!c->buttons[sb]) sb--; c->buttons[tb--]=c->buttons[sb--]; while(!c->buttons[tb]) tb--; } c->buttons[i+j+k*c->num_columns]=NULL; } } } } } } /* ----------------------------- button iterator --------------------------- */ /** *** NextButton() *** Iterator to traverse buttontree. Start it with first argument a pointer *** to the root UberButton, and the index int set to -1. Each subsequent call *** gives the pointer to uberbutton, button and button index within uberbutton. *** If all, also returns containers, apart from the UberButton. **/ button_info *NextButton(button_info **ub,button_info **b,int *i,int all) { /* Get next button */ (*i)++; /* Skip fake buttons */ while((*i)<(*ub)->c->num_buttons && !(*ub)->c->buttons[*i]) (*i)++; /* End of contained buttons */ if((*i)>=(*ub)->c->num_buttons) { *b=*ub; *ub=(*b)->parent; /* End of the world as we know it */ if(!(*ub)) { *b=NULL; return *b; } *i=(*b)->n; if((*i)>=(*ub)->c->num_buttons) { fprintf(stderr,"%s: BUG: Couldn't return to uberbutton\n",MyName); exit(2); } NextButton(ub,b,i,all); return *b; } *b=(*ub)->c->buttons[*i]; /* Found new container */ if((*b)->flags & b_Container) { *i=-1; *ub=*b; if(!all) NextButton(ub,b,i,all); return *b; } return *b; } /* --------------------------- button navigation --------------------------- */ /** *** button_belongs_to() *** Function that finds out which button a given position belongs to. *** Returns -1 is not part of any, button if a proper button. **/ int button_belongs_to(button_info *ub,int button) { int x,y,xx,yy; button_info *b; if(!ub || button<0 || button>ub->c->num_buttons) return -1; if(ub->c->buttons[button]) return button; yy=button/ub->c->num_columns; xx=button%ub->c->num_columns; for(y=yy;y>=0;y--) for(x=xx;x>=0;x--) { b=ub->c->buttons[x+y*ub->c->num_columns]; if(b && (x+b->BWidth > xx) && (y+b->BHeight > yy)) { return x+y*ub->c->num_columns; } } return -1; } /** *** select_button() *** Given (x,y) and uberbutton, returns pointer to referred button, or NULL **/ button_info *select_button(button_info *ub,int x,int y) { int i; button_info *b; if(!(ub->flags&b_Container)) return ub; x-=buttonXPad(ub)+buttonFrame(ub); y-=buttonYPad(ub)+buttonFrame(ub); if(x >= ub->c->ButtonWidth * ub->c->num_columns || x<0 || y >= ub->c->ButtonHeight * ub->c->num_rows || y<0) return ub; i=x/ub->c->ButtonWidth + (y/ub->c->ButtonHeight)*ub->c->num_columns; i=button_belongs_to(ub,i); if(i==-1)return ub; b=ub->c->buttons[i]; return select_button(b,x-(i%ub->c->num_columns)*ub->c->ButtonWidth, y-(i/ub->c->num_columns)*ub->c->ButtonHeight); }