/****************************************************************************
 * This module is all original code 
 * by Rob Nation 
 * Copyright 1993, Robert Nation
 *     You may use this code for any purpose, as long as the original
 *     copyright remains in the source code and all documentation
 ****************************************************************************/


/***********************************************************************
 *
 * fvwm window border drawing code
 *
 ***********************************************************************/

#include <FVWMconfig.h>

#include <stdio.h>
#include <signal.h>
#include <string.h>

#include "fvwm.h"
#include "menus.h"
#include "misc.h"
#include "parse.h"
#include "screen.h"
#include "module.h"

#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif

void DrawLinePattern(Window win,
                     GC ReliefGC,
                     GC ShadowGC,
                     int num_coords,
                     int *x_coord, 
                     int *y_coord,
                     int *line_style,
                     int th);

/* macro to change window background color/pixmap */
#define ChangeWindowColor(window,color) {\
        if (NewColor)\
           {\
             if (Scr.d_depth >= 2) attributes.background_pixel = color;\
             XChangeWindowAttributes(dpy, window, valuemask, &attributes);\
             XClearWindow(dpy,window);\
           }\
         }

extern Window PressedW;
XGCValues Globalgcv;
unsigned long Globalgcm;
/****************************************************************************
 *
 * Redraws the windows borders
 *
 ****************************************************************************/
