const
  XV_NOFONT =	         1;  
  XV_NOMEM =	         2;  
  XV_NOXIMAGE =     	 3;  
  XV_VERSION     = 1.0;      
  XV_COPYRIGHT  =  'Copyright (c) ...';
type
  TRectangleList = specialize TFPGList<PXRectangle>;
  TXRectangleArray = array of TXRectangle;
  TBorderRectangleList = class(TRectangleList)
  public
    procedure appendRect(x, y, w, h: integer);
    function ToArray(AStartIndex, ALength: Integer): TXRectangleArray;
  end;
procedure TBorderRectangleList.appendRect(x, y, w, h: integer);
var
  r: PXRectangle;
begin
  r := GetMem(SizeOf(TXRectangle));
  r^.x := x;
  r^.y := y;
  r^.width := w;
  r^.height := h;
  Add(r);
end;
function TBorderRectangleList.ToArray(AStartIndex, ALength: Integer): TXRectangleArray;
var
  i: Integer;
begin
  SetLength(Result, ALength);
  for i := 0 to ALength - 1 do
    Result[i] := Items[i]^;
end;
constructor TFPWMBorder.Create(const c: TFPWMClient; child: TWindow);
var
  values: TXGCValues;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.Create] BEGIN');
  {$endif}
  inherited Create();
  m_client := c;
  m_child := child;
  m_tabHeight := -1;
  m_prevW := -1;
  m_prevH := -1;
  m_parent := root();
{$ifdef FPWM_ROTATED}
  if m_tabFont = nil then
  begin
    m_tabFont := XRotLoadFont(display(), CONFIG_NICE_FONT, 90.0);
    if m_tabFont = nil then
      m_tabFont := XRotLoadFont(display(), CONFIG_NASTY_FONT, 90.0);
    if m_tabFont = nil then
      windowManager().fatal('couldn''t load default rotated font, bailing out');
  end;
{$else}
  m_tabFont^.xfontstruct^.fid := XLoadFont(display(), CONFIG_NICE_FONT);
  if (m_tabFont^.xfontstruct^.fid = 0) then
  begin
    m_tabFont^.xfontstruct^.fid := XLoadFont(display(), CONFIG_NICE_FONT);
    if m_tabFont^.xfontstruct^.fid = 0 then
      m_tabFont^.xfontstruct^.fid := XLoadFont(display(), CONFIG_NASTY_FONT);
    if m_tabFont^.xfontstruct^.fid = 0 then
      windowManager().fatal('couldn''t load default font, bailing out');
  end;
{$endif}
  m_tabWidth := m_tabFont^.height + 4;
  if (m_tabWidth < TAB_TOP_HEIGHT * 2 + 8) then
  begin
    m_tabWidth := TAB_TOP_HEIGHT * 2 + 8;
  end;
  m_foregroundPixel := windowManager().allocateColour(CONFIG_TAB_FOREGROUND, 'tab foreground');
  m_backgroundPixel := windowManager().allocateColour(CONFIG_TAB_BACKGROUND, 'tab background');
  m_frameBackgroundPixel := windowManager().allocateColour(CONFIG_FRAME_BACKGROUND, 'frame background');
  m_buttonBackgroundPixel := windowManager().allocateColour(CONFIG_BUTTON_BACKGROUND, 'button background');
  m_borderPixel := windowManager().allocateColour(CONFIG_BORDERS, 'border');
  values.foreground := m_foregroundPixel;
  values.background := m_backgroundPixel;
  values._function := GXcopy;
  values.line_width := 0;
  values.subwindow_mode := IncludeInferiors;
  m_drawGC := XCreateGC(display(), root(),
    GCForeground or GCBackground or GCFunction or
    GCLineWidth or GCSubwindowMode,
    @values);
  if (m_drawGC = nil) then
  begin
    windowManager().fatal('couldn''t allocate border GC');
  end;
  Inc(borderCounter);
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.Create] END');
  {$endif}
