/* 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; memset((void *)b, 0, sizeof(*b)); b->flags = 0; b->swallow = 0; b->BWidth = b->BHeight = 1; b->BPosX = b->BPosY = 0; b->parent = ub; b->n = -1; b->IconWin = 0; 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) { if (b->parent->c->flags&b_IconBack || b->parent->c->flags&b_IconParent) b->c->flags=b_IconParent; else 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]); } } /** *** PlaceAndExpandButton() *** Places a button in it's container and claims all needed slots. **/ char PlaceAndExpandButton(int x, int y, button_info *b, button_info *ub) { int i,j,k; container_info *c=ub->c; i = x+y*c->num_columns; if (x>=c->num_columns || x<0) { fprintf(stderr,"%s: Button out of horizontal range. Quitting.\n",MyName); fprintf(stderr,"Button=%d num_columns=%d BPosX=%d\n", i,c->num_columns,b->BPosX); exit(1); } if (y>=c->num_rows || y<0) { if (b->flags&b_PosFixed || !(ub->c->flags&b_SizeSmart) || y<0) { fprintf(stderr,"%s: Button out of vertical range. Quitting.\n", MyName); fprintf(stderr,"Button=%d num_rows=%d BPosY=%d\n", i,c->num_rows,b->BPosY); exit(1); } c->num_rows=y+b->BHeight; c->num_buttons=c->num_columns*c->num_rows; alloc_buttonlist(ub,c->num_buttons); } if(x+b->BWidth>c->num_columns) { 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,x); b->BWidth = c->num_columns-x; } if(y+b->BHeight>c->num_rows) { if (c->flags&b_SizeSmart) { c->num_rows=y+b->BHeight; c->num_buttons=c->num_columns*c->num_rows; alloc_buttonlist(ub,c->num_buttons); } else { 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,y); b->BHeight = c->num_rows-y; } } /* check if buttons are free */ for(k=0;kBHeight;k++) for(j=0;jBWidth;j++) if (c->buttons[i+j+k*c->num_columns]) return 1; /* claim all buttons */ for(k=0;kBHeight;k++) for(j=0;jBWidth;j++) c->buttons[i+j+k*c->num_columns] = b; b->BPosX = x; b->BPosY = y; return 0; } /** *** ShrinkButton() *** Frees all but the upper left slot a button uses in it's container. **/ void ShrinkButton(button_info *b, container_info *c) { int i,j,k,l; if (!b) { fprintf(stderr,"error: shrink1: button is empty but shouldn't\n"); exit(1); } i = b->BPosX+b->BPosY*c->num_columns; /* free all buttons but the upper left corner */ for(k=0;kBHeight;k++) for(j=0;jBWidth;j++) if(j||k) { l = i+j+k*c->num_columns; if (c->buttons[l] != b) { fprintf(stderr,"error: shrink2: button was stolen\n"); exit(1); } c->buttons[l] = NULL; } } /** *** ShuffleButtons() *** Orders and sizes the buttons in the UberButton, corrects num_rows and *** num_columns in containers. **/ void ShuffleButtons(button_info *ub) { int i,actual_buttons_used; int next_button_x, next_button_y, num_items; button_info *b; button_info **local_buttons; container_info *c=ub->c; /* make local copy of buttons in ub */ num_items = c->num_buttons; local_buttons=(button_info**)mymalloc(sizeof(button_info)*num_items); for(i=0;ibuttons[i]; c->buttons[i] = NULL; } /* Allow for multi-width/height buttons */ actual_buttons_used = 0; for(i=0;iBWidth*local_buttons[i]->BHeight; if (!(c->flags&b_SizeFixed)||!(c->num_rows)||!(c->num_columns)) { /* 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+(actual_buttons_used-1)/c->num_rows; if(c->num_rows==0) c->num_rows=1+(actual_buttons_used-1)/c->num_columns; while(c->num_rows * c->num_columns < actual_buttons_used) c->num_columns++; if (!(c->flags&b_SizeFixed)) { while(c->num_rows*c->num_columns >= actual_buttons_used + c->num_columns) c->num_rows--; } } if (c->flags&b_SizeSmart) { /* Set rows/columns to at least the height/width of largest button */ for(i=0;inum_rowsBHeight) c->num_rows=b->BHeight; if (c->num_columnsBWidth) c->num_columns=b->BWidth; if (b->flags&b_PosFixed && c->num_columnsBWidth+b->BPosX) c->num_columns=b->BWidth+b->BPosX; if (b->flags&b_PosFixed && c->num_columnsBWidth-b->BPosX) c->num_columns=b->BWidth-b->BPosX; if (b->flags&b_PosFixed && c->num_rowsBHeight+b->BPosY) c->num_rows=b->BHeight+b->BPosY; if (b->flags&b_PosFixed && c->num_rowsBHeight-b->BPosY) c->num_rows=b->BHeight-b->BPosY; } } /* this was buggy before */ c->num_buttons = c->num_rows*c->num_columns; alloc_buttonlist(ub,c->num_buttons); /* Shuffle subcontainers */ for(i=0;iflags&b_Container) ShuffleButtons(b); } /* Place fixed buttons as given in BPosX and BPosY */ for(i=0;iflags&b_PosFixed)) continue; /* recalculate position for negative offsets */ if (b->BPosX<0) b->BPosX=b->BPosX+c->num_columns-b->BWidth+1; if (b->BPosY<0) b->BPosY=b->BPosY+c->num_rows-b->BHeight+1; /* Move button if position given by user */ if (PlaceAndExpandButton(b->BPosX,b->BPosY,b,ub)) { fprintf(stderr, "%s: Overlapping fixed buttons. Quitting.\n",MyName); fprintf(stderr, "Button=%d, x=%d, y=%d\n", i,b->BPosX,b->BPosY); exit(1); } } /* place floating buttons dynamically */ next_button_x = next_button_y = 0; for(i=0;iflags&b_PosFixed) continue; if (next_button_x+b->BWidth>c->num_columns) { next_button_y++; next_button_x=0; } /* Search for next free position to accomodate button */ while (PlaceAndExpandButton(next_button_x,next_button_y,b,ub)) { next_button_x++; if (next_button_x+b->BWidth>c->num_columns) { next_button_y++; next_button_x=0; if (next_button_y>=c->num_rows) { /* could not place button */ fprintf(stderr,"%s: Button confusion! Quitting\n", MyName); exit(1); } } } } /* shrink buttons in Container */ for(i=0;ic->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); }