void SetBorder (FvwmWindow *t, Bool onoroff,Bool force,Bool Mapped, 
		Window expose_win)
  {
  int    i, x, y;
  Pixel  BackColor, ForeColor, TitleBackColor, TitleTextColor;
  Pixmap BackPixmap, TextColor;
  GC     ReliefGC, ShadowGC;
  Bool   NewColor = False;
  XSetWindowAttributes attributes;
  unsigned long valuemask;
  static unsigned int corners[4];
  Window w;

  corners[0] = TOP_HILITE | LEFT_HILITE;
  corners[1] = TOP_HILITE | RIGHT_HILITE;
  corners[2] = BOTTOM_HILITE | LEFT_HILITE;
  corners[3] = BOTTOM_HILITE | RIGHT_HILITE;
  
  if (!t) return;
  
  if (onoroff) 
    {
    /* on */

    /* don't re-draw just for kicks */
    if ((!force) && (Scr.Hilite == t)) return;

    if (Scr.Hilite != t) NewColor = True;
      
    /* make sure that the previously highlighted window got unhighlighted */
    if ((Scr.Hilite != t) && (Scr.Hilite != NULL))
      SetBorder(Scr.Hilite, False, False, True, None);

    /* set the keyboard focus */
    if ((Mapped) && (t->flags&MAPPED) && (Scr.Hilite != t))
      w = t->w;
    else if ((t->flags & ICONIFIED) &&
            (Scr.Hilite != t) && (!(t->flags & SUPPRESSICON)))
      w = t->icon_w;
    Scr.Hilite = t;

    BackPixmap = Scr.gray_pixmap;
    TitleBackColor = Scr.ActiveTitleColors.back;
    TitleTextColor = Scr.ActiveTitleColors.fore;
    }
  else
    {
    /* off */

    /* don't re-draw just for kicks */
    if ((!force) && (Scr.Hilite != t)) return;
      
    if(Scr.Hilite == t)
      {
      Scr.Hilite = NULL;
      NewColor = True;
      }
      
    if (t->flags & STICKY)
      {
      BackPixmap = Scr.sticky_gray_pixmap;
      TitleBackColor = Scr.StickyColors.back;
      TitleTextColor = Scr.StickyColors.fore;
      }
    else
      {
      BackPixmap = Scr.light_gray_pixmap;
      TitleBackColor = t->BackPixel;
      TitleTextColor = t->TextPixel;
      }
    }

  ReliefGC = Scr.WinReliefGC;
  ShadowGC = Scr.WinShadowGC;
  BackColor = Scr.WinColors.back;
  ForeColor = Scr.WinColors.fore;

  if (t->flags & ICONIFIED)
    {
    DrawIconWindow(t);
    return;
    }

  valuemask = CWBorderPixel;
  attributes.border_pixel = Scr.WinColors.shadow;
  if (Scr.d_depth < 2)
    {
    attributes.background_pixmap = BackPixmap;
    valuemask |= CWBackPixmap;
    }
  else
    {
    attributes.background_pixel = BackColor;
    valuemask |= CWBackPixel;
    }
  
  if(t->flags & (TITLE | BORDER))
    {
    XSetWindowBorder(dpy, t->Parent, BackColor);
    XSetWindowBorder(dpy, t->frame, BackColor);
    }

  /* Area for optimization? */

  if(t->flags & TITLE)
    {
    Window *win;

    /* fore color for selected window title bar */
    ChangeWindowColor (t->title_w, TitleBackColor);

    for (i=0, win=t->left_w; i<Scr.nr_left_buttons; i++, win++)
      {
      if (*win != None)
        {
        ChangeWindowColor (*win, TitleBackColor);
        if(flush_expose(*win) || (expose_win == *win) ||
           (expose_win == None))
          {
          if ((i == 0) && (t->title_icon)) /* title icon present? */
            {
            XGCValues gcv;
            unsigned long gcm;

            gcm = GCClipMask|GCClipXOrigin|GCClipYOrigin;
            gcv.clip_mask = t->title_icon->mask;
            gcv.clip_x_origin = 0;
            gcv.clip_y_origin = 0;
            XChangeGC(dpy, Scr.ScratchGC3, gcm, &gcv);
            
            XCopyArea (dpy, t->title_icon->picture, *win,
                       Scr.ScratchGC3, 0, 0,
                       t->title_icon->width, t->title_icon->height,
                       gcv.clip_x_origin, gcv.clip_y_origin);

            gcm = GCClipMask;
            gcv.clip_mask = None;
            XChangeGC(dpy, Scr.ScratchGC3, gcm, &gcv);
            }
          else
            {	
            RelieveButton (t, *win, 0, 0,
                           Scr.button_width, Scr.button_height,
                           ReliefGC, ShadowGC,
                           (PressedW == *win));
            XCopyArea (dpy, Scr.button_pixmap[i<<1], *win,
                       Scr.WinGC, 0, 0,
                       Scr.button_width-3, Scr.button_height-3,
                       (PressedW == *win) ? 2 : 1,
                       (PressedW == *win) ? 2 : 1);
            }

          }
        }
	  
      }
	     
    for (i=0, win=t->right_w; i<Scr.nr_right_buttons; i++, win++)
      {
      if (*win != None)
        {
        ChangeWindowColor(*win, TitleBackColor);
        if (flush_expose(*win) || (expose_win == *win) ||
           (expose_win == None))
          {
          RelieveButton (t, *win, 0, 0,
                         Scr.button_width, Scr.button_height,
                         ReliefGC, ShadowGC,
                         (PressedW == *win));
          if ((i == 1) && (t->flags & MAXIMIZED))
            {
            XCopyArea (dpy, Scr.button_pixmap[(i<<1)], *win,
                       Scr.WinGC, 0, 0,
                       Scr.button_width-3, Scr.button_height-3,
                       (PressedW == *win) ? 2 : 1,
                       (PressedW == *win) ? 2 : 1);
            }
          else
            {
            XCopyArea (dpy, Scr.button_pixmap[(i<<1)+1], *win,
                       Scr.WinGC, 0, 0,
                       Scr.button_width-3, Scr.button_height-3,
                       (PressedW == *win) ? 2 : 1,
                       (PressedW == *win) ? 2 : 1);
            }

          }
        }

      }

    SetTitleBar (t, onoroff, False);
    }

  if(t->flags & BORDER)
    {
    Window *side, *corner;

    /* draw relief lines */
    y = t->frame_height - (t->corner_width << 1);
    x = t->frame_width  - (t->corner_width << 1) + t->bw;

    for (i=0, side=t->sides, corner=t->corners; i<4; i++, side++, corner++)
      {
      ChangeWindowColor(*side, BackColor);
      if((flush_expose(*side)) || (expose_win == *side)||
         (expose_win == None))
        {
        /* index    side
         * 0        TOP
         * 1        RIGHT
         * 2        BOTTOM
         * 3        LEFT
         */
	      
        RelieveWindow(t, *side, 0, 0,
                      ((i & 1) ? t->boundary_width : x),
                      ((i & 1) ? y : t->boundary_width),
                      ReliefGC, ShadowGC, (0x0001 << i));
        }
      ChangeWindowColor(*corner, BackColor);
      if((flush_expose(*corner)) || (expose_win == *corner)||
         (expose_win == None))
        {
        RelieveWindow(t, *corner, 0, 0, t->corner_width,
                      ((i>>1) ? t->corner_width+t->bw : t->corner_width),
                      ReliefGC, ShadowGC, corners[i]);
        }
      }
    }
  else      /* no decorative border */
    {
    /* for mono - put a black border on 
     * for color, make it the color of the decoration background */
    if(t->boundary_width < 2)
      {
      flush_expose (t->frame);
      if(Scr.d_depth < 2)
        {
        XSetWindowBorder (dpy, t->frame, ForeColor);
        XSetWindowBorder (dpy, t->Parent, ForeColor);
        XSetWindowBackgroundPixmap (dpy, t->frame, BackPixmap);
        XClearWindow (dpy, t->frame);
        XSetWindowBackgroundPixmap (dpy, t->Parent, BackPixmap);
        XClearWindow (dpy, t->Parent);
        }
      else
        {
        XSetWindowBackground (dpy, t->frame, BackColor);
        XSetWindowBorder (dpy, t->frame, Scr.WinColors.shadow);
        XClearWindow (dpy, t->frame);
        XSetWindowBackground (dpy, t->Parent, Scr.WinColors.shadow);
        XSetWindowBorder (dpy, t->Parent, Scr.WinColors.shadow);
        XClearWindow (dpy, t->Parent);
        XSetWindowBorder (dpy, t->w, Scr.WinColors.shadow);	      
        }
      }
    else
      {
      XSetWindowBorder (dpy, t->Parent, Scr.WinColors.shadow);
      XSetWindowBorder (dpy, t->frame, Scr.WinColors.shadow);

      ChangeWindowColor (t->frame, BackColor);
      if((flush_expose(t->frame)) || (expose_win == t->frame)||
         (expose_win == None))
        {
        if(t->boundary_width > 2)
          {
          RelieveWindow(t, t->frame, 0, 0, t->frame_width + t->bw,
                        t->frame_height + t->bw,
                        ReliefGC, ShadowGC,
                        TOP_HILITE | LEFT_HILITE | RIGHT_HILITE |
                        BOTTOM_HILITE);
          }
        else
          {
          RelieveWindow(t, t->frame, 0, 0, t->frame_width + t->bw,
                        t->frame_height + t->bw,
                        ReliefGC, ShadowGC,
                        TOP_HILITE | LEFT_HILITE | RIGHT_HILITE |
                        BOTTOM_HILITE);	      
          }
        }
      else
        {
        XSetWindowBackground(dpy, t->Parent, Scr.WinColors.shadow);
        }
      }
    }

  /* Sync to make the border-color change look fast! */
  XSync(dpy, 0);
  }