end;
destructor TFPWMBorder.Destroy();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.Destroy]');
  {$endif}
  if (m_parent <> root()) then
  begin
    if (m_parent = 0) then
    begin
	Writeln('fpwm: zero parent in TFPWMBorder.Destroy');
    end
    else
    begin
	XDestroyWindow(display(), m_tab);
	XDestroyWindow(display(), m_button);
	XDestroyWindow(display(), m_parent);
	XDestroyWindow(display(), m_resize);
    end;
  end;
  Dec(borderCounter);
  if (borderCounter = 0) then
  begin
    XFreeGC(display(), m_drawGC);
  end;
  inherited Destroy;
end;
procedure TFPWMBorder.fatal(s: string);
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.fatal]');
  {$endif}
  windowManager().fatal(s);
end;
function TFPWMBorder.display(): PDisplay;
begin
  {$ifdef FPWM_TRACE_INLINES}
  FPWMTrace('[TFPWMBorder.display]');
  {$endif}
  Result := m_client.display();
end;
function TFPWMBorder.windowManager(): TFPWMWindowManager;
begin
  {$ifdef FPWM_TRACE_INLINES}
  FPWMTrace('[TFPWMBorder.windowManager]');
  {$endif}
  Result := m_client.windowManager();
end;
function TFPWMBorder.root(): TWindow;
begin
  {$ifdef FPWM_TRACE_INLINES}
  FPWMTrace('[TFPWMBorder.root]');
  {$endif}
  Result := m_client.root();
end;
procedure TFPWMBorder.expose_(e: PXExposeEvent);
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.expose_]');
  {$endif}
  if (e^.window <> m_tab) then Exit();
  drawLabel();
end;
procedure TFPWMBorder.drawLabel();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.drawLabel]');
  {$endif}
  {$ifdef FPWM_ROTATED}
  if (m_label <> '') then
  begin
    XClearWindow(display(), m_tab);
    XRotDrawString(display(), m_tabFont, m_tab, m_drawGC,
       2 + m_tabFont^.max_ascent, m_tabHeight - 1,
       m_label, Length(m_label));
  end;
  {$endif}
end;
function TFPWMBorder.isTransient(): Boolean;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.isTransient]');
  {$endif}
    Result := m_client.isTransient();
end;
function TFPWMBorder.isFixedSize(): Boolean;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.isFixedSize]');
  {$endif}
  Result := m_client.isFixedSize();
end;
procedure TFPWMBorder.fixTabHeight(maxHeight: cint);
var
  len: Integer;
  newLabel: string;
begin
  m_tabHeight := $7fff;
  Dec(maxHeight, m_tabWidth);	
  m_label := m_client.GetLabel();
  if (m_label <> '') then
      m_tabHeight :=
	  XRotTextWidth(m_tabFont, m_label, Length(m_label)) + 6 + m_tabWidth;
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format(
    '[TFPWMBorder.fixTabHeight] 1 m_tabHeight=%d maxHeight=%d m_label=%s',
    [m_tabHeight, maxHeight, m_label]));
  {$endif}
  if (m_tabHeight <= maxHeight) then Exit;
  if m_client.iconName() <> '' then
    m_label := m_client.iconName()
  else
    m_label := 'incognito';
  len := Length(m_label);
  m_tabHeight := XRotTextWidth(m_tabFont, m_label, len) + 6 + m_tabWidth;
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format(
    '[TFPWMBorder.fixTabHeight] 2 m_tabHeight=%d maxHeight=%d m_label=%s',
    [m_tabHeight, maxHeight, m_label]));
  {$endif}
  if (m_tabHeight <= maxHeight) then Exit;
      newlabel := m_label;
      newLabel := newLabel + '...';
      m_tabHeight := XRotTextWidth(m_tabFont, newLabel,
	  Length(newLabel)) + 6 + m_tabWidth;
  m_label := newLabel;
  if (m_tabHeight > maxHeight) then m_tabHeight := maxHeight;
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format('[TFPWMBorder.fixTabHeight] END m_tabHeight=%d m_label=%s',
    [m_tabHeight, m_label]));
  {$endif}
