/* -*-c-*- */
/* FvwmTaskBar Module for Fvwm.
*
* Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or
* Mike_Finger@atk.com)
* Copyright 1995, Pekka Pietik{inen (pp@netppl.fi)
*
* The functions in this source file that are the original work of Mike Finger.
* This source file has been modified for use with fvwm95look by
* Pekka Pietik{inen, David Barth, Hector Peraza, etc, etc...
*
* 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.
*
*/
/* 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 <stdio.h>
#include <X11/Xlib.h>
#include "libs/fvwmlib.h"
#include "libs/Colorset.h"
#include "libs/Flocale.h"
#include "libs/Picture.h"
#include "libs/PictureGraphics.h"
#include "libs/Rectangles.h"
#include "ButtonArray.h"
#include "Mallocs.h"
extern FlocaleFont *FButtonFont, *FSelButtonFont;
extern Display *dpy;
extern Window win;
extern GC shadow, hilite, graph, whitegc, blackgc, checkered, icongraph,
iconhilite, iconshadow, focusgraph, focushilite, focusshadow;
extern GC iconbackgraph;
extern GC focusbackgraph;
extern FlocaleWinString *FwinString;
extern int pad;
extern int button_width;
extern int iconcolorset;
extern int focuscolorset;
extern int colorset;
extern int NoBrightFocus;
extern int ThreeDfvwm;
extern char *FocusBackColor;
extern Button *StartButton;
int w3p; /* width of the string "..." in pixels */
extern int NRows, RowHeight;
#define MIN_BUTTON_SIZE 32 /*....*/
/*
* Button handling functions and procedures
*/
/* Draws a 3D rectangle */
void Draw3dRect(
Window wn, int x, int y, int w, int h, XRectangle *bounding,
int state, Bool iconified)
{
colorset_t *cset = &Colorset[0]; /* initialize to avoid warning */
int d = 1;
XRectangle r,inter;
Bool draw;
if (ThreeDfvwm)
{
d = 2;
}
if (bounding)
{
r.x = bounding->x;
r.y = bounding->y;
r.width = bounding->width;
r.height = bounding->height;
}
else
{
r.x = x;
r.y = y;
r.width = w;
r.height = h;
}
XClearArea (dpy, wn, r.x, r.y, r.width, r.height, False);
if (iconified)
{
draw = frect_get_intersection(
x + d, y + d, w - 3, h - 3,
r.x, r.y, r.width, r.height, &inter);
if (iconcolorset >= 0)
{
cset = &Colorset[iconcolorset];
}
if (iconcolorset >= 0 && (cset->pixmap || cset->shape_mask)
&& draw)
{
/* we have a colorset background */
SetClippedRectangleBackground(
dpy, win, x + d, y + d, w - 3, h - 3, &inter,
cset, Pdepth, icongraph);
}
else if (draw)
{
XFillRectangle (
dpy, wn, iconbackgraph,
inter.x, inter.y, inter.width, inter.height);
}
XDrawLine (dpy, wn, iconhilite, x, y, x+w-2, y);
XDrawLine (dpy, wn, iconhilite, x, y, x, y+h-2);
if (ThreeDfvwm)
{
XDrawLine (dpy, wn, iconhilite, x, y+1, x+w-2, y+1);
XDrawLine (dpy, wn, iconhilite, x+1, y, x+1, y+h-2);
}
XDrawLine (dpy, wn, iconshadow, x+1, y+h-2, x+w-2, y+h-2);
XDrawLine (dpy, wn, iconshadow, x+w-2, y+h-2, x+w-2, y+1);
XDrawLine (dpy, wn, blackgc, x, y+h-1, x+w-1, y+h-1);
XDrawLine (dpy, wn, blackgc, x+w-1, y+h-1, x+w-1, y);
return;
}
switch (state)
{
case BUTTON_UP:
XDrawLine (dpy, wn, hilite, x, y, x+w-2, y);
XDrawLine (dpy, wn, hilite, x, y, x, y+h-2);
if (ThreeDfvwm)
{
XDrawLine (dpy, wn, hilite, x, y+1, x+w-2, y+1);
XDrawLine (dpy, wn, hilite, x+1, y, x+1, y+h-2);
}
XDrawLine (dpy, wn, shadow, x+1, y+h-2, x+w-2, y+h-2);
XDrawLine (dpy, wn, shadow, x+w-2, y+h-2, x+w-2, y+1);
XDrawLine (dpy, wn, blackgc, x, y+h-1, x+w-1, y+h-1);
XDrawLine (dpy, wn, blackgc, x+w-1, y+h-1, x+w-1, y);
break;
case BUTTON_BRIGHT:
draw = frect_get_intersection(
x + 2, y + 2, w - 4 + (2 - d), h - 4 + (2 - d),
r.x, r.y, r.width, r.height, &inter);
if (focuscolorset >= 0)
cset = &Colorset[focuscolorset];
if (focuscolorset >= 0 && (cset->pixmap || cset->shape_mask) &&
draw)
{
/* we have a colorset background */
SetClippedRectangleBackground(
dpy, win, x + 2, y + 2, w - 4 + (2 - d),
h - 4 + (2 - d), &inter, cset, Pdepth,
focusgraph);
}
else if (draw)
{
XFillRectangle (
dpy, wn, focusbackgraph, inter.x, inter.y,
inter.width, inter.height);
}
if (!NoBrightFocus)
XFillRectangle (
dpy, wn, checkered, inter.x, inter.y,
inter.width, inter.height);
XDrawLine (dpy, wn, blackgc, x, y, x+w-2, y);
XDrawLine (dpy, wn, blackgc, x, y, x, y+h-2);
XDrawLine (dpy, wn, focusshadow, x, y+1, x+w-2, y+1);
XDrawLine (dpy, wn, focusshadow, x+1, y, x+1, y+h-2);
if (ThreeDfvwm)
{
XDrawLine (
dpy, wn, focushilite, x+1, y+h-2, x+w-2, y+h-2);
XDrawLine (
dpy, wn, focushilite, x+w-2, y+h-2, x+w-2, y+1);
}
XDrawLine (dpy, wn, focushilite, x, y+h-1, x+w-1, y+h-1);
XDrawLine (dpy, wn, focushilite, x+w-1, y+h-1, x+w-1, y);
break;
case BUTTON_DOWN:
XDrawLine (dpy, wn, blackgc, x, y, x+w-2, y);
XDrawLine (dpy, wn, blackgc, x, y, x, y+h-2);
XDrawLine (dpy, wn, shadow, x, y+1, x+w-2, y+1);
XDrawLine (dpy, wn, shadow, x+1, y, x+1, y+h-2);
if (ThreeDfvwm)
{
XDrawLine (dpy, wn, hilite, x+1, y+h-2, x+w-2, y+h-2);
XDrawLine (dpy, wn, hilite, x+w-2, y+h-2, x+w-2, y+1);
}
XDrawLine (dpy, wn, hilite, x, y+h-1, x+w-1, y+h-1);
XDrawLine (dpy, wn, hilite, x+w-1, y+h-1, x+w-1, y);
break;
}
}
/* -------------------------------------------------------------------------
ButtonNew - Allocates and fills a new button structure
------------------------------------------------------------------------- */
Button *ButtonNew(const char *title, FvwmPicture *p, int state, int count)
{
Button *new;
if (title == NULL)
return NULL;
new = (Button *)safemalloc(sizeof(Button));
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 = 0;
}
new->state = state;
new->count = count;
new->next = NULL;
new->needsupdate = 1;
new->iconified = 0;
return new;
}
/* -------------------------------------------------------------------------
ButtonDraw - Draws the specified button
------------------------------------------------------------------------- */
void ButtonDraw(Button *button, int x, int y, int w, int h, XEvent *evp)
{
char *t3p = "...\0";
int state, x3p, newx;
int search_len;
FlocaleFont *Ffont;
XGCValues gcv;
unsigned long gcm;
GC *drawgc;
int cs;
XRectangle rect,inter;
Region t_region;
if (w <= 0)
{
w = 1;
}
if (button == NULL)
{
return;
}
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;
}
button->needsupdate = 0;
state = button->state;
Draw3dRect(
win, x, y, w, h, &rect, state, !!(button->iconified));
if (button->iconified)
{
drawgc = &icongraph;
cs = iconcolorset;
}
else if (state == BUTTON_BRIGHT)
{
drawgc = &focusgraph;
cs = focuscolorset;
}
else
{
drawgc = &graph;
cs = colorset;
}
if (state != BUTTON_UP) { x++; y++; }
if (state == BUTTON_BRIGHT || button == StartButton)
{
Ffont = FSelButtonFont;
}
else
{
Ffont = FButtonFont;
}
if (Ffont->font != NULL)
{
gcm = GCFont;
gcv.font = Ffont->font->fid;
XChangeGC(dpy, *drawgc, gcm, &gcv);
}
newx = 4;
w3p = FlocaleTextWidth(Ffont, t3p, 3);
if (button->p.picture != 0)
{
/* clip pixmap to fit inside button */
int pheight = min(button->p.height, h-2);
int offset = (button->p.height > h) ?
0 : ((h - button->p.height) >> 1);
int pwidth = min(button->p.width, w-5);
FvwmRenderAttributes fra;
fra.mask = FRAM_DEST_IS_A_WINDOW;
if (cs >= 0)
{
fra.mask |= FRAM_HAVE_ICON_CSET;
fra.colorset = &Colorset[cs];
}
if (frect_get_intersection(
rect.x, rect.y, rect.width, rect.height,
x+3, y+offset, pwidth, pheight, &inter))
{
PGraphicsRenderPicture(
dpy, win, &(button->p), &fra, win,
*drawgc, None, None,
(inter.x > (x+3))? inter.x - (x+3):0,
(inter.y > (y+offset))? inter.y - (y+offset):0,
inter.width, inter.height,
inter.x /*x+3*/, inter.y /*y+offset*/,
inter.width, inter.height, False);
}
newx += pwidth+2;
}
if (button->title == NULL)
{
return;
}
t_region = XCreateRegion();
XUnionRectWithRegion (&rect, t_region, t_region);
/* see if we have the place for "...", if not for "..", if not for "."
* if not return */
if ((newx + w3p + 2) >= w)
{
t3p = "..\0";
w3p = FlocaleTextWidth(Ffont, t3p, 2);
if ((newx + w3p + 2) >= w)
{
t3p = ".\0";
w3p = FlocaleTextWidth(Ffont, t3p, 1);
if ((newx + w3p + 2) >= w)
{
XDestroyRegion(t_region);
return;
}
}
}
search_len = strlen(button->title);
FwinString->win = win;
FwinString->y = y + Ffont->ascent + (RowHeight - Ffont->height)/2;
FwinString->gc = *drawgc;
FwinString->flags.has_colorset = False;
FwinString->flags.has_clip_region = True;
FwinString->clip_region = t_region;
if (cs >= 0)
{
FwinString->colorset = &Colorset[cs];
FwinString->flags.has_colorset = True;
}
button->truncate = False;
if (FlocaleTextWidth(Ffont, button->title, search_len) > w-newx-3)
{
x3p = 0;
while (search_len >= 0
&& ((x3p = newx + FlocaleTextWidth(
Ffont, button->title, search_len))
> w-w3p-3))
{
search_len--;
}
FwinString->str = t3p;
FwinString->x = x + x3p;
FlocaleDrawString(dpy, Ffont, FwinString, 0);
button->truncate = True;
}
/* Only print as much of the title as will fit. */
if (search_len)
{
FwinString->str = button->title;
FwinString->x = x + newx;
FwinString->len = search_len;
FlocaleDrawString(dpy, Ffont, FwinString, FWS_HAVE_LENGTH);
}
FwinString->flags.has_clip_region = False;
XDestroyRegion(t_region);
}
/* -------------------------------------------------------------------------
ButtonUpdate - Change the name/state of a button
------------------------------------------------------------------------- */
int ButtonUpdate(Button *button, const char *title, int state)
{
if (button == NULL) return -1;
if ((title != NULL) && (button->title != title)) {
button->title = (char *)saferealloc(button->title,strlen(title)+1);
strcpy(button->title,title);
button->needsupdate = 1;
}
if (state != DONT_CARE) {
if (state != button->state) {
button->state = state;
button->needsupdate = 1;
}
}
return 1;
}
/* -------------------------------------------------------------------------
ButtonDelete - Free space allocated to a button
------------------------------------------------------------------------- */
void ButtonDelete(Button *ptr)
{
if (ptr != NULL) {
if (ptr->title != NULL) free(ptr->title);
free(ptr);
}
}
/* -------------------------------------------------------------------------
ButtonName - Return the name of the button
------------------------------------------------------------------------- */
char *ButtonName(Button *button)
{
if (button == NULL) return NULL;
else return button->title;
}
/*
* ButtonArray handling functions and procedures
*/
/* -------------------------------------------------------------------------
InitArray - Initialize the arrary of buttons
------------------------------------------------------------------------- */
void InitArray(ButtonArray *array, int x, int y, int w, int h, int tw)
{
array->count = 0;
array->head = array->tail = NULL;
array->x = x;
array->y = y;
array->w = w;
array->h = h;
array->tw = tw;
}
/* -------------------------------------------------------------------------
UpdateArray - Update the array specifics. x,y, width, height
------------------------------------------------------------------------- */
void UpdateArray(ButtonArray *array,int x,int y,int w, int h, int tw)
{
Button *temp;
if (x != -1)
array->x = x;
if (y != -1)
array->y = y;
if (w != -1)
array->w = w;
if (h != -1)
array->h = h;
if (tw != -1)
array->tw = tw;
for(temp=array->head; temp!=NULL; temp=temp->next)
temp->needsupdate = 1;
}
/* -------------------------------------------------------------------------
AddButton - Allocate space for and add the button to the list
------------------------------------------------------------------------- */
void AddButton(ButtonArray *array, const char *title, FvwmPicture *p, int state,
int count, int iconified)
{
Button *new, *temp;
new = ButtonNew(title, p, state, count);
if (new == NULL)
return;
if (iconified)
new->iconified = 1;
if (array->head == NULL)
array->head = new;
else
{
for (temp = array->head; temp->next; temp = temp->next)
;
temp->next = new;
}
array->count++;
ArrangeButtonArray(array);
}
/* -------------------------------------------------------------------------
ArrangeButtonArray - Rearrange the button size (called from AddButton,
RemoveButton, AdjustWindow)
------------------------------------------------------------------------- */
void ArrangeButtonArray (ButtonArray *array)
{
int tw;
Button *temp;
if (!array->count)
tw = array->w;
else if (NRows == 1)
tw = array->w / array->count;
else
tw = array->w / ((array->count / NRows)+1);
if (tw > button_width)
tw = button_width;
if (tw < MIN_BUTTON_SIZE)
tw = MIN_BUTTON_SIZE;
if (tw != array->tw) /* update needed */
{
array->tw = tw;
for(temp = array->head; temp != NULL; temp = temp->next)
temp->needsupdate = 1;
}
}
/* -------------------------------------------------------------------------
UpdateButton - Change the name/state of a button
------------------------------------------------------------------------- */
int UpdateButton(ButtonArray *array, int butnum, const char *title, int state)
{
Button *temp;
for (temp = array->head; temp; temp = temp->next)
if (temp->count == butnum)
break;
return ButtonUpdate(temp, title, state);
}
/* -------------------------------------------------------------------------
UpdateButtonPicture - Change the picture of a button
------------------------------------------------------------------------- */
int UpdateButtonPicture(ButtonArray *array, int butnum, FvwmPicture *p)
{
Button *temp;
for (temp=array->head; temp; temp=temp->next)
if (temp->count == butnum)
break;
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;
}
/* -------------------------------------------------------------------------
RemoveButton - Delete a button from the list
------------------------------------------------------------------------- */
void RemoveButton(ButtonArray *array, int butnum)
{
Button *temp, *to_die;
if (array->head == NULL)
return;
if (array->head->count == butnum)
{
to_die = array->head;
array->head = array->head->next;
}
else
{
for (temp = array->head, to_die = array->head->next; to_die != NULL;
to_die = to_die->next, temp = temp->next)
{
if (to_die->count == butnum)
break;
}
if (!to_die)
return;
temp->next = to_die->next;
}
ButtonDelete(to_die);
if (array->count > 0)
array->count--;
for (temp = array->head; temp; temp = temp->next)
temp->needsupdate = 1;
ArrangeButtonArray(array);
}
/* -------------------------------------------------------------------------
find_n - Find the nth button in the list (Use internally)
------------------------------------------------------------------------- */
Button *find_n(ButtonArray *array, int n)
{
Button *temp;
temp = array->head;
if (n < 0)
return NULL;
for ( ; temp && n != temp->count; temp=temp->next)
;
return temp;
}
/* -------------------------------------------------------------------------
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;
ButtonDelete(temp2);
}
array->count = 0;
array->head = NULL;
}
/* ------------------------------------------------------------------------
DrawButtonArray - Draw the whole array (all=1), or only those that need.
------------------------------------------------------------------------ */
void DrawButtonArray(ButtonArray *array, int all, XEvent *evp)
{
Button *temp;
int x, y, n;
static Bool exposed = False;
if (!exposed && evp)
{
exposed = True;
}
if (!exposed)
{
return;
}
x = 0;
y = array->y;
n = 1;
for(temp=array->head; temp!=NULL; temp=temp->next)
{
if ((x + array->tw > array->w) && (n < NRows))
{
x = 0;
y += RowHeight+2;
++n;
}
if (temp->needsupdate || all)
ButtonDraw(
temp, x + array->x, y, array->tw-pad, array->h,
(temp->needsupdate)? NULL:evp);
x += array->tw;
}
}
/* -------------------------------------------------------------------------
RadioButton - Enable button i and verify all others are disabled
------------------------------------------------------------------------- */
void RadioButton(ButtonArray *array, int butnum, int state)
{
Button *button;
for(button=array->head; button!=NULL; button=button->next) {
if (button->count == butnum) {
button->state = state;
button->needsupdate = 1;
} else {
if (button->state != BUTTON_UP) {
button->state = BUTTON_UP;
button->needsupdate = 1;
}
}
}
}
/* -------------------------------------------------------------------------
------------------------------------------------------------------------- */
Bool CheckRootTransparentButtons(ButtonArray *array)
{
Button *button;
Bool r = 0;
if (!CSET_IS_TRANSPARENT_ROOT(iconcolorset) &&
!CSET_IS_TRANSPARENT_ROOT(focuscolorset))
{
return r;
}
for(button=array->head; button!=NULL; button=button->next)
{
if ((button->iconified &&
CSET_IS_TRANSPARENT_ROOT(iconcolorset)) ||
(button->state == BUTTON_BRIGHT &&
CSET_IS_TRANSPARENT_ROOT(focuscolorset)))
{
r = True;
button->needsupdate = 1;
}
}
return r;
}
/* -------------------------------------------------------------------------
WhichButton - Based on x,y which button was pressed
------------------------------------------------------------------------- */
int WhichButton(ButtonArray *array, int xp, int yp)
{
int junkx, junky, junkz;
char *junkt;
return LocateButton(array, xp, yp, &junkx, &junky, &junkt, &junkz);
}
int LocateButton(ButtonArray *array, int xp, int yp, int *xb, int *yb,
char **name, int *trunc)
{
Button *temp;
int num, x, y, n;
if (xp < array->x || xp > array->x+array->w) return -1;
x = 0;
y = array->y;
n = 1;
for(temp=array->head, num=0; temp!=NULL; temp=temp->next, num++) {
if((x + array->tw > array->w) && (n < NRows))
{ x = 0; y += RowHeight+2; ++n; }
if( xp >= x+array->x && xp <= x+array->x+array->tw-3 &&
yp >= y && yp <= y+array->h) break;
x += array->tw;
}
if (num<0 || num>array->count-1) num = -1;
*xb = x+array->x;
*yb = y;
if (temp) {
*name = temp->title;
*trunc = temp->truncate;
} else {
*name = NULL;
}
return (num == -1) ? num : temp->count;
}
/* -------------------------------------------------------------------------
ButtonCoordinates - Compute the coordinates of a button (animation)
------------------------------------------------------------------------- */
extern int StartAndLaunchButtonsWidth;
void ButtonCoordinates(ButtonArray *array, int numbut, int *xc, int *yc)
{
Button *temp;
int x = 0;
int y = 0;
int r = 0;
for(temp=array->head; temp->count != numbut; temp=temp->next)
{
if((x + 2*array->tw > array->w) && (r < NRows))
{
x = 0;
y += RowHeight+2;
++r;
}
else
{
x += array->tw;
}
}
*xc = x+ StartAndLaunchButtonsWidth+3;
*yc = y;
}
void ButtonDimensions(ButtonArray *array, int *width, int *height)
{
*width = array->tw;
*height = RowHeight+2;
}
syntax highlighted by Code2HTML, v. 0.9.1