/****************************************************************************
 *
 *  Redraws just the title bar
 *
 ****************************************************************************/
void SetTitleBar (FvwmWindow *t, Bool onoroff, Bool NewTitle)
  {
  int x, y, w, i;
  Pixel Forecolor, BackColor;

  if (!t) return;
  if (!(t->flags & TITLE)) return;

  if (onoroff) 
    {
    Forecolor = Scr.ActiveTitleColors.fore;
    BackColor = Scr.ActiveTitleColors.back;
    }
  else
    {
    Forecolor = t->TextPixel;
    BackColor = t->BackPixel;
    }

  flush_expose(t->title_w);
  
  if(t->name != (char *)NULL)
    {
    w = XTextWidth(Scr.WindowFont.font,t->name,strlen(t->name));
    if (w > t->title_width-12) w = t->title_width-4;
    if (w < 0) w = 0;
    }
  else
    {
    w = 0;
    }

  x = Scr.button_width*t->nr_left_buttons + 6;
  y = ((Scr.WindowFont.y + t->title_height) >> 1) - 1; 
  
  NewFontAndColor(Scr.WindowFont.font->fid, Forecolor, BackColor);
  
  if (NewTitle) XClearWindow (dpy, t->title_w);

#ifdef I18N
#undef FONTSET
#define FONTSET Scr.WindowFont.fontset
#endif /* I18N */

  /* for mono, we clear an area in the title bar where the window
   * title goes, so that its more legible. For color, no need */
  if(Scr.d_depth<2)
    {
    XFillRectangle(dpy,t->title_w,
                   Scr.BlackGC,
                   x - 2, 0, w+4, t->title_height);
      
    if(t->name != (char *)NULL)
      XDrawString (dpy, t->title_w,Scr.ScratchGC3, x, y,
                   t->name, strlen(t->name));
    }
  else
    { 
    if(t->name != (char *)NULL)
      XDrawString (dpy, t->title_w, Scr.ScratchGC3, x, y,
                   t->name, strlen(t->name));
    }

  XFlush(dpy);
  }