end;
procedure TFPWMBorder.shapeTransientParent(w, h: cint);
{$ifdef FPWM_ROTATED}
var
  r: TXRectangle;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.shapeTransientParent]');
  {$endif}
    r.x := xIndent() - 1; r.y := yIndent() - 1;
    r.width := w + 2; r.height := h + 2;
    XShapeCombineRectangles
	(display(), m_parent, ShapeBounding, 0, 0, @r, 1, ShapeSet, YXBanded);
    r.x := xIndent(); r.y := yIndent();
    r.width := w; r.height := h;
    XShapeCombineRectangles
	(display(), m_parent, ShapeClip, 0, 0, @r, 1, ShapeSet, YXBanded);
end;
{$else}
begin
end;
{$endif}
procedure TFPWMBorder.setTransientFrameVisibility(visible: Boolean; w, h: integer);
{$ifdef FPWM_ROTATED}
var
  i: integer;
  lShape: cint;
  rl: TBorderRectangleList;
  rects: TXRectangleArray;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.setTransientFrameVisibility]');
  {$endif}
  rl := TBorderRectangleList.Create;
  try
    rl.appendRect(0, 0, w + 1, yIndent() - 1);
    for i := 1 to yIndent()-1 do
      rl.appendRect(w + 1, i - 1, i + 1, 1);
    rl.appendRect(0, yIndent() - 1, xIndent() - 1, h - yIndent() + 2);
    for i := 1 to yIndent()-1 do
	  rl.appendRect(i - 1, h, 1, i + 2);
    if visible then lShape := ShapeUnion
    else lShape := ShapeSubtract;
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
      (display(), m_parent, ShapeBounding,
	   0, 0, @rects[0], rl.count,
	   lShape, YXSorted);
    rl.clear;
    rl.appendRect(1, 1, w, yIndent() - 2);
    for i := 2 to yIndent() - 1 do
	  rl.appendRect(w + 1, i - 1, i, 1);
    rl.appendRect(1, yIndent() - 1, xIndent() - 2, h - yIndent() + 1);
    for i := 2 to yIndent() - 1 do
	  rl.appendRect(i - 1, h, 1, i + 1);
    if visible then lShape := ShapeUnion
    else lShape := ShapeSubtract;
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
      (display(), m_parent, ShapeClip,
       0, 0, @rects[0], rl.count,
       lShape, YXSorted);
  finally
    rl.Free;
  end;
end;
{$else}
begin
end;
{$endif}
procedure TFPWMBorder.shapeParent(w, h: cint);
{$ifdef FPWM_ROTATED}
var
  i, mainRect: integer;
  rl: TBorderRectangleList;
  rects: TXRectangleArray;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format('[TFPWMBorder.shapeParent] m_tabWidth=%d', [m_tabWidth]));
  {$endif}
  rl := TBorderRectangleList.Create;
  try
    if (isTransient()) then
    begin
	shapeTransientParent(w, h);
	Exit();
    end;
    rl.appendRect(0, 0, w + m_tabWidth + 1, TAB_TOP_HEIGHT + 2);
    rl.appendRect(0, TAB_TOP_HEIGHT + 1,
		  TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
    rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT, TAB_TOP_HEIGHT + 1,
		  TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
    mainRect := rl.count;
    rl.appendRect(xIndent() - 1, yIndent() - 1, w + 2, h + 2);
    rl.appendRect(0, m_tabWidth - TAB_TOP_HEIGHT, m_tabWidth + 2,
	  m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT);
    for i := 1 to m_tabWidth - 2 do
	rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_parent, ShapeBounding,
	 0, 0, @rects[0], rl.count, ShapeSet, YXSorted);
    Inc(rl.items[mainRect]^.x);
    Inc(rl.items[mainRect]^.y);
    Dec(rl.items[mainRect]^.width, 2);
    Dec(rl.items[mainRect]^.height, 2);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_parent, ShapeClip,
	 0, 0, @rects[0], rl.count, ShapeSet, YXSorted);
  finally
    rl.Free;
  end;
end;
{$else}
begin
  XResizeWindow(display(), m_parent, w + 8, h + 8);
