CMD_EwwmhBaseStruts: Use EWMH_UpdateWorkArea() and not separate function calls
[fvwm.git] / modules / FvwmWinList / ButtonArray.c
blob13452fb34455bfad34aeb7f9a301e917923e422b
1 /* -*-c-*- */
2 /* FvwmWinList Module for Fvwm.
4 * Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or
5 * Mike_Finger@atk.com)
7 * The functions in this source file that are the original work of Mike Finger.
9 * No guarantees or warantees or anything are provided or implied in any way
10 * whatsoever. Use this program at your own risk. Permission to use this
11 * program for any purpose is given, as long as the copyright is kept intact.
13 * Things to do: Convert to C++ (In Progress)
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
31 #include "config.h"
33 #include <stdio.h>
34 #include <X11/Xlib.h>
36 #include "libs/fvwmlib.h"
37 #include "libs/Colorset.h"
38 #include "libs/Flocale.h"
40 #include "FvwmWinList.h"
41 #include "ButtonArray.h"
42 #include "Mallocs.h"
43 #include "libs/PictureGraphics.h"
44 #include "libs/Rectangles.h"
45 #include "libs/Graphics.h"
47 extern FlocaleFont *FButtonFont;
48 extern FlocaleWinString *FwinString;
49 extern Display *dpy;
50 extern Window win;
51 extern GC shadow[MAX_COLOUR_SETS],hilite[MAX_COLOUR_SETS];
52 extern GC graph[MAX_COLOUR_SETS],background[MAX_COLOUR_SETS];
53 extern int colorset[MAX_COLOUR_SETS];
54 extern Pixmap pixmap[MAX_COLOUR_SETS];
55 extern int LeftJustify, TruncateLeft, ShowFocus;
56 extern int win_width;
57 extern int win_height;
59 extern long CurrentDesk;
60 extern int ShowCurrentDesk;
61 extern int UseSkipList;
64 * Button handling functions and procedures
68 ButtonNew - Allocates and fills a new button structure
70 Button *ButtonNew(char *title, FvwmPicture *p, int up)
72 Button *new;
74 new = (Button *)safemalloc(sizeof(Button));
75 memset(new, 0, sizeof(Button));
76 if (title != NULL)
78 new->title = safemalloc(strlen(title)+1);
79 strcpy(new->title, title);
81 if (p != NULL)
83 new->p.picture = p->picture;
84 new->p.mask = p->mask;
85 new->p.alpha = p->alpha;
86 new->p.width = p->width;
87 new->p.height = p->height;
88 new->p.depth = p->depth;
89 } else {
90 new->p.picture = None;
91 new->p.width = None;
94 new->up = up;
95 new->next = NULL;
96 new->needsupdate = 1;
98 return new;
102 InitArray - Initialize the arrary of buttons
104 void InitArray(ButtonArray *array,int x,int y,int w,int h,int rw)
106 array->count=0;
107 array->head=array->tail=NULL;
108 array->x=x;
109 array->y=y;
110 array->w=w;
111 array->h=h+2*rw;
112 array->rw=rw;
116 UpdateArray - Update the array width
118 void UpdateArray(ButtonArray *array, int w)
120 Button *temp;
122 if (w >= 0 && array->w != w)
124 array->w = w;
125 for(temp = array->head; temp != NULL; temp = temp->next)
126 temp->needsupdate = 1;
131 Reorder buttons in window list order (see List.c:ReorderList()
133 void ReorderButtons(ButtonArray *array, int ButNum, int FlipFocus)
135 Button *temp = array->head, *prev = NULL;
136 int i = 0;
138 if (!ButNum) return; /* this is a NOP if ButNum == 0 */
139 /* find the item, marking everything from the top as needing update */
140 while (temp && i != ButNum) {
141 prev = temp;
142 temp->needsupdate = True;
143 temp = temp->next;
144 i++;
147 if (!temp) return; /* we fell off the list */
149 /* prev is guaranteed to be !NULL */
150 if (FlipFocus) {
151 /* take care of the tail of the list */
152 if (array->tail == temp) array->tail = prev;
153 /* pluck it */
154 prev->next = temp->next;
155 /* shove it */
156 temp->next = array->head;
157 array->head = temp;
158 } else {
159 /* close the end */
160 array->tail->next = array->head;
161 /* rotate around by changing the list pointers */
162 array->head = temp;
163 array->tail = prev;
164 /* unclose the end */
165 prev->next = NULL;
168 /* Focus requires the entire array to be redrawn */
169 if (!FlipFocus)
170 for (temp = array->head; temp; temp = temp->next)
171 temp->needsupdate = True;
175 AddButton - Allocate space for and add the button to the bottom
177 int AddButton(ButtonArray *array, char *title, FvwmPicture *p, int up)
179 Button *new;
181 new = ButtonNew(title, p, up);
182 if (array->head == NULL)
184 array->head = array->tail = new;
186 else
188 array->tail->next = new;
189 array->tail = new;
191 array->count++;
193 /* in Taskbar this replaces below ArrangeButtonArray (array);*/
194 if (title != NULL)
196 new->tw=FlocaleTextWidth(FButtonFont,title,strlen(title));
198 new->truncatewidth=0;
199 new->next=NULL;
200 new->needsupdate=1;
201 new->set=0;
202 new->reliefwidth=array->rw;
204 return (array->count-1);
208 UpdateButton - Change the name/state of a button
210 int UpdateButton(ButtonArray *array, int butnum, char *title, int up)
212 Button *temp;
214 temp=find_n(array,butnum);
215 if (temp!=NULL)
217 if (title!=NULL)
219 temp->title=(char *)saferealloc(temp->title,strlen(title)+1);
220 strcpy(temp->title,title);
221 temp->tw=FlocaleTextWidth(FButtonFont,title,strlen(title));
222 temp->truncatewidth = 0;
224 if (up!=-1)
226 temp->up=up;
228 } else return -1;
229 temp->needsupdate=1;
230 return 1;
233 /* -------------------------------------------------------------------------
234 UpdateButtonPicture - Change the picture of a button
235 ------------------------------------------------------------------------- */
236 int UpdateButtonPicture(ButtonArray *array, int butnum, FvwmPicture *p)
238 Button *temp;
239 temp=find_n(array,butnum);
240 if (temp == NULL) return -1;
241 if (temp->p.picture != p->picture || temp->p.mask != p->mask)
243 temp->p.picture = p->picture;
244 temp->p.mask = p->mask;
245 temp->p.alpha = p->alpha;
246 temp->p.width = p->width;
247 temp->p.height = p->height;
248 temp->p.depth = p->depth;
249 temp->needsupdate = 1;
251 return 1;
254 void UpdateButtonIconified(ButtonArray *array, int butnum, int iconified)
256 Button *temp;
258 temp=find_n(array,butnum);
259 if (temp!=NULL)
261 temp->is_iconified = !!iconified;
263 return;
268 UpdateButtonSet - Change colour set of a button between odd and even
270 int UpdateButtonSet(ButtonArray *array, int butnum, int set)
272 Button *btn;
274 btn=find_n(array, butnum);
275 if (btn != NULL)
277 if ((btn->set & 1) != set)
279 btn->set = (btn->set & 2) | set;
280 btn->needsupdate = 1;
282 } else return -1;
283 return 1;
287 UpdateButtonDeskFlags - Change desk and flags of a button
289 int UpdateButtonDeskFlags(ButtonArray *array, int butnum, long desk,
290 int is_sticky, int skip)
292 Button *btn;
294 btn = find_n(array, butnum);
295 if (btn != NULL)
297 btn->desk = desk;
298 btn->is_sticky = is_sticky;
299 btn->skip = skip;
300 } else return -1;
301 return 1;
306 RemoveButton - Delete a button from the list
308 void RemoveButton(ButtonArray *array, int butnum)
310 Button *temp, *to_die;
312 if (butnum == 0) {
313 to_die = array->head;
314 temp = NULL;
315 } else {
316 temp = find_n(array, butnum-1);
317 if (temp == NULL) return;
318 to_die = temp->next;
320 if ( !to_die ) return;
322 if (array->tail == to_die)
323 array->tail = temp;
324 if ( !temp )
325 array->head = to_die->next;
326 else
327 temp->next = to_die->next;
329 FreeButton(to_die);
330 array->count--;
331 if (temp && temp != array->head)
332 temp = temp->next;
333 for (; temp!=NULL; temp=temp->next)
334 temp->needsupdate = 1;
338 find_n - Find the nth button in the list (Use internally)
340 Button *find_n(ButtonArray *array, int n)
342 Button *temp;
343 int i;
345 temp=array->head;
346 for(i=0;i<n && temp!=NULL;i++,temp=temp->next);
347 return temp;
351 FreeButton - Free space allocated to a button
353 void FreeButton(Button *ptr)
355 if (ptr != NULL) {
356 if (ptr->title!=NULL) free(ptr->title);
357 free(ptr);
362 FreeAllButtons - Free the whole array of buttons
364 void FreeAllButtons(ButtonArray *array)
366 Button *temp,*temp2;
367 for(temp=array->head;temp!=NULL;)
369 temp2=temp;
370 temp=temp->next;
371 FreeButton(temp2);
376 DoButton - Draw the specified button. (Used internally)
378 void DoButton(
379 Button *button, int x, int y, int w, int h, Bool clear_bg, XEvent *evp)
381 int up,Fontheight,newx,set,len;
382 GC topgc;
383 GC bottomgc;
384 char *string;
385 XGCValues gcv;
386 unsigned long gcm;
387 FlocaleFont *Ffont;
388 FvwmRenderAttributes fra;
389 XRectangle rect,inter;
390 Region t_region;
392 /* The margin we want between the relief/text/pixmaps */
393 #define INNER_MARGIN 2
395 h += 1;
396 if (evp)
398 if (!frect_get_intersection(
399 x, y, w, h,
400 evp->xexpose.x, evp->xexpose.y,
401 evp->xexpose.width, evp->xexpose.height,
402 &rect))
404 return;
407 else
409 rect.x = x;
410 rect.y = y;
411 rect.width = w;
412 rect.height = h;
414 up=button->up;
415 set=button->set;
416 topgc = up ? hilite[set] : shadow[set];
417 bottomgc = up ? shadow[set] : hilite[set];
418 Ffont = FButtonFont;
420 if (Ffont->font != NULL)
422 gcm = GCFont;
423 gcv.font = Ffont->font->fid;
424 XChangeGC(dpy, graph[set], gcm, &gcv);
427 Fontheight=FButtonFont->height;
429 if ((FftSupport && Ffont->fftf.fftfont != NULL) ||
430 (button->p.picture != 0 && button->p.alpha != 0) ||
431 (colorset[set] >= 0 &&
432 Colorset[colorset[set]].icon_alpha_percent < 100))
434 clear_bg = True;
437 /* handle transparency by clearing button, otherwise paint with
438 * background */
439 if (clear_bg)
441 if (CSET_IS_TRANSPARENT_PR_PURE(colorset[set]))
443 XClearArea(
444 dpy, win, rect.x, rect.y, rect.width,
445 rect.height, False);
447 else if (CSET_IS_TRANSPARENT_PR_TINT(colorset[set]))
449 SetRectangleBackground(
450 dpy, win, rect.x, rect.y, rect.width,
451 rect.height, &Colorset[colorset[set]], Pdepth,
452 background[set]);
454 else
456 XFillRectangle(
457 dpy, win, background[set],
458 rect.x, rect.y, rect.width, rect.height);
462 if (button->p.picture != 0)
464 /* clip pixmap to fit inside button */
465 int height = min(button->p.height, h);
466 int offset = (button->p.height > h) ?
467 0 : ((h - button->p.height) >> 1);
469 fra.mask = FRAM_DEST_IS_A_WINDOW;
470 if (colorset[set] >= 0)
472 fra.mask |= FRAM_HAVE_ICON_CSET;
473 fra.colorset = &Colorset[colorset[set]];
475 if (frect_get_intersection(
476 rect.x, rect.y, rect.width, rect.height,
477 x + 2 + button->reliefwidth, y+offset,
478 button->p.width, height, &inter))
480 PGraphicsRenderPicture(
481 dpy, win, &(button->p), &fra,
482 win, graph[set], None, None,
483 inter.x - (x + 2 + button->reliefwidth),
484 inter.y - (y+offset),
485 inter.width, inter.height,
486 inter.x, inter.y, inter.width, inter.height,
487 False);
489 newx = button->p.width+2*INNER_MARGIN;
491 else
493 if (LeftJustify)
495 newx = INNER_MARGIN;
496 if (!button->is_iconified)
498 static int icon_offset = -1;
500 if (icon_offset == -1)
501 icon_offset = FlocaleTextWidth(
502 FButtonFont, "(", 1);
503 newx += icon_offset;
506 else
508 newx = max(
509 (w - button->tw) / 2 - button->reliefwidth,
510 INNER_MARGIN);
513 /* check if the string needs to be truncated */
514 string = button->title;
515 len = strlen(string);
517 if (newx + button->tw + 2 * button->reliefwidth + INNER_MARGIN > w)
519 if (button -> truncatewidth == w)
521 /* truncated version already calculated use it */
522 string = button->truncate_title;
523 len = strlen(string);
525 else
527 if (TruncateLeft)
529 /* move the ptr up until the rest fits */
530 while (*string &&
531 (newx + FlocaleTextWidth(
532 FButtonFont, string,
533 strlen(string))
534 + 2 * button->reliefwidth +
535 INNER_MARGIN) > w)
537 string++;
538 len--;
540 button->truncatewidth = w;
541 button->truncate_title = string;
543 else
545 while ((len > 1) &&
546 (newx + FlocaleTextWidth(
547 FButtonFont, string, len)
548 + 2 * button->reliefwidth +
549 INNER_MARGIN) > w)
551 len--;
556 FwinString->str = string;
557 FwinString->len = len;
558 FwinString->x = x+newx+button->reliefwidth;
559 FwinString->y = y+1+button->reliefwidth+FButtonFont->ascent;
560 FwinString->gc = graph[set];
561 t_region = XCreateRegion();
562 XUnionRectWithRegion (&rect, t_region, t_region);
563 FwinString->flags.has_clip_region = True;
564 FwinString->clip_region = t_region;
565 FwinString->flags.has_colorset = False;
566 if (colorset[set] >= 0)
568 FwinString->colorset = &Colorset[colorset[set]] ;
569 FwinString->flags.has_colorset = True;
571 FlocaleDrawString(dpy, FButtonFont, FwinString, FWS_HAVE_LENGTH);
572 FwinString->flags.has_clip_region = False;
573 XDestroyRegion(t_region);
575 /* Draw relief last */
576 RelieveRectangle(
577 dpy,win,x,y,w-1,h-1,topgc,bottomgc,button->reliefwidth);
579 button->needsupdate=0;
583 DrawButtonArray - Draw the whole array (all=1), or only those that need.
585 void DrawButtonArray(
586 ButtonArray *barray, Bool all, Bool clear_bg, XEvent *evp)
588 Button *btn;
589 int i = 0; /* buttons displayed */
591 for(btn = barray->head; btn != NULL; btn = btn->next)
592 if (IsButtonVisible(btn))
594 if (all || btn->needsupdate)
595 DoButton(btn, barray->x, barray->y + (i * (barray->h + 1)),
596 barray->w, barray->h, clear_bg, evp);
597 i++;
602 Mark all the buttons in the array as dirty
604 void DirtyButtonArray(ButtonArray *barray)
606 Button *btn;
608 for (btn = barray->head; btn != NULL; btn = btn->next)
610 btn->needsupdate = 1;
613 return;
617 DrawButtonArray - Draw the whole array (all=1), or only those that need.
619 void DrawTransparentButtonArray(ButtonArray *barray)
621 Button *btn;
622 int i = 0; /* buttons displayed */
624 for (i = 0; i != MAX_COLOUR_SETS; i++)
626 int cset = colorset[i];
628 if (!CSET_IS_TRANSPARENT_ROOT(cset))
630 continue;
632 if (pixmap[i])
633 XFreePixmap(dpy, pixmap[i]);
634 pixmap[i] = CreateBackgroundPixmap(
635 dpy, win, win_width, win_height,
636 &Colorset[cset], Pdepth,
637 background[i], False);
638 XSetTile(dpy, background[i], pixmap[i]);
641 i = 0;
642 for(btn = barray->head; btn != NULL; btn = btn->next)
644 if (IsButtonVisible(btn))
646 if (CSET_IS_TRANSPARENT(colorset[btn->set]))
648 DoButton(
649 btn, barray->x,
650 barray->y + (i * (barray->h + 1)),
651 barray->w, barray->h, True, NULL);
653 i++;
658 SwitchButton - Alternate the state of a button
660 void SwitchButton(ButtonArray *array, int butnum)
662 Button *btn;
664 btn = find_n(array, butnum);
665 if (btn != NULL)
667 btn->up =!btn->up;
668 btn->needsupdate=1;
669 DrawButtonArray(array, False, True, NULL);
673 /* -------------------------------------------------------------------------
674 RadioButton - Enable button i and verify all others are disabled
675 ------------------------------------------------------------------------- */
676 void RadioButton(ButtonArray *array, int butnum, int butnumpressed)
678 Button *temp;
679 int i;
681 for(temp=array->head,i=0; temp!=NULL; temp=temp->next,i++)
683 if (i == butnum)
685 if (ShowFocus && temp->up)
687 temp->up = 0;
688 temp->needsupdate=1;
690 if (!(temp->set & 2))
692 temp->set |= 2;
693 temp->needsupdate=1;
696 else if (i == butnumpressed)
698 if (temp->set & 2)
700 temp->set &= 1;
701 temp->needsupdate = 1;
704 else
706 if (ShowFocus && !temp->up)
708 temp->up = 1;
709 temp->needsupdate = 1;
711 if (temp->set & 2)
713 temp->set &= 1;
714 temp->needsupdate = 1;
721 WhichButton - Based on x,y which button was pressed
723 int WhichButton(ButtonArray *array,int x, int y)
725 int num;
726 Button *temp;
727 int i, n;
729 num=y/(array->h+1);
730 if (x<array->x || x>array->x+array->w || num<0 || num>array->count-1) num=-1;
732 temp=array->head;
733 for(i=0, n = 0;n < (num + 1) && temp != NULL;temp=temp->next, i++)
735 if (IsButtonVisible(temp))
736 n++;
738 num = i-1;
740 return(num);
744 ButtonName - Return the name of the button
746 char *ButtonName(ButtonArray *array, int butnum)
748 Button *temp;
750 temp=find_n(array,butnum);
751 return temp->title;
755 PrintButtons - Print the array of button names to the console. (Debugging)
757 void PrintButtons(ButtonArray *array)
759 Button *temp;
761 ConsoleMessage("List of Buttons:\n");
762 for(temp=array->head;temp!=NULL;temp=temp->next)
763 ConsoleMessage(" %s is %s\n",temp->title,(temp->up) ? "Up":"Down");
767 ButtonPicture - Return the mini icon associated with the button
769 FvwmPicture *ButtonPicture(ButtonArray *array, int butnum)
771 Button *temp;
773 if (!FMiniIconsSupported)
775 return NULL;
777 temp=find_n(array,butnum);
778 return &(temp->p);
782 IsButtonVisible - Says if the button should be in winlist
784 int IsButtonVisible(Button *btn)
787 if ((!ShowCurrentDesk || btn->desk == CurrentDesk || btn->is_sticky) &&
788 (!btn->skip || !UseSkipList))
789 return 1;
790 else
791 return 0;
795 IsButtonIndexVisible - Says if the button of index butnum should be
796 in winlist
798 int IsButtonIndexVisible(ButtonArray *array, int butnum)
800 Button *temp;
802 temp=find_n(array,butnum);
803 if (temp == NULL) return 0;
804 if (IsButtonVisible(temp))
805 return 1;
806 else
807 return 0;
810 #if 0
812 ButtonArrayMaxWidth - Calculate the width needed for the widest title
814 int ButtonArrayMaxWidth(ButtonArray *array)
816 Button *temp;
817 int x=0;
818 for(temp=array->head;temp!=NULL;temp=temp->next)
819 x=max(temp->tw,x);
820 return x;
822 #endif