/****************************************************************************
 *
 *  Draws the relief pattern around a window (win95)
 *
 ****************************************************************************/
inline void RelieveWindow(FvwmWindow *t, Window win,
                          int x, int y, int w, int h,
                          GC ReliefGC, GC ShadowGC, int hilite)
  {
  XSegment seg[4];
  int i;
  int edge;

  edge = 0; 
  if ((win == t->sides[0]) || (win == t->sides[1])||
      (win == t->sides[2]) || (win == t->sides[3])) edge = -1;
  else if (win == t->corners[0]) edge = 1;
  else if (win == t->corners[1]) edge = 2;
  else if (win == t->corners[2]) edge = 3;
  else if (win == t->corners[3]) edge = 4;

  /* window sides */
  if (edge == -1)
    {
    switch (hilite)
      {
      case LEFT_HILITE:
            i = 0;
            seg[i].x1 = x+1;      seg[i].y1   = y;
            seg[i].x2 = x+1;      seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, ReliefGC, seg, i);
            break;

      case TOP_HILITE:
            i = 0;
            seg[i].x1 = x;        seg[i].y1   = y+1;
            seg[i].x2 = w+x-1;    seg[i++].y2 = y+1;
            XDrawSegments(dpy, win, ReliefGC, seg, i);
            break;

      case RIGHT_HILITE:
            i = 0;
            seg[i].x1 = w+x-1;    seg[i].y1   = y;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
            i = 0;
            seg[i].x1 = w+x-2;    seg[i].y1   = y;
            seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, ShadowGC, seg, i);
            break;

      case BOTTOM_HILITE:
            i = 0;
            seg[i].x1 = x;        seg[i].y1   = h+y-1;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
            i = 0;
            seg[i].x1 = x;        seg[i].y1   = h+y-2;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-2;
            XDrawSegments(dpy, win, ShadowGC, seg, i);
            break;

      }
    return;
    }

  /* corners */
  if (edge >= 1 && edge <= 4)
    {
    switch (edge)
      {
      case 1:
            i = 0;
            seg[i].x1 = x+1;      seg[i].y1   = y+1;
            seg[i].x2 = x+1;      seg[i++].y2 = h+y-1;
            seg[i].x1 = x+1;      seg[i].y1   = y+1;
            seg[i].x2 = w+x-1;    seg[i++].y2 = y+1;
            XDrawSegments(dpy, win, ReliefGC, seg, i);
            break;

      case 2:
            i = 0;
            seg[i].x1 = x;        seg[i].y1   = y+1;
            seg[i].x2 = w+x-2;    seg[i++].y2 = y+1;
            XDrawSegments(dpy, win, ReliefGC, seg, i);
            i = 0;
            seg[i].x1 = w+x-1;    seg[i].y1   = y;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
            i = 0;
            seg[i].x1 = w+x-2;    seg[i].y1   = y+1;
            seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, ShadowGC, seg, i);
            break;

      case 3:
            i = 0;
            seg[i].x1 = x+1;      seg[i].y1   = y;
            seg[i].x2 = x+1;      seg[i++].y2 = h+y-2;
            XDrawSegments(dpy, win, ReliefGC, seg, i);
            i = 0;
            seg[i].x1 = x;        seg[i].y1   = h+y-1;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
            i = 0;
            seg[i].x1 = x+1;      seg[i].y1   = h+y-2;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-2;
            XDrawSegments(dpy, win, ShadowGC, seg, i);
            break;

      case 4:
            i = 0;
            seg[i].x1 = w+x-1;    seg[i].y1   = y;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
            seg[i].x1 = x;        seg[i].y1   = h+y-1;
            seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
            XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
            i = 0;
            seg[i].x1 = w+x-2;    seg[i].y1   = y;
            seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-2;
            seg[i].x1 = x;        seg[i].y1   = h+y-2;
            seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-2;
            XDrawSegments(dpy, win, ShadowGC, seg, i);
            break;

      }
    return;
    }

  /* any other rectangular window */
  if (edge == 0)
    {
    i = 0;
    seg[i].x1 = x+1;      seg[i].y1   = y+1;
    seg[i].x2 = w+x-2;    seg[i++].y2 = y+1;
    seg[i].x1 = x+1;      seg[i].y1   = y+1;
    seg[i].x2 = x+1;      seg[i++].y2 = h+y-2;
    XDrawSegments(dpy, win, ReliefGC, seg, i);
    i = 0;
    seg[i].x1 = x+1;      seg[i].y1   = h+y-2;
    seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-2;
    seg[i].x1 = w+x-2;    seg[i].y1   = y+1;
    seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-2;
    XDrawSegments(dpy, win, ShadowGC, seg, i);
    i = 0;
    seg[i].x1 = x;        seg[i].y1   = h+y-1;
    seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
    seg[i].x1 = w+x-1;    seg[i].y1   = y;
    seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
    XDrawSegments(dpy, win, Scr.BlackGC, seg, i);

    return;
    }
  }