end;
{$endif}
procedure TFPWMBorder.shapeTab(w, h: cint);
{$ifdef FPWM_ROTATED}
var
  i: integer;
  rl: TBorderRectangleList;
  rects: TXRectangleArray;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format('[TFPWMBorder.shapeTab] m_tabWidth=%d', [m_tabWidth]));
  {$endif}
  rl := TBorderRectangleList.Create;
  try
    if (isTransient()) then
    begin
	Exit();
    end;
    rl.appendRect(0, 0, w + m_tabWidth + 1, TAB_TOP_HEIGHT + 2);
    rl.appendRect(0, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 2,
		  m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
    rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT, TAB_TOP_HEIGHT + 1,
		  TAB_TOP_HEIGHT + 2, m_tabWidth - TAB_TOP_HEIGHT*2 - 1);
    rl.appendRect(0, m_tabWidth - TAB_TOP_HEIGHT, m_tabWidth + 2,
		  m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT);
    for i := 1 to m_tabWidth - 2 do
	rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_tab, ShapeBounding,
	 0, 0, @rects[0], rl.count, ShapeSet, YXSorted);
    rl.Clear;
    rl.appendRect(1, 1, w + m_tabWidth - 1, TAB_TOP_HEIGHT);
    rl.appendRect(1, TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT,
		  m_tabWidth + TAB_TOP_HEIGHT*2 - 1);
    rl.appendRect(m_tabWidth - TAB_TOP_HEIGHT + 1, TAB_TOP_HEIGHT + 1,
		  TAB_TOP_HEIGHT, m_tabWidth + TAB_TOP_HEIGHT*2 - 1);
    rl.appendRect(1, m_tabWidth - TAB_TOP_HEIGHT + 1, m_tabWidth,
		  m_tabHeight - m_tabWidth + TAB_TOP_HEIGHT - 1);
    for i := 1 to m_tabWidth - 3 do
		rl.appendRect(i + 1, m_tabHeight + i - 1, m_tabWidth - i, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_tab, ShapeClip,
	 0, 0, @rects[0], rl.count, ShapeSet, YXSorted);
  finally
    rl.Free;
  end;
end;
{$else}
begin
end;
{$endif}
procedure TFPWMBorder.resizeTab(h: cint);
{$ifdef FPWM_ROTATED}
var
  i, shorter, longer, operation, prevTabHeight: integer;
  r: TXRectangle;
  rl: TBorderRectangleList;
  wc: TXWindowChanges;
  rects: TXRectangleArray;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.resizeTab]');
  {$endif}
  rl := TBorderRectangleList.Create;
  try
    if isTransient() then Exit();
    prevTabHeight := m_tabHeight;
    fixTabHeight(h);
    if (m_tabHeight = prevTabHeight) then Exit();
    wc.height := m_tabHeight + 2 + m_tabWidth;
    XConfigureWindow(display(), m_tab, CWHeight, @wc);
    if (m_tabHeight > prevTabHeight) then 
    begin
	shorter := prevTabHeight;
	longer := m_tabHeight;
	operation := ShapeUnion;
    end
    else
    begin
	shorter := m_tabHeight;
	longer := prevTabHeight + m_tabWidth;
	operation := ShapeSubtract;
    end;
    r.x := 0; r.y := shorter ;
    r.width := m_tabWidth + 2; r.height := longer - shorter;
    XShapeCombineRectangles(display(), m_parent, ShapeBounding,
			    0, 0, @r, 1, operation, YXBanded);
    XShapeCombineRectangles(display(), m_parent, ShapeClip,
			    0, 0, @r, 1, operation, YXBanded);
    XShapeCombineRectangles(display(), m_tab, ShapeBounding,
			    0, 0, @r, 1, operation, YXBanded);
    Inc(r.x);
    Dec(r.width, 2);
    XShapeCombineRectangles(display(), m_tab, ShapeClip,
			    0, 0, @r, 1, operation, YXBanded);
    if (m_client.isActive()) then
    begin
	r.x := m_tabWidth + 1;
        r.y := shorter;
	r.width := FRAME_WIDTH - 1;
        r.height := longer - shorter;
	XShapeCombineRectangles(display(), m_parent, ShapeBounding,
		0, 0, @r, 1, ShapeUnion, YXBanded);
    end;
    for i := 1 to m_tabWidth - 2 do
	rl.appendRect(i, m_tabHeight + i - 1, m_tabWidth - i + 2, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_parent, ShapeBounding,
	 0, 0, @rects[0], rl.count, ShapeUnion, YXBanded);
    XShapeCombineRectangles
	(display(), m_parent, ShapeClip,
	 0, 0, @rects[0], rl.count, ShapeUnion, YXBanded);
    XShapeCombineRectangles
	(display(), m_tab, ShapeBounding,
	 0, 0, @rects[0], rl.count, ShapeUnion, YXBanded);
    if (rl.count < 2) then Exit();
    for i := 0 to rl.count - 2 do
    begin
    	Inc(rl.items[i]^.x);
        Dec(rl.items[i]^.width, 2);
    end;
    rects := rl.ToArray(0, rl.count - 1);
    XShapeCombineRectangles
	(display(), m_tab, ShapeClip,
	 0, 0, @rects[0], rl.count - 1,
	 ShapeUnion, YXBanded);
  finally
    rl.Free
  end;
