Cull unused functions when compiling against librplay.
[fvwm.git] / modules / FvwmTaskBar / ButtonArray.c
blob0d7d49c241f76bb2ed02176d3f0435e30b144333
1 /* -*-c-*- */
2 /* FvwmTaskBar Module for Fvwm.
4 * Copyright 1994, Mike Finger (mfinger@mermaid.micro.umn.edu or
5 * Mike_Finger@atk.com)
6 * Copyright 1995, Pekka Pietik{inen (pp@netppl.fi)
8 * The functions in this source file that are the original work of Mike Finger.
9 * This source file has been modified for use with fvwm95look by
10 * Pekka Pietik{inen, David Barth, Hector Peraza, etc, etc...
12 * No guarantees or warantees or anything are provided or implied in any way
13 * whatsoever. Use this program at your own risk. Permission to use this
14 * program for any purpose is given, as long as the copyright is kept intact.
18 /* This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "config.h"
35 #include <stdio.h>
36 #include <X11/Xlib.h>
38 #include "libs/fvwmlib.h"
39 #include "libs/Colorset.h"
40 #include "libs/Flocale.h"
41 #include "libs/Picture.h"
42 #include "libs/PictureGraphics.h"
43 #include "libs/Rectangles.h"
45 #include "ButtonArray.h"
46 #include "Mallocs.h"
48 extern FlocaleFont *FButtonFont, *FSelButtonFont;
49 extern Display *dpy;
50 extern Window win;
51 extern GC shadow, hilite, graph, whitegc, blackgc, checkered, icongraph,
52 iconhilite, iconshadow, focusgraph, focushilite, focusshadow;
53 extern GC iconbackgraph;
54 extern GC focusbackgraph;
55 extern FlocaleWinString *FwinString;
56 extern int pad;
57 extern int button_width;
58 extern int iconcolorset;
59 extern int focuscolorset;
60 extern int colorset;
61 extern int NoBrightFocus;
62 extern int ThreeDfvwm;
63 extern char *FocusBackColor;
64 extern Button *StartButton;
66 int w3p; /* width of the string "..." in pixels */
68 extern int NRows, RowHeight;
70 #define MIN_BUTTON_SIZE 32 /*....*/
73 * Button handling functions and procedures
76 /* Draws a 3D rectangle */
77 void Draw3dRect(
78 Window wn, int x, int y, int w, int h, XRectangle *bounding,
79 int state, Bool iconified)
81 colorset_t *cset = &Colorset[0]; /* initialize to avoid warning */
82 int d = 1;
83 XRectangle r,inter;
84 Bool draw;
86 if (ThreeDfvwm)
88 d = 2;
90 if (bounding)
92 r.x = bounding->x;
93 r.y = bounding->y;
94 r.width = bounding->width;
95 r.height = bounding->height;
97 else
99 r.x = x;
100 r.y = y;
101 r.width = w;
102 r.height = h;
104 XClearArea (dpy, wn, r.x, r.y, r.width, r.height, False);
105 if (iconified)
107 draw = frect_get_intersection(
108 x + d, y + d, w - 3, h - 3,
109 r.x, r.y, r.width, r.height, &inter);
110 if (iconcolorset >= 0)
112 cset = &Colorset[iconcolorset];
114 if (iconcolorset >= 0 && (cset->pixmap || cset->shape_mask)
115 && draw)
117 /* we have a colorset background */
118 SetClippedRectangleBackground(
119 dpy, win, x + d, y + d, w - 3, h - 3, &inter,
120 cset, Pdepth, icongraph);
122 else if (draw)
124 XFillRectangle (
125 dpy, wn, iconbackgraph,
126 inter.x, inter.y, inter.width, inter.height);
128 XDrawLine (dpy, wn, iconhilite, x, y, x+w-2, y);
129 XDrawLine (dpy, wn, iconhilite, x, y, x, y+h-2);
130 if (ThreeDfvwm)
132 XDrawLine (dpy, wn, iconhilite, x, y+1, x+w-2, y+1);
133 XDrawLine (dpy, wn, iconhilite, x+1, y, x+1, y+h-2);
135 XDrawLine (dpy, wn, iconshadow, x+1, y+h-2, x+w-2, y+h-2);
136 XDrawLine (dpy, wn, iconshadow, x+w-2, y+h-2, x+w-2, y+1);
137 XDrawLine (dpy, wn, blackgc, x, y+h-1, x+w-1, y+h-1);
138 XDrawLine (dpy, wn, blackgc, x+w-1, y+h-1, x+w-1, y);
139 return;
142 switch (state)
144 case BUTTON_UP:
145 XDrawLine (dpy, wn, hilite, x, y, x+w-2, y);
146 XDrawLine (dpy, wn, hilite, x, y, x, y+h-2);
147 if (ThreeDfvwm)
149 XDrawLine (dpy, wn, hilite, x, y+1, x+w-2, y+1);
150 XDrawLine (dpy, wn, hilite, x+1, y, x+1, y+h-2);
152 XDrawLine (dpy, wn, shadow, x+1, y+h-2, x+w-2, y+h-2);
153 XDrawLine (dpy, wn, shadow, x+w-2, y+h-2, x+w-2, y+1);
154 XDrawLine (dpy, wn, blackgc, x, y+h-1, x+w-1, y+h-1);
155 XDrawLine (dpy, wn, blackgc, x+w-1, y+h-1, x+w-1, y);
156 break;
157 case BUTTON_BRIGHT:
158 draw = frect_get_intersection(
159 x + 2, y + 2, w - 4 + (2 - d), h - 4 + (2 - d),
160 r.x, r.y, r.width, r.height, &inter);
161 if (focuscolorset >= 0)
162 cset = &Colorset[focuscolorset];
163 if (focuscolorset >= 0 && (cset->pixmap || cset->shape_mask) &&
164 draw)
166 /* we have a colorset background */
167 SetClippedRectangleBackground(
168 dpy, win, x + 2, y + 2, w - 4 + (2 - d),
169 h - 4 + (2 - d), &inter, cset, Pdepth,
170 focusgraph);
172 else if (draw)
174 XFillRectangle (
175 dpy, wn, focusbackgraph, inter.x, inter.y,
176 inter.width, inter.height);
178 if (!NoBrightFocus)
179 XFillRectangle (
180 dpy, wn, checkered, inter.x, inter.y,
181 inter.width, inter.height);
182 XDrawLine (dpy, wn, blackgc, x, y, x+w-2, y);
183 XDrawLine (dpy, wn, blackgc, x, y, x, y+h-2);
185 XDrawLine (dpy, wn, focusshadow, x, y+1, x+w-2, y+1);
186 XDrawLine (dpy, wn, focusshadow, x+1, y, x+1, y+h-2);
187 if (ThreeDfvwm)
189 XDrawLine (
190 dpy, wn, focushilite, x+1, y+h-2, x+w-2, y+h-2);
191 XDrawLine (
192 dpy, wn, focushilite, x+w-2, y+h-2, x+w-2, y+1);
194 XDrawLine (dpy, wn, focushilite, x, y+h-1, x+w-1, y+h-1);
195 XDrawLine (dpy, wn, focushilite, x+w-1, y+h-1, x+w-1, y);
196 break;
197 case BUTTON_DOWN:
198 XDrawLine (dpy, wn, blackgc, x, y, x+w-2, y);
199 XDrawLine (dpy, wn, blackgc, x, y, x, y+h-2);
201 XDrawLine (dpy, wn, shadow, x, y+1, x+w-2, y+1);
202 XDrawLine (dpy, wn, shadow, x+1, y, x+1, y+h-2);
203 if (ThreeDfvwm)
205 XDrawLine (dpy, wn, hilite, x+1, y+h-2, x+w-2, y+h-2);
206 XDrawLine (dpy, wn, hilite, x+w-2, y+h-2, x+w-2, y+1);
208 XDrawLine (dpy, wn, hilite, x, y+h-1, x+w-1, y+h-1);
209 XDrawLine (dpy, wn, hilite, x+w-1, y+h-1, x+w-1, y);
210 break;
215 /* -------------------------------------------------------------------------
216 ButtonNew - Allocates and fills a new button structure
217 ------------------------------------------------------------------------- */
218 Button *ButtonNew(const char *title, FvwmPicture *p, int state, int count)
220 Button *new;
222 if (title == NULL)
223 return NULL;
224 new = (Button *)safemalloc(sizeof(Button));
225 new->title = safemalloc(strlen(title)+1);
226 strcpy(new->title, title);
227 if (p != NULL) {
228 new->p.picture = p->picture;
229 new->p.mask = p->mask;
230 new->p.alpha = p->alpha;
231 new->p.width = p->width;
232 new->p.height = p->height;
233 new->p.depth = p->depth;
234 } else {
235 new->p.picture = 0;
238 new->state = state;
239 new->count = count;
240 new->next = NULL;
241 new->needsupdate = 1;
242 new->iconified = 0;
244 return new;
247 /* -------------------------------------------------------------------------
248 ButtonDraw - Draws the specified button
249 ------------------------------------------------------------------------- */
250 void ButtonDraw(Button *button, int x, int y, int w, int h, XEvent *evp)
252 char *t3p = "...\0";
253 int state, x3p, newx;
254 int search_len;
255 FlocaleFont *Ffont;
256 XGCValues gcv;
257 unsigned long gcm;
258 GC *drawgc;
259 int cs;
260 XRectangle rect,inter;
261 Region t_region;
263 if (w <= 0)
265 w = 1;
267 if (button == NULL)
269 return;
271 if (evp)
273 if (!frect_get_intersection(
274 x, y, w, h,
275 evp->xexpose.x, evp->xexpose.y,
276 evp->xexpose.width, evp->xexpose.height,
277 &rect))
279 return;
282 else
284 rect.x = x;
285 rect.y = y;
286 rect.width = w;
287 rect.height = h;
289 button->needsupdate = 0;
290 state = button->state;
291 Draw3dRect(
292 win, x, y, w, h, &rect, state, !!(button->iconified));
293 if (button->iconified)
295 drawgc = &icongraph;
296 cs = iconcolorset;
298 else if (state == BUTTON_BRIGHT)
300 drawgc = &focusgraph;
301 cs = focuscolorset;
303 else
305 drawgc = &graph;
306 cs = colorset;
309 if (state != BUTTON_UP) { x++; y++; }
311 if (state == BUTTON_BRIGHT || button == StartButton)
313 Ffont = FSelButtonFont;
315 else
317 Ffont = FButtonFont;
320 if (Ffont->font != NULL)
322 gcm = GCFont;
323 gcv.font = Ffont->font->fid;
324 XChangeGC(dpy, *drawgc, gcm, &gcv);
327 newx = 4;
328 w3p = FlocaleTextWidth(Ffont, t3p, 3);
330 if (button->p.picture != 0)
332 /* clip pixmap to fit inside button */
333 int pheight = min(button->p.height, h-2);
334 int offset = (button->p.height > h) ?
335 0 : ((h - button->p.height) >> 1);
336 int pwidth = min(button->p.width, w-5);
337 FvwmRenderAttributes fra;
339 fra.mask = FRAM_DEST_IS_A_WINDOW;
340 if (cs >= 0)
342 fra.mask |= FRAM_HAVE_ICON_CSET;
343 fra.colorset = &Colorset[cs];
345 if (frect_get_intersection(
346 rect.x, rect.y, rect.width, rect.height,
347 x+3, y+offset, pwidth, pheight, &inter))
349 PGraphicsRenderPicture(
350 dpy, win, &(button->p), &fra, win,
351 *drawgc, None, None,
352 (inter.x > (x+3))? inter.x - (x+3):0,
353 (inter.y > (y+offset))? inter.y - (y+offset):0,
354 inter.width, inter.height,
355 inter.x /*x+3*/, inter.y /*y+offset*/,
356 inter.width, inter.height, False);
358 newx += pwidth+2;
361 if (button->title == NULL)
363 return;
366 t_region = XCreateRegion();
367 XUnionRectWithRegion (&rect, t_region, t_region);
368 /* see if we have the place for "...", if not for "..", if not for "."
369 * if not return */
370 if ((newx + w3p + 2) >= w)
372 t3p = "..\0";
373 w3p = FlocaleTextWidth(Ffont, t3p, 2);
374 if ((newx + w3p + 2) >= w)
376 t3p = ".\0";
377 w3p = FlocaleTextWidth(Ffont, t3p, 1);
378 if ((newx + w3p + 2) >= w)
380 XDestroyRegion(t_region);
381 return;
386 search_len = strlen(button->title);
387 FwinString->win = win;
388 FwinString->y = y + Ffont->ascent + (RowHeight - Ffont->height)/2;
389 FwinString->gc = *drawgc;
390 FwinString->flags.has_colorset = False;
391 FwinString->flags.has_clip_region = True;
392 FwinString->clip_region = t_region;
393 if (cs >= 0)
395 FwinString->colorset = &Colorset[cs];
396 FwinString->flags.has_colorset = True;
398 button->truncate = False;
400 if (FlocaleTextWidth(Ffont, button->title, search_len) > w-newx-3)
402 x3p = 0;
403 while (search_len >= 0
404 && ((x3p = newx + FlocaleTextWidth(
405 Ffont, button->title, search_len))
406 > w-w3p-3))
408 search_len--;
410 FwinString->str = t3p;
411 FwinString->x = x + x3p;
412 FlocaleDrawString(dpy, Ffont, FwinString, 0);
413 button->truncate = True;
416 /* Only print as much of the title as will fit. */
417 if (search_len)
419 FwinString->str = button->title;
420 FwinString->x = x + newx;
421 FwinString->len = search_len;
422 FlocaleDrawString(dpy, Ffont, FwinString, FWS_HAVE_LENGTH);
424 FwinString->flags.has_clip_region = False;
425 XDestroyRegion(t_region);
429 /* -------------------------------------------------------------------------
430 ButtonUpdate - Change the name/state of a button
431 ------------------------------------------------------------------------- */
432 int ButtonUpdate(Button *button, const char *title, int state)
434 if (button == NULL) return -1;
436 if ((title != NULL) && (button->title != title)) {
437 button->title = (char *)saferealloc(button->title,strlen(title)+1);
438 strcpy(button->title,title);
439 button->needsupdate = 1;
442 if (state != DONT_CARE) {
443 if (state != button->state) {
444 button->state = state;
445 button->needsupdate = 1;
449 return 1;
452 /* -------------------------------------------------------------------------
453 ButtonDelete - Free space allocated to a button
454 ------------------------------------------------------------------------- */
455 void ButtonDelete(Button *ptr)
457 if (ptr != NULL) {
458 if (ptr->title != NULL) free(ptr->title);
459 free(ptr);
463 /* -------------------------------------------------------------------------
464 ButtonName - Return the name of the button
465 ------------------------------------------------------------------------- */
466 char *ButtonName(Button *button)
468 if (button == NULL) return NULL;
469 else return button->title;
474 * ButtonArray handling functions and procedures
477 /* -------------------------------------------------------------------------
478 InitArray - Initialize the arrary of buttons
479 ------------------------------------------------------------------------- */
480 void InitArray(ButtonArray *array, int x, int y, int w, int h, int tw)
482 array->count = 0;
483 array->head = array->tail = NULL;
484 array->x = x;
485 array->y = y;
486 array->w = w;
487 array->h = h;
488 array->tw = tw;
491 /* -------------------------------------------------------------------------
492 UpdateArray - Update the array specifics. x,y, width, height
493 ------------------------------------------------------------------------- */
494 void UpdateArray(ButtonArray *array,int x,int y,int w, int h, int tw)
496 Button *temp;
498 if (x != -1)
499 array->x = x;
500 if (y != -1)
501 array->y = y;
502 if (w != -1)
503 array->w = w;
504 if (h != -1)
505 array->h = h;
506 if (tw != -1)
507 array->tw = tw;
508 for(temp=array->head; temp!=NULL; temp=temp->next)
509 temp->needsupdate = 1;
512 /* -------------------------------------------------------------------------
513 AddButton - Allocate space for and add the button to the list
514 ------------------------------------------------------------------------- */
515 void AddButton(ButtonArray *array, const char *title, FvwmPicture *p, int state,
516 int count, int iconified)
518 Button *new, *temp;
520 new = ButtonNew(title, p, state, count);
521 if (new == NULL)
522 return;
523 if (iconified)
524 new->iconified = 1;
525 if (array->head == NULL)
526 array->head = new;
527 else
529 for (temp = array->head; temp->next; temp = temp->next)
531 temp->next = new;
533 array->count++;
535 ArrangeButtonArray(array);
538 /* -------------------------------------------------------------------------
539 ArrangeButtonArray - Rearrange the button size (called from AddButton,
540 RemoveButton, AdjustWindow)
541 ------------------------------------------------------------------------- */
543 void ArrangeButtonArray (ButtonArray *array)
545 int tw;
546 Button *temp;
548 if (!array->count)
549 tw = array->w;
550 else if (NRows == 1)
551 tw = array->w / array->count;
552 else
553 tw = array->w / ((array->count / NRows)+1);
555 if (tw > button_width)
556 tw = button_width;
557 if (tw < MIN_BUTTON_SIZE)
558 tw = MIN_BUTTON_SIZE;
560 if (tw != array->tw) /* update needed */
562 array->tw = tw;
563 for(temp = array->head; temp != NULL; temp = temp->next)
564 temp->needsupdate = 1;
568 /* -------------------------------------------------------------------------
569 UpdateButton - Change the name/state of a button
570 ------------------------------------------------------------------------- */
571 int UpdateButton(ButtonArray *array, int butnum, const char *title, int state)
573 Button *temp;
575 for (temp = array->head; temp; temp = temp->next)
576 if (temp->count == butnum)
577 break;
579 return ButtonUpdate(temp, title, state);
582 /* -------------------------------------------------------------------------
583 UpdateButtonPicture - Change the picture of a button
584 ------------------------------------------------------------------------- */
585 int UpdateButtonPicture(ButtonArray *array, int butnum, FvwmPicture *p)
587 Button *temp;
589 for (temp=array->head; temp; temp=temp->next)
590 if (temp->count == butnum)
591 break;
593 if (temp == NULL) return -1;
594 if (temp->p.picture != p->picture || temp->p.mask != p->mask) {
595 temp->p.picture = p->picture;
596 temp->p.mask = p->mask;
597 temp->p.alpha = p->alpha;
598 temp->p.width = p->width;
599 temp->p.height = p->height;
600 temp->p.depth = p->depth;
601 temp->needsupdate = 1;
603 return 1;
606 /* -------------------------------------------------------------------------
607 RemoveButton - Delete a button from the list
608 ------------------------------------------------------------------------- */
609 void RemoveButton(ButtonArray *array, int butnum)
611 Button *temp, *to_die;
613 if (array->head == NULL)
614 return;
616 if (array->head->count == butnum)
618 to_die = array->head;
619 array->head = array->head->next;
621 else
623 for (temp = array->head, to_die = array->head->next; to_die != NULL;
624 to_die = to_die->next, temp = temp->next)
626 if (to_die->count == butnum)
627 break;
629 if (!to_die)
630 return;
631 temp->next = to_die->next;
634 ButtonDelete(to_die);
635 if (array->count > 0)
636 array->count--;
637 for (temp = array->head; temp; temp = temp->next)
638 temp->needsupdate = 1;
640 ArrangeButtonArray(array);
643 /* -------------------------------------------------------------------------
644 find_n - Find the nth button in the list (Use internally)
645 ------------------------------------------------------------------------- */
646 Button *find_n(ButtonArray *array, int n)
648 Button *temp;
650 temp = array->head;
651 if (n < 0)
652 return NULL;
653 for ( ; temp && n != temp->count; temp=temp->next)
655 return temp;
658 /* -------------------------------------------------------------------------
659 FreeAllButtons - Free the whole array of buttons
660 ------------------------------------------------------------------------- */
661 void FreeAllButtons(ButtonArray *array)
663 Button *temp, *temp2;
665 for(temp=array->head; temp!=NULL; ) {
666 temp2 = temp;
667 temp = temp->next;
668 ButtonDelete(temp2);
670 array->count = 0;
671 array->head = NULL;
674 /* ------------------------------------------------------------------------
675 DrawButtonArray - Draw the whole array (all=1), or only those that need.
676 ------------------------------------------------------------------------ */
677 void DrawButtonArray(ButtonArray *array, int all, XEvent *evp)
679 Button *temp;
680 int x, y, n;
681 static Bool exposed = False;
683 if (!exposed && evp)
685 exposed = True;
687 if (!exposed)
689 return;
691 x = 0;
692 y = array->y;
693 n = 1;
694 for(temp=array->head; temp!=NULL; temp=temp->next)
696 if ((x + array->tw > array->w) && (n < NRows))
698 x = 0;
699 y += RowHeight+2;
700 ++n;
702 if (temp->needsupdate || all)
703 ButtonDraw(
704 temp, x + array->x, y, array->tw-pad, array->h,
705 (temp->needsupdate)? NULL:evp);
706 x += array->tw;
710 /* -------------------------------------------------------------------------
711 RadioButton - Enable button i and verify all others are disabled
712 ------------------------------------------------------------------------- */
713 void RadioButton(ButtonArray *array, int butnum, int state)
715 Button *button;
717 for(button=array->head; button!=NULL; button=button->next) {
718 if (button->count == butnum) {
719 button->state = state;
720 button->needsupdate = 1;
721 } else {
722 if (button->state != BUTTON_UP) {
723 button->state = BUTTON_UP;
724 button->needsupdate = 1;
729 /* -------------------------------------------------------------------------
731 ------------------------------------------------------------------------- */
732 Bool CheckRootTransparentButtons(ButtonArray *array)
734 Button *button;
735 Bool r = 0;
737 if (!CSET_IS_TRANSPARENT_ROOT(iconcolorset) &&
738 !CSET_IS_TRANSPARENT_ROOT(focuscolorset))
740 return r;
742 for(button=array->head; button!=NULL; button=button->next)
744 if ((button->iconified &&
745 CSET_IS_TRANSPARENT_ROOT(iconcolorset)) ||
746 (button->state == BUTTON_BRIGHT &&
747 CSET_IS_TRANSPARENT_ROOT(focuscolorset)))
749 r = True;
750 button->needsupdate = 1;
753 return r;
756 /* -------------------------------------------------------------------------
757 WhichButton - Based on x,y which button was pressed
758 ------------------------------------------------------------------------- */
759 int WhichButton(ButtonArray *array, int xp, int yp)
761 int junkx, junky, junkz;
762 char *junkt;
764 return LocateButton(array, xp, yp, &junkx, &junky, &junkt, &junkz);
767 int LocateButton(ButtonArray *array, int xp, int yp, int *xb, int *yb,
768 char **name, int *trunc)
770 Button *temp;
771 int num, x, y, n;
773 if (xp < array->x || xp > array->x+array->w) return -1;
775 x = 0;
776 y = array->y;
777 n = 1;
778 for(temp=array->head, num=0; temp!=NULL; temp=temp->next, num++) {
779 if((x + array->tw > array->w) && (n < NRows))
780 { x = 0; y += RowHeight+2; ++n; }
781 if( xp >= x+array->x && xp <= x+array->x+array->tw-3 &&
782 yp >= y && yp <= y+array->h) break;
783 x += array->tw;
786 if (num<0 || num>array->count-1) num = -1;
788 *xb = x+array->x;
789 *yb = y;
790 if (temp) {
791 *name = temp->title;
792 *trunc = temp->truncate;
793 } else {
794 *name = NULL;
797 return (num == -1) ? num : temp->count;
800 /* -------------------------------------------------------------------------
801 ButtonCoordinates - Compute the coordinates of a button (animation)
802 ------------------------------------------------------------------------- */
803 extern int StartAndLaunchButtonsWidth;
804 void ButtonCoordinates(ButtonArray *array, int numbut, int *xc, int *yc)
806 Button *temp;
807 int x = 0;
808 int y = 0;
809 int r = 0;
811 for(temp=array->head; temp->count != numbut; temp=temp->next)
813 if((x + 2*array->tw > array->w) && (r < NRows))
815 x = 0;
816 y += RowHeight+2;
817 ++r;
819 else
821 x += array->tw;
825 *xc = x+ StartAndLaunchButtonsWidth+3;
826 *yc = y;
829 void ButtonDimensions(ButtonArray *array, int *width, int *height)
831 *width = array->tw;
832 *height = RowHeight+2;