void RelieveButton (FvwmWindow *t, Window win, int x, int y, int w, int h,
                     GC ReliefGC, GC ShadowGC, int state)
  {
  int i;
  XSegment seg[4];

  if (state) /* 1 = pressed */
    {
    i = 0;
    seg[i].x1 = x;        seg[i].y1   = y;
    seg[i].x2 = w+x-1;    seg[i++].y2 = y;
    seg[i].x1 = x;        seg[i].y1   = y;
    seg[i].x2 = x;        seg[i++].y2 = h+y-1;
    XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
    i = 0;
    seg[i].x1 = x+1;      seg[i].y1   = y+1;
    seg[i].x2 = w+x-2;    seg[i++].y2 = y+1;
    seg[i].x1 = x+1;      seg[i].y1   = y+1;
    seg[i].x2 = x+1;      seg[i++].y2 = h+y-2;
    XDrawSegments(dpy, win, ShadowGC, seg, i);
    i = 0;
    seg[i].x1 = x+1;      seg[i].y1   = h+y-1;
    seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
    seg[i].x1 = w+x-1;    seg[i].y1   = y+1;
    seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
    XDrawSegments(dpy, win, ReliefGC, seg, i);
    }
  else
    {
    i = 0;
    seg[i].x1 = x;        seg[i].y1   = y;
    seg[i].x2 = w+x-2;    seg[i++].y2 = y;
    seg[i].x1 = x;        seg[i].y1   = y;
    seg[i].x2 = x;        seg[i++].y2 = h+y-2;
    XDrawSegments(dpy, win, ReliefGC, seg, i);
    i = 0;
    seg[i].x1 = x+1;      seg[i].y1   = h+y-2;
    seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-2;
    seg[i].x1 = w+x-2;    seg[i].y1   = y+1;
    seg[i].x2 = w+x-2;    seg[i++].y2 = h+y-2;
    XDrawSegments(dpy, win, ShadowGC, seg, i);
    i = 0;
    seg[i].x1 = x;        seg[i].y1   = h+y-1;
    seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
    seg[i].x1 = w+x-1;    seg[i].y1   = y;
    seg[i].x2 = w+x-1;    seg[i++].y2 = h+y-1;
    XDrawSegments(dpy, win, Scr.BlackGC, seg, i);
    }
  }