end;
{$else}
begin
end;
{$endif}
procedure TFPWMBorder.shapeResize();
{$ifdef FPWM_ROTATED}
var
  i: integer;
  rl: TBorderRectangleList;
  rects: TXRectangleArray;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.shapeResize]');
  {$endif}
  rl := TBorderRectangleList.Create;
  try
    for i := 0 to FRAME_WIDTH*2 - 1 do
	rl.appendRect(FRAME_WIDTH*2 - i - 1, i, i + 1, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_resize, ShapeBounding, 0, 0,
	 @rects[0], rl.count, ShapeSet, YXBanded);
    rl.Clear;
    for i := 1 to FRAME_WIDTH*2 - 1 do
	rl.appendRect(FRAME_WIDTH*2 - i, i, i, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_resize, ShapeClip, 0, 0,
	 @rects[0], rl.count, ShapeSet, YXBanded);
    rl.Clear; 
    for i := 0 to FRAME_WIDTH*2 - 4 do
	rl.appendRect(FRAME_WIDTH*2 - i - 1, i + 3, 1, 1);
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles
	(display(), m_resize, ShapeClip, 0, 0,
	 @rects[0], rl.count, ShapeSubtract, YXBanded);
    windowManager().installCursorOnWindow(DownrightCursor, m_resize);
  finally
    rl.Free;
  end;
end;
{$else}
begin
end;
{$endif}
procedure TFPWMBorder.setFrameVisibility(visible: Boolean; w, h: integer);
var
  ww: integer;
  rl: TBorderRectangleList;
  final, lShape: cint;
  rects: TXRectangleArray;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format('[TFPWMBorder.setFrameVisibility] m_tabHeight=%d', [m_tabHeight]));
  {$endif}
  if (CONFIG_PROD_SHAPE) then
  begin
    shapeParent(w, h);
    shapeTab(w, h);
  end;
  if (isTransient()) then
  begin
    setTransientFrameVisibility(visible, w, h);
    Exit;
  end;
  rl := TBorderRectangleList.Create;
  try
    rl.appendRect(m_tabWidth + w + 1, 0, FRAME_WIDTH + 1, FRAME_WIDTH);
    rl.appendRect(m_tabWidth + 2, TAB_TOP_HEIGHT + 2, w,
	  FRAME_WIDTH - TAB_TOP_HEIGHT - 2);
    ww := m_tabWidth - TAB_TOP_HEIGHT*2 - 4;
    rl.appendRect((m_tabWidth + 2 - ww) div 2, (m_tabWidth+2 - ww) div 2, ww, ww);
    rl.appendRect(m_tabWidth + 2, FRAME_WIDTH,
		  FRAME_WIDTH - 2, m_tabHeight + m_tabWidth - FRAME_WIDTH - 2);
    if (rl.items[rl.count-2]^.y > rl.items[rl.count-1]^.y) then
    begin
        rl.add(rl.items[rl.count-2]);
        rl.Delete(rl.count-3);
    end;
    final := rl.count;
    rl.add(rl.items[final-1]);
    Dec(rl.items[final]^.x);
    Inc(rl.items[final]^.y, rl.items[final]^.height);
    Inc(rl.items[final]^.width);
    rl.items[final]^.height := h - rl.items[final]^.height + 2;
    if visible then lShape := ShapeUnion
    else lShape := ShapeSubtract;
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles(display(), m_parent, ShapeBounding,
	    0, 0, @rects[0], rl.count,
	    lShape, YXSorted);
    rl.Clear();
    rl.appendRect(m_tabWidth + w + 1, 1, FRAME_WIDTH, FRAME_WIDTH - 1);
    rl.appendRect(m_tabWidth + 2, TAB_TOP_HEIGHT + 2, w,
	  FRAME_WIDTH - TAB_TOP_HEIGHT - 2);
    ww := m_tabWidth - TAB_TOP_HEIGHT*2 - 6;
    rl.appendRect((m_tabWidth + 2 - ww) div 2, (m_tabWidth+2 - ww) div 2, ww, ww);
    rl.appendRect(m_tabWidth + 2, FRAME_WIDTH,
		  FRAME_WIDTH - 2, h - FRAME_WIDTH);
    if (rl.items[rl.count-2]^.y > rl.items[rl.count-1]^.y) then
    begin
        rl.add(rl.items[rl.count-2]);
        rl.delete(rl.count-3);
    end;
    rl.appendRect(m_tabWidth + 2, h, FRAME_WIDTH - 2, FRAME_WIDTH + 1);
    if visible then lShape := ShapeUnion
    else lShape := ShapeSubtract;
    rects := rl.ToArray(0, rl.count);
    XShapeCombineRectangles(display(), m_parent, ShapeClip,
			    0, 0, @rects[0], rl.count,
			    lShape, YXSorted);
  finally
    rl.Free;
  end;
  if (visible and (not isFixedSize())) then
      XMapRaised(display(), m_resize)
  else
      XUnmapWindow(display(), m_resize);
