/* -*-c-*- */ /* FvwmWinList Module for Fvwm. * * Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or * Mike_Finger@atk.com) * * The functions in this source file that are the original work of Mike Finger. * * 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. * * Things to do: Convert to C++ (In Progress) */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include "libs/fvwmlib.h" #include "libs/Colorset.h" #include "libs/Flocale.h" #include "FvwmWinList.h" #include "ButtonArray.h" #include "Mallocs.h" #include "libs/PictureGraphics.h" #include "libs/Rectangles.h" #include "libs/Graphics.h" extern FlocaleFont *FButtonFont; extern FlocaleWinString *FwinString; extern Display *dpy; extern Window win; extern GC shadow[MAX_COLOUR_SETS],hilite[MAX_COLOUR_SETS]; extern GC graph[MAX_COLOUR_SETS],background[MAX_COLOUR_SETS]; extern int colorset[MAX_COLOUR_SETS]; extern Pixmap pixmap[MAX_COLOUR_SETS]; extern int LeftJustify, TruncateLeft, ShowFocus; extern int win_width; extern int win_height; extern long CurrentDesk; extern int ShowCurrentDesk; extern int UseSkipList; /* * Button handling functions and procedures */ /* ButtonNew - Allocates and fills a new button structure */ Button *ButtonNew(char *title, FvwmPicture *p, int up) { Button *new; new = (Button *)safemalloc(sizeof(Button)); memset(new, 0, sizeof(Button)); if (title != NULL) { new->title = safemalloc(strlen(title)+1); strcpy(new->title, title); } if (p != NULL) { new->p.picture = p->picture; new->p.mask = p->mask; new->p.alpha = p->alpha; new->p.width = p->width; new->p.height = p->height; new->p.depth = p->depth; } else { new->p.picture = None; new->p.width = None; } new->up = up; new->next = NULL; new->needsupdate = 1; return new; } /* InitArray - Initialize the arrary of buttons */ void InitArray(ButtonArray *array,int x,int y,int w,int h,int rw) { array->count=0; array->head=array->tail=NULL; array->x=x; array->y=y; array->w=w; array->h=h+2*rw; array->rw=rw; } /* UpdateArray - Update the array width */ void UpdateArray(ButtonArray *array, int w) { Button *temp; if (w >= 0 && array->w != w) { array->w = w; for(temp = array->head; temp != NULL; temp = temp->next) temp->needsupdate = 1; } } /* Reorder buttons in window list order (see List.c:ReorderList() */ void ReorderButtons(ButtonArray *array, int ButNum, int FlipFocus) { Button *temp = array->head, *prev = NULL; int i = 0; if (!ButNum) return; /* this is a NOP if ButNum == 0 */ /* find the item, marking everything from the top as needing update */ while (temp && i != ButNum) { prev = temp; temp->needsupdate = True; temp = temp->next; i++; } if (!temp) return; /* we fell off the list */ /* prev is guaranteed to be !NULL */ if (FlipFocus) { /* take care of the tail of the list */ if (array->tail == temp) array->tail = prev; /* pluck it */ prev->next = temp->next; /* shove it */ temp->next = array->head; array->head = temp; } else { /* close the end */ array->tail->next = array->head; /* rotate around by changing the list pointers */ array->head = temp; array->tail = prev; /* unclose the end */ prev->next = NULL; } /* Focus requires the entire array to be redrawn */ if (!FlipFocus) for (temp = array->head; temp; temp = temp->next) temp->needsupdate = True; } /* AddButton - Allocate space for and add the button to the bottom */ int AddButton(ButtonArray *array, char *title, FvwmPicture *p, int up) { Button *new; new = ButtonNew(title, p, up); if (array->head == NULL) { array->head = array->tail = new; } else { array->tail->next = new; array->tail = new; } array->count++; /* in Taskbar this replaces below ArrangeButtonArray (array);*/ if (title != NULL) { new->tw=FlocaleTextWidth(FButtonFont,title,strlen(title)); } new->truncatewidth=0; new->next=NULL; new->needsupdate=1; new->set=0; new->reliefwidth=array->rw; return (array->count-1); } /* UpdateButton - Change the name/state of a button */ int UpdateButton(ButtonArray *array, int butnum, char *title, int up) { Button *temp; temp=find_n(array,butnum); if (temp!=NULL) { if (title!=NULL) { temp->title=(char *)saferealloc(temp->title,strlen(title)+1); strcpy(temp->title,title); temp->tw=FlocaleTextWidth(FButtonFont,title,strlen(title)); temp->truncatewidth = 0; } if (up!=-1) { temp->up=up; } } else return -1; temp->needsupdate=1; return 1; } /* ------------------------------------------------------------------------- UpdateButtonPicture - Change the picture of a button ------------------------------------------------------------------------- */ int UpdateButtonPicture(ButtonArray *array, int butnum, FvwmPicture *p) { Button *temp; temp=find_n(array,butnum); if (temp == NULL) return -1; if (temp->p.picture != p->picture || temp->p.mask != p->mask) { temp->p.picture = p->picture; temp->p.mask = p->mask; temp->p.alpha = p->alpha; temp->p.width = p->width; temp->p.height = p->height; temp->p.depth = p->depth; temp->needsupdate = 1; } return 1; } void UpdateButtonIconified(ButtonArray *array, int butnum, int iconified) { Button *temp; temp=find_n(array,butnum); if (temp!=NULL) { temp->is_iconified = !!iconified; } return; } /* UpdateButtonSet - Change colour set of a button between odd and even */ int UpdateButtonSet(ButtonArray *array, int butnum, int set) { Button *btn; btn=find_n(array, butnum); if (btn != NULL) { if ((btn->set & 1) != set) { btn->set = (btn->set & 2) | set; btn->needsupdate = 1; } } else return -1; return 1; } /* UpdateButtonDeskFlags - Change desk and flags of a button */ int UpdateButtonDeskFlags(ButtonArray *array, int butnum, long desk, int is_sticky, int skip) { Button *btn; btn = find_n(array, butnum); if (btn != NULL) { btn->desk = desk; btn->is_sticky = is_sticky; btn->skip = skip; } else return -1; return 1; } /* RemoveButton - Delete a button from the list */ void RemoveButton(ButtonArray *array, int butnum) { Button *temp, *to_die; if (butnum == 0) { to_die = array->head; temp = NULL; } else { temp = find_n(array, butnum-1); if (temp == NULL) return; to_die = temp->next; } if ( !to_die ) return; if (array->tail == to_die) array->tail = temp; if ( !temp ) array->head = to_die->next; else temp->next = to_die->next; FreeButton(to_die); array->count--; if (temp && temp != array->head) temp = temp->next; for (; temp!=NULL; temp=temp->next) temp->needsupdate = 1; } /* find_n - Find the nth button in the list (Use internally) */ Button *find_n(ButtonArray *array, int n) { Button *temp; int i; temp=array->head; for(i=0;inext); return temp; } /* FreeButton - Free space allocated to a button */ void FreeButton(Button *ptr) { if (ptr != NULL) { if (ptr->title!=NULL) free(ptr->title); free(ptr); } } /* FreeAllButtons - Free the whole array of buttons */ void FreeAllButtons(ButtonArray *array) { Button *temp,*temp2; for(temp=array->head;temp!=NULL;) { temp2=temp; temp=temp->next; FreeButton(temp2); } } /* DoButton - Draw the specified button. (Used internally) */ void DoButton( Button *button, int x, int y, int w, int h, Bool clear_bg, XEvent *evp) { int up,Fontheight,newx,set,len; GC topgc; GC bottomgc; char *string; XGCValues gcv; unsigned long gcm; FlocaleFont *Ffont; FvwmRenderAttributes fra; XRectangle rect,inter; Region t_region; /* The margin we want between the relief/text/pixmaps */ #define INNER_MARGIN 2 h += 1; if (evp) { if (!frect_get_intersection( x, y, w, h, evp->xexpose.x, evp->xexpose.y, evp->xexpose.width, evp->xexpose.height, &rect)) { return; } } else { rect.x = x; rect.y = y; rect.width = w; rect.height = h; } up=button->up; set=button->set; topgc = up ? hilite[set] : shadow[set]; bottomgc = up ? shadow[set] : hilite[set]; Ffont = FButtonFont; if (Ffont->font != NULL) { gcm = GCFont; gcv.font = Ffont->font->fid; XChangeGC(dpy, graph[set], gcm, &gcv); } Fontheight=FButtonFont->height; if ((FftSupport && Ffont->fftf.fftfont != NULL) || (button->p.picture != 0 && button->p.alpha != 0) || (colorset[set] >= 0 && Colorset[colorset[set]].icon_alpha_percent < 100)) { clear_bg = True; } /* handle transparency by clearing button, otherwise paint with * background */ if (clear_bg) { if (CSET_IS_TRANSPARENT_PR_PURE(colorset[set])) { XClearArea( dpy, win, rect.x, rect.y, rect.width, rect.height, False); } else if (CSET_IS_TRANSPARENT_PR_TINT(colorset[set])) { SetRectangleBackground( dpy, win, rect.x, rect.y, rect.width, rect.height, &Colorset[colorset[set]], Pdepth, background[set]); } else { XFillRectangle( dpy, win, background[set], rect.x, rect.y, rect.width, rect.height); } } if (button->p.picture != 0) { /* clip pixmap to fit inside button */ int height = min(button->p.height, h); int offset = (button->p.height > h) ? 0 : ((h - button->p.height) >> 1); fra.mask = FRAM_DEST_IS_A_WINDOW; if (colorset[set] >= 0) { fra.mask |= FRAM_HAVE_ICON_CSET; fra.colorset = &Colorset[colorset[set]]; } if (frect_get_intersection( rect.x, rect.y, rect.width, rect.height, x + 2 + button->reliefwidth, y+offset, button->p.width, height, &inter)) { PGraphicsRenderPicture( dpy, win, &(button->p), &fra, win, graph[set], None, None, inter.x - (x + 2 + button->reliefwidth), inter.y - (y+offset), inter.width, inter.height, inter.x, inter.y, inter.width, inter.height, False); } newx = button->p.width+2*INNER_MARGIN; } else { if (LeftJustify) { newx = INNER_MARGIN; if (!button->is_iconified) { static int icon_offset = -1; if (icon_offset == -1) icon_offset = FlocaleTextWidth( FButtonFont, "(", 1); newx += icon_offset; } } else { newx = max( (w - button->tw) / 2 - button->reliefwidth, INNER_MARGIN); } } /* check if the string needs to be truncated */ string = button->title; len = strlen(string); if (newx + button->tw + 2 * button->reliefwidth + INNER_MARGIN > w) { if (button -> truncatewidth == w) { /* truncated version already calculated use it */ string = button->truncate_title; len = strlen(string); } else { if (TruncateLeft) { /* move the ptr up until the rest fits */ while (*string && (newx + FlocaleTextWidth( FButtonFont, string, strlen(string)) + 2 * button->reliefwidth + INNER_MARGIN) > w) { string++; len--; } button->truncatewidth = w; button->truncate_title = string; } else { while ((len > 1) && (newx + FlocaleTextWidth( FButtonFont, string, len) + 2 * button->reliefwidth + INNER_MARGIN) > w) { len--; } } } } FwinString->str = string; FwinString->len = len; FwinString->x = x+newx+button->reliefwidth; FwinString->y = y+1+button->reliefwidth+FButtonFont->ascent; FwinString->gc = graph[set]; t_region = XCreateRegion(); XUnionRectWithRegion (&rect, t_region, t_region); FwinString->flags.has_clip_region = True; FwinString->clip_region = t_region; FwinString->flags.has_colorset = False; if (colorset[set] >= 0) { FwinString->colorset = &Colorset[colorset[set]] ; FwinString->flags.has_colorset = True; } FlocaleDrawString(dpy, FButtonFont, FwinString, FWS_HAVE_LENGTH); FwinString->flags.has_clip_region = False; XDestroyRegion(t_region); /* Draw relief last */ RelieveRectangle( dpy,win,x,y,w-1,h-1,topgc,bottomgc,button->reliefwidth); button->needsupdate=0; } /* DrawButtonArray - Draw the whole array (all=1), or only those that need. */ void DrawButtonArray( ButtonArray *barray, Bool all, Bool clear_bg, XEvent *evp) { Button *btn; int i = 0; /* buttons displayed */ for(btn = barray->head; btn != NULL; btn = btn->next) if (IsButtonVisible(btn)) { if (all || btn->needsupdate) DoButton(btn, barray->x, barray->y + (i * (barray->h + 1)), barray->w, barray->h, clear_bg, evp); i++; } } /* Mark all the buttons in the array as dirty */ void DirtyButtonArray(ButtonArray *barray) { Button *btn; for (btn = barray->head; btn != NULL; btn = btn->next) { btn->needsupdate = 1; } return; } /* DrawButtonArray - Draw the whole array (all=1), or only those that need. */ void DrawTransparentButtonArray(ButtonArray *barray) { Button *btn; int i = 0; /* buttons displayed */ for (i = 0; i != MAX_COLOUR_SETS; i++) { int cset = colorset[i]; if (!CSET_IS_TRANSPARENT_ROOT(cset)) { continue; } if (pixmap[i]) XFreePixmap(dpy, pixmap[i]); pixmap[i] = CreateBackgroundPixmap( dpy, win, win_width, win_height, &Colorset[cset], Pdepth, background[i], False); XSetTile(dpy, background[i], pixmap[i]); } i = 0; for(btn = barray->head; btn != NULL; btn = btn->next) { if (IsButtonVisible(btn)) { if (CSET_IS_TRANSPARENT(colorset[btn->set])) { DoButton( btn, barray->x, barray->y + (i * (barray->h + 1)), barray->w, barray->h, True, NULL); } i++; } } } /* SwitchButton - Alternate the state of a button */ void SwitchButton(ButtonArray *array, int butnum) { Button *btn; btn = find_n(array, butnum); if (btn != NULL) { btn->up =!btn->up; btn->needsupdate=1; DrawButtonArray(array, False, True, NULL); } } /* ------------------------------------------------------------------------- RadioButton - Enable button i and verify all others are disabled ------------------------------------------------------------------------- */ void RadioButton(ButtonArray *array, int butnum, int butnumpressed) { Button *temp; int i; for(temp=array->head,i=0; temp!=NULL; temp=temp->next,i++) { if (i == butnum) { if (ShowFocus && temp->up) { temp->up = 0; temp->needsupdate=1; } if (!(temp->set & 2)) { temp->set |= 2; temp->needsupdate=1; } } else if (i == butnumpressed) { if (temp->set & 2) { temp->set &= 1; temp->needsupdate = 1; } } else { if (ShowFocus && !temp->up) { temp->up = 1; temp->needsupdate = 1; } if (temp->set & 2) { temp->set &= 1; temp->needsupdate = 1; } } } } /* WhichButton - Based on x,y which button was pressed */ int WhichButton(ButtonArray *array,int x, int y) { int num; Button *temp; int i, n; num=y/(array->h+1); if (xx || x>array->x+array->w || num<0 || num>array->count-1) num=-1; temp=array->head; for(i=0, n = 0;n < (num + 1) && temp != NULL;temp=temp->next, i++) { if (IsButtonVisible(temp)) n++; } num = i-1; return(num); } /* ButtonName - Return the name of the button */ char *ButtonName(ButtonArray *array, int butnum) { Button *temp; temp=find_n(array,butnum); return temp->title; } /* PrintButtons - Print the array of button names to the console. (Debugging) */ void PrintButtons(ButtonArray *array) { Button *temp; ConsoleMessage("List of Buttons:\n"); for(temp=array->head;temp!=NULL;temp=temp->next) ConsoleMessage(" %s is %s\n",temp->title,(temp->up) ? "Up":"Down"); } /* ButtonPicture - Return the mini icon associated with the button */ FvwmPicture *ButtonPicture(ButtonArray *array, int butnum) { Button *temp; if (!FMiniIconsSupported) { return NULL; } temp=find_n(array,butnum); return &(temp->p); } /* IsButtonVisible - Says if the button should be in winlist */ int IsButtonVisible(Button *btn) { if ((!ShowCurrentDesk || btn->desk == CurrentDesk || btn->is_sticky) && (!btn->skip || !UseSkipList)) return 1; else return 0; } /* IsButtonIndexVisible - Says if the button of index butnum should be in winlist */ int IsButtonIndexVisible(ButtonArray *array, int butnum) { Button *temp; temp=find_n(array,butnum); if (temp == NULL) return 0; if (IsButtonVisible(temp)) return 1; else return 0; } #if 0 /* ButtonArrayMaxWidth - Calculate the width needed for the widest title */ int ButtonArrayMaxWidth(ButtonArray *array) { Button *temp; int x=0; for(temp=array->head;temp!=NULL;temp=temp->next) x=max(temp->tw,x); return x; } #endif