/***********************************************************************
 *
 *  Procedure:
 *      Setupframe - set window sizes, this was called from either
 *              AddWindow, EndResize, or HandleConfigureNotify.
 *
 *  Inputs:
 *      tmp_win - the FvwmWindow pointer
 *      x       - the x coordinate of the upper-left outer corner of the frame
 *      y       - the y coordinate of the upper-left outer corner of the frame
 *      w       - the width of the frame window w/o border
 *      h       - the height of the frame window w/o border
 *
 *  Special Considerations:
 *      This routine will check to make sure the window is not completely
 *      off the display, if it is, it'll bring some of it back on.
 *
 *      The tmp_win->frame_XXX variables should NOT be updated with the
 *      values of x,y,w,h prior to calling this routine, since the new
 *      values are compared against the old to see whether a synthetic
 *      ConfigureNotify event should be sent.  (It should be sent if the
 *      window was moved but not resized.)
 *
 ************************************************************************/

void SetupFrame(FvwmWindow *tmp_win, int x, int y, int w, int h,
                Bool sendEvent) 
{
  XEvent client_event;
  XWindowChanges frame_wc, xwc;
  unsigned long frame_mask, xwcm;
  int    cx, cy, i;
  Bool   Resized = False;
  int    xwidth, ywidth;
  Window *win;

  /* if windows is not being maximized, save size in case of maximization */
  if (!(tmp_win->flags & MAXIMIZED))
    {
    tmp_win->orig_x  = x;
    tmp_win->orig_y  = y;
    tmp_win->orig_wd = w;
    tmp_win->orig_ht = h;
    }

/* This screws up the Taskbar's AutoHide mode when the southern
   and eastern most pages are selected.  Is this really
   necessary anyway?  Will removing this break anything else? */

/*
  if (x >= Scr.MyDisplayWidth + Scr.VxMax - Scr.Vx - 16)
    x = Scr.MyDisplayWidth + Scr.VxMax - Scr.Vx - 16;

  if (y >= Scr.MyDisplayHeight + Scr.VyMax - Scr.Vy - 16)
    y = Scr.MyDisplayHeight + Scr.VyMax - Scr.Vy - 16;
*/

  /*
   * According to the July 27, 1988 ICCCM draft, we should send a
   * "synthetic" ConfigureNotify event to the client if the window
   * was moved but not resized.
   */
  if ((x != tmp_win->frame_x || y != tmp_win->frame_y) &&
      (w == tmp_win->frame_width && h == tmp_win->frame_height))
    sendEvent = TRUE;

  if((w != tmp_win->frame_width) || (h != tmp_win->frame_height))
    Resized = True;

  xwcm = CWX | CWY | CWWidth | CWHeight;

  if(Resized)
    {
    if (tmp_win->flags & TITLE) 
      tmp_win->title_height = Scr.TitleHeight + tmp_win->bw;

    tmp_win->title_width = w - (tmp_win->boundary_width << 1) + tmp_win->bw;
    if(tmp_win->title_width < 1) tmp_win->title_width = 1;

    if (tmp_win->flags & TITLE) 
      {
      /* setup titlebar window */

      tmp_win->title_x = tmp_win->boundary_width;

      if(tmp_win->title_x >= w - tmp_win->boundary_width)
        tmp_win->title_x = -10;

      tmp_win->title_y = tmp_win->boundary_width;
	  
      xwc.width  = tmp_win->title_width;
      xwc.height = tmp_win->title_height;

      xwc.x = tmp_win->title_x;
      xwc.y = tmp_win->title_y;

      XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);

      /* setup left button windows */

      /* mini-icon first */

      if (tmp_win->title_icon)
        {
        xwc.height = tmp_win->title_icon->height;
        xwc.width = tmp_win->title_icon->width;
        }
      else
        {
        xwc.height = Scr.button_height;
        xwc.width = Scr.button_width;
        }

      xwc.y = tmp_win->boundary_width +
              ((tmp_win->title_height - xwc.height) >> 1) +1;
      xwc.x = tmp_win->boundary_width +3;

      win = tmp_win->left_w;
      if (*win != None)
        {
        if(xwc.x + xwc.width >= w-tmp_win->boundary_width)
          xwc.x = -xwc.width;

        XConfigureWindow(dpy, *win, xwcm, &xwc);
        xwc.x += xwc.width +2;
        }

      win++;

      xwc.height = Scr.button_height;
      xwc.width = Scr.button_width;

      xwc.y = tmp_win->boundary_width +
              ((tmp_win->title_height - xwc.height) >> 1) +1;

      for(i=1; i<Scr.nr_left_buttons; i++, win++)
        {
        if (*win != None)
          {
          if(xwc.x + Scr.button_width >= w-tmp_win->boundary_width)
            xwc.x = -Scr.button_width;

          XConfigureWindow(dpy, *win, xwcm, &xwc);
          xwc.x += Scr.button_width +2;
          }
        }

      /* setup right button windows */

      xwc.x = w-tmp_win->boundary_width + tmp_win->bw -2;

      for(i=0, win=tmp_win->right_w; i<Scr.nr_right_buttons; i++, win++)
        {
        if (*win != None)
          {
          xwc.x -= Scr.button_width;
          if(xwc.x <= tmp_win->boundary_width)
            xwc.x = -Scr.button_width;

          XConfigureWindow(dpy, *win, xwcm, &xwc);
          if (i == 0) xwc.x -= 2;
          }
        }
      }

    if(tmp_win->flags & BORDER)
      {
      /* setup side windows */

      tmp_win->corner_width = Scr.TitleHeight + tmp_win->bw + 
                              tmp_win->boundary_width;

      if (w < (tmp_win->corner_width << 1)) tmp_win->corner_width = w/3;
      if (h < (tmp_win->corner_width << 1)) tmp_win->corner_width = h/3;

      xwidth = w - (tmp_win->corner_width << 1) + tmp_win->bw;
      ywidth = h - (tmp_win->corner_width << 1);

      if (xwidth < 2) xwidth = 2;
      if (ywidth < 2) ywidth = 2;

      for(i=0, win=tmp_win->sides; i<4; i++, win++)
        {
        if (i == 0)
          {
          xwc.x = tmp_win->corner_width;
          xwc.y = 0;
          xwc.height = tmp_win->boundary_width;
          xwc.width  = xwidth;
          }
        else if (i == 1)
          {
          xwc.x = w - tmp_win->boundary_width + tmp_win->bw;	
          xwc.y = tmp_win->corner_width;
          xwc.width  = tmp_win->boundary_width;
          xwc.height = ywidth;
          }
        else if (i == 2)
          {
          xwc.x = tmp_win->corner_width;
          xwc.y = h - tmp_win->boundary_width + tmp_win->bw;
          xwc.height = tmp_win->boundary_width + tmp_win->bw;
          xwc.width  = xwidth;
          }
        else
          {
          xwc.x = 0;
          xwc.y = tmp_win->corner_width;
          xwc.width  = tmp_win->boundary_width;
          xwc.height = ywidth;
          }
        XConfigureWindow(dpy, *win, xwcm, &xwc);
        }

      /* setup corner windows */

      xwc.width  = tmp_win->corner_width;
      xwc.height = tmp_win->corner_width;

      for(i=0, win=tmp_win->corners; i<4; i++, win++)
        {
        if(i & 1)
          xwc.x = w - tmp_win->corner_width + tmp_win->bw;
        else
          xwc.x = 0;
	      
        if(i >> 1)
          xwc.y = h - tmp_win->corner_width;
        else
          xwc.y = 0;

        XConfigureWindow(dpy, *win, xwcm, &xwc);
        }
      }
    }

  tmp_win->attr.width  = w - (tmp_win->boundary_width << 1);
  tmp_win->attr.height = h - tmp_win->title_height 
                           - (tmp_win->boundary_width << 1);

  cx = tmp_win->boundary_width - tmp_win->bw;
  cy = tmp_win->title_height + tmp_win->boundary_width - tmp_win->bw;

  XResizeWindow(dpy, tmp_win->w, tmp_win->attr.width,
		tmp_win->attr.height);
  XMoveResizeWindow(dpy, tmp_win->Parent, cx,cy,
		    tmp_win->attr.width, tmp_win->attr.height);

  /* 
   * fix up frame and assign size/location values in tmp_win
   */
  frame_wc.x = tmp_win->frame_x = x;
  frame_wc.y = tmp_win->frame_y = y;
  frame_wc.width = tmp_win->frame_width = w;
  frame_wc.height = tmp_win->frame_height = h;
  frame_mask = (CWX | CWY | CWWidth | CWHeight);
  XConfigureWindow (dpy, tmp_win->frame, frame_mask, &frame_wc);