end;
procedure TFPWMBorder.configure(x, y, w, h: cint;
  mask: culong; detail: cint;
  force: Boolean); 
var
  prevTabHeight: integer;
  wc: TXWindowChanges;
  rmask: culong = 0;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.configure] BEGIN');
  {$endif}
    if ((m_parent = 0) or (m_parent = root())) then
    begin
	m_parent := XCreateSimpleWindow
	    (display(), root(), 1, 1, 1, 1, 0,
	     m_borderPixel, m_frameBackgroundPixel);
    	m_tab := XCreateSimpleWindow
	    (display(), m_parent, 1, 1, 1, 1, 0,
	     m_borderPixel, m_backgroundPixel);
	m_button := XCreateSimpleWindow
	    (display(), m_parent, 1, 1, 1, 1, 0,
	     m_borderPixel, m_buttonBackgroundPixel);
	m_resize := XCreateWindow
	    (display(), m_child, 1, 1, FRAME_WIDTH*2, FRAME_WIDTH*2, 0,
	     CopyFromParent, InputOutput, PVisual(CopyFromParent), 0, nil);
        shapeResize();
	XSelectInput(display(), m_parent,
		     SubstructureRedirectMask or SubstructureNotifyMask or
		     ButtonPressMask or ButtonReleaseMask);
	if (not isTransient()) then
	begin
	    XSelectInput(display(), m_tab,
			 ExposureMask or ButtonPressMask or ButtonReleaseMask or
			 EnterWindowMask);
	end;
	XSelectInput(display(), m_button,
		     ButtonPressMask or ButtonReleaseMask);
	XSelectInput(display(), m_resize, ButtonPressMask or ButtonReleaseMask);
	mask := mask or (CWX or CWY or CWWidth or CWHeight or CWBorderWidth);
    end;
    wc.x := x - xIndent();
    wc.y := y - yIndent();
    wc.width  := w + xIndent() + 1;
    wc.height := h + yIndent() + 1;
    wc.border_width := 0;
    wc.sibling := None;
    wc.stack_mode := detail;
    XConfigureWindow(display(), m_parent, mask, @wc);
    rmask := 0;
    if (mask and CWWidth) <> 0 then rmask := rmask or CWX;
    if (mask and CWHeight) <> 0 then rmask := rmask or CWY;
    wc.x := w - FRAME_WIDTH*2;
    wc.y := h - FRAME_WIDTH*2;
    XConfigureWindow(display(), m_resize, rmask, @wc);
  if force or ((m_prevW < 0) or (m_prevH < 0)) or
	(((mask and (CWWidth or CWHeight)) <> 0) and
        ((w <> m_prevW) or (h <> m_prevH))) then
  begin
    prevTabHeight := m_tabHeight;
    if (isTransient()) then m_tabHeight := 10 
    else fixTabHeight(h);
    shapeParent(w, h);
    setFrameVisibility(m_client.isActive(), w, h);
    if force or (prevTabHeight <> m_tabHeight) or (m_prevW < 0) or (m_prevH < 0) then
    begin
      wc.x := 0;
      wc.y := 0;
      wc.width := w + xIndent();
      wc.height := m_tabHeight + 2 + m_tabWidth;
      {$ifdef FPWM_TRACE}
      FPWMTrace(Format(
        '[TFPWMBorder.configure] XConfigureWindow m_tab wc.width=%d wx.height=%d',
        [wc.width, wc.height]));
      {$endif}
      XConfigureWindow(display(), m_tab, mask, @wc);
      shapeTab(w, h);
    end;
    m_prevW := w;
    m_prevH := h;
  end
  else
    resizeTab(h);
  wc.x := TAB_TOP_HEIGHT + 2;
  wc.y := wc.x;
  wc.height := m_tabWidth - TAB_TOP_HEIGHT*2 - 4;
  wc.width := wc.height;
  {$ifdef FPWM_TRACE}
  FPWMTrace(Format('[TFPWMBorder.configure] XConfigureWindow m_button x=%d y=%d w=%d h=%d m_tabWidth=%d TAB_TOP_HEIGHT=%d',
    [wc.x, wc.y, wc.width, wc.height, m_tabWidth, TAB_TOP_HEIGHT]));
  {$endif}
  XConfigureWindow(display(), m_button, mask, @wc);
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.configure] END');
  {$endif}