#ifdef SHAPE
  if (ShapesSupported)
    if ((Resized) && (tmp_win->wShaped)) SetShape (tmp_win, w);
#endif /* SHAPE */

  XSync (dpy, 0);

  if (sendEvent)
    {
    client_event.type = ConfigureNotify;
    client_event.xconfigure.display = dpy;
    client_event.xconfigure.event   = tmp_win->w;
    client_event.xconfigure.window  = tmp_win->w;
      
    client_event.xconfigure.x = x + tmp_win->boundary_width;
    client_event.xconfigure.y = y + tmp_win->title_height
                                  + tmp_win->boundary_width;
    client_event.xconfigure.width  = w - (tmp_win->boundary_width << 1);
    client_event.xconfigure.height = h - (tmp_win->boundary_width << 1)
                                       - tmp_win->title_height;

    client_event.xconfigure.border_width = tmp_win->bw;

    /* Real ConfigureNotify events say we're above title window, so ... */
    /* what if we don't have a title ????? */

    client_event.xconfigure.above = tmp_win->frame;
    client_event.xconfigure.override_redirect = False;

    XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
    }

  BroadcastConfig (M_CONFIGURE_WINDOW, tmp_win);
}


/****************************************************************************
 *
 * Sets up the shaped window borders 
 * 
 ****************************************************************************/
void SetShape(FvwmWindow *tmp_win, int w)
{
#ifdef SHAPE
  if (ShapesSupported)
  {
    XRectangle rect;

    XShapeCombineShape (dpy, tmp_win->frame, ShapeBounding,
  		        tmp_win->boundary_width,
		        tmp_win->title_height + tmp_win->boundary_width,
		        tmp_win->w,
		        ShapeBounding, ShapeSet);
    if (tmp_win->title_w) 
      {
      /* windows w/ titles */
      rect.x = tmp_win->boundary_width;
      rect.y = tmp_win->title_y;
      rect.width  = w - (tmp_win->boundary_width << 1) + tmp_win->bw;
      rect.height = tmp_win->title_height;
      
      
      XShapeCombineRectangles(dpy, tmp_win->frame, ShapeBounding,
                              0, 0, &rect, 1, ShapeUnion, Unsorted);
      }
  }
#endif
}


syntax highlighted by Code2HTML, v. 0.9.1