end;
procedure TFPWMBorder.moveTo(x, y: integer);
var
  wc: TXWindowChanges;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.moveTo]');
  {$endif}
  wc.x := x - xIndent();
  wc.y := y - yIndent();
  XConfigureWindow(display(), m_parent, CWX or CWY, @wc);
end;
procedure TFPWMBorder.map();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.map]');
  {$endif}
  if (m_parent = root()) then
  begin
    writeln('fpwm: bad parent in Border.map()');
  end
  else
  begin
    XMapWindow(display(), m_parent);
    if (not isTransient()) then
    begin
      XMapWindow(display(), m_tab);
      XMapWindow(display(), m_button);
      if (not isFixedSize()) then XMapWindow(display(), m_resize);
    end;
  end;
end;
procedure TFPWMBorder.mapRaised();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.mapRaised]');
  {$endif}
  if (m_parent = root()) then
  begin
    writeln('fpwm: bad parent in TFPWMBorder.mapRaised()');
  end
  else
  begin
    XMapRaised(display(), m_parent);
    if (not isTransient()) then
    begin
      XMapWindow(display(), m_tab);
      XMapRaised(display(), m_button);
      if (not isFixedSize()) then XMapRaised(display(), m_resize);
    end;
  end;
end;
procedure TFPWMBorder.lower();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.lower]');
  {$endif}
    XLowerWindow(display(), m_parent);
end;
procedure TFPWMBorder.unmap();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.unmap]');
  {$endif}
  if (m_parent = root()) then
  begin
    writeln('fpwm: bad parent in Border.unmap()');
  end
  else
  begin
    XUnmapWindow(display(), m_parent);
    if (not isTransient()) then
    begin
      XUnmapWindow(display(), m_tab);
      XUnmapWindow(display(), m_button);
    end;
  end;
end;
procedure TFPWMBorder.decorate(active: Boolean; w, h: integer);
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.decorate]');
  {$endif}
  setFrameVisibility(active, w, h);
end;
procedure TFPWMBorder.reparent();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMBorder.reparent]');
  {$endif}
  XReparentWindow(display(), m_child, m_parent, xIndent(), yIndent());
end;