/* $Id: ps_build.c,v 1.2 90/11/29 18:32:56 altenhof Exp $ */

/*
 * Copyright (C) 1990 by Digital Equipment Corporation.
 * 
 * Author: Michael P. Altenhofen, CEC Karlsruhe e-mail:
 * Altenhofen@kampus.enet.dec.com
 * 
 * This file ist part of Shared X
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation without fee is hereby granted, but only for non-profit  use
 * and distribution,  and provided  that the copyright notice and this notice
 * is preserved on all copies.
 * 
 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#define PUBLIC extern

#define _USE_STRUCTS_
#define _USE_PROTO_

#include "glob.h"

#include "utils.h"

#undef PUBLIC

#include <X11/Xatom.h>

int Dec_Wm_Hints, Dec_Wm_Decoration_Geometry;

/* -- some definitions for BuildColor -- */
#define ColPixel   (1L<<0)
#define ColRed     (1L<<1)
#define ColGreen   (1L<<2)
#define ColBlue    (1L<<3)
#define ColFlags   (1L<<4)

void
PSBuildProperty (type, property, units, connection, from_where)
  Atom type;			/* the property type */
  char *property;		/* the data */
  int units;			/* the number of data units */
  int connection;		/* in case we have to map ID's that lurk in
				 * the data */
  int from_where;		/* is it an ID from the server or from the
				 * client */
{
  /* we only check "long" (4 byte) properties and assume that
   *  unsigned longs are 4 bytes long */
  register unsigned long *pbuf = (unsigned long *) property;
  register int i;

  /*
   * As you can see by the switch statement: this procedure is restricted to
   * predefined atoms and DEC_WM_HINTS / DEC_WM_DECORATION_GEOMETRY (which
   * are flaged by variables) and does the mapping in a hardcoded way. We
   * can't solve this problem in a generic way but there exists  a
   * "probabilistic solution": use the structure of X's resource ID's; a
   * (valid) ID has at least one of it's 13 high bits set (hope that the
   * protocol won't change that!), so a property value with one of these bits
   * set will "probably" be an ID:
   *    for (i = 0 ; i < units ; i++ , pbuf++)
   *      if (*pbuf & 0xfff80000)
   *        *pbuf = MapID (*pbuf , connection , from_where);
   * maybe we use it next time
   */

  switch (type) {
  case XA_BITMAP:
  case XA_COLORMAP:
  case XA_CURSOR:
  case XA_DRAWABLE:
  case XA_FONT:
  case XA_PIXMAP:
  case XA_VISUALID:
  case XA_WINDOW:
  case XA_WM_TRANSIENT_FOR:
    /* -- these properties should be of size 1 -- */
    *pbuf = MapID (*pbuf, connection, from_where);
    break;

  case XA_RGB_COLOR_MAP:
  case XA_RGB_BEST_MAP:
  case XA_RGB_BLUE_MAP:
  case XA_RGB_DEFAULT_MAP:
  case XA_RGB_GRAY_MAP:
  case XA_RGB_GREEN_MAP:
  case XA_RGB_RED_MAP:
    /* we have to rely on ../X11/server/dix/BuiltInAtoms */
    *pbuf = MapID (*pbuf, connection, from_where);
    break;

  case XA_WM_HINTS:
    /* -- according to ../X11/server/dix/BuiltInAtoms .. -- */
    /* -- unit 4 contains the icon-pixmap ID ... -- */
    pbuf[3] = MapID (pbuf[3], connection, from_where);
    /* -- unit 5 the icon-window ID ... -- */
    pbuf[4] = MapID (pbuf[4], connection, from_where);
    /* -- and unit 6 the icon-mask bitmap ID -- */
    pbuf[5] = MapID (pbuf[5], connection, from_where);
    break;

  default:
    /* -- Handle DEC wm hints and decoration geom here -- */
    if (type == Dec_Wm_Hints)
      /* -- unit 2 is the iconify-pixmap ID ( cf. DECWmHints.h ) -- */
      pbuf[1] = MapID (pbuf[1], connection, from_where);
    else if (type == Dec_Wm_Decoration_Geometry) {
      /* -- title font -- */
      pbuf[0] = MapID (pbuf[0], connection, from_where);
      /* -- icon font -- */
      pbuf[1] = MapID (pbuf[1], connection, from_where);
    }
  }
}

/* -- Do you know another way ?  -- */

void
PSImageStripOffPadBytes (image, pad_bytes)
  XImage *image;
  int pad_bytes;
{
  char *buf;
  register int num_lines, bytes_per_line, i;

  num_lines = image->height;
  bytes_per_line = image->bytes_per_line;

  if (image->format == ZPixmap)
    buf =
      (char *) Xmalloc (num_lines * bytes_per_line);
  else
    buf =
      (char *) Xmalloc (image->depth * num_lines * bytes_per_line);

  if (buf != NULL) {
    if (image->format == ZPixmap)
      for (i = 0; i < num_lines; i++)
	bcopy (image->data + i * (bytes_per_line + pad_bytes),
	       buf + i * bytes_per_line, bytes_per_line);
    else
      bcopy (image->data, buf, image->depth * num_lines * bytes_per_line);

    /*
     * for( i = 0 ; i < image->depth; i++) bcopy( image->data + i * (
     * pad_bytes + (bytes_per_line * num_lines)), buf + i * bytes_per_line *
     * num_lines, bytes_per_line * num_lines);
     */
    image->data = buf;
  }
}

#define FontShiftSize  5
#define TextEltHeader  2

static int padlength[4] =
{0, 3, 2, 1};

XTextItem *
PSBuildTextItems (req, conn, n)
  xPolyTextReq *req;
  int conn;
  int *n;
{
  register int i, j;
  XTextItem *items;
  register unsigned char *pBuf;
  unsigned char *endReq, *pNextElt;

  i = 0;
  *n = 0;
  pBuf = (unsigned char *) &req[1];
  endReq = ((unsigned char *) req) + (req->length << 2);

  if ((items = (XTextItem *)
       Xmalloc (sizeof (XTextItem))) == NULL)
    return ((XTextItem *) NULL);

  /*
   * Another "hard stuff" routine: if you read the protocol encoding, delta
   * is defined as INT8, which means a signed byte. This would restrict delta
   * to values between -128 and 127. This is the "dirty hack" Xlib uses to
   * allow greater delta values: encode the delta value in a sequence of
   * xTextElt items with len set to 0 and delta set to the apropriate portion
   * of the delta.
   * 
   * And what about padding bytes? They're padded and the end of the request
   * and there may be three of them, so testing (endReq - pBuf > TextEltHeader)
   * could fail. If there is another text item following, there will be at
   * least 4 bytes!
   */

  while (endReq - pBuf > TextEltHeader + 1) {

    (*n)++;
    if (*n > 1)
      if ((items = (XTextItem *)
	   Xrealloc (items, *n * sizeof (XTextItem))) == NULL) {
	ErrorF ("Out of memory!\n");
	*n = 0;
	return ((XTextItem *) NULL);
      }
    items[i].nchars = 0;
    items[i].delta = 0;
    items[i].chars = NULL;
    if (*pBuf == FontChange) {	/* -- it's a font -- */
      items[i].font = ((XID) * (pBuf + 4))
	| ((XID) * (pBuf + 3)) << 8
	| ((XID) * (pBuf + 2)) << 16
	| ((XID) * (pBuf + 1)) << 24;
      /* -- map it -- */
      items[i].font = MapID (items[i].font, conn, FromClient);
      debug (_debug_requests, " font 0x%lx ", items[i].font);
      pBuf += FontShiftSize;
    }
    else {
      register int n_chars;

      /*
       * First comes the delta (first byte of xTextElt == 0).  If
       * there is one, may be more than one xTextElt to allow greater
       * delta values (see above)
       */
      items[i].delta = 0;
      while (!*pBuf) {
	/* -- skip over null byte -- */
	*pBuf++;
	items[i].delta += *pBuf++;
	/* -- adjust pointer to next text item -- */
	/* -- pNextElt = pBuf + TextEltHeader ;	-- */
	pBuf += TextEltHeader;
      }
      /* -- adjust pointer to next text item -- */
      pNextElt = pBuf + TextEltHeader + (*pBuf);
      items[i].nchars = n_chars = (int) *pBuf++;
      debug (_debug_requests, " %d chars: \"", items[i].nchars);
      /* -- last delta amount for this text item -- */
      items[i].delta += (INT8) * pBuf++;
      if ((items[i].chars =
	   (char *) Xmalloc (n_chars)) == NULL) {
	ErrorF ("Out of memory!\n");
	*n = 0;
	return ((XTextItem *) NULL);
      }
      for (j = 0; j < n_chars; j++) {
	debug (_debug_requests, "%c", *pBuf);
	items[i].chars[j] = *pBuf++;
      }
      debug (_debug_requests, "\"");
      items[i].font = None;
      pBuf = pNextElt;
    }
    i++;
  }
  return (items);
}

XTextItem16 *
PSBuildTextItems16 (req, conn, n16)
  xPolyText16Req *req;
  int conn;
  int *n16;
{
  register int i, j;
  XTextItem16 *items;
  register unsigned char *pBuf;
  unsigned char *endReq, *pNextElt;

  i = 0;
  *n16 = 0;
  pBuf = (unsigned char *) &req[1];
  endReq = ((unsigned char *) req) + (req->length << 2);

  /*
   * -- take care of pad bytes
   */
  endReq -= padlength[(endReq - pBuf) & 3];

  if ((items = (XTextItem16 *)
       Xmalloc (sizeof (XTextItem16))) == NULL)
    return ((XTextItem16 *) NULL);

  /*
   * Another "hard stuff" routine: if you read the protocol encoding, delta
   * is defined as INT8, which means a signed byte. This would restrict delta
   * to values between -128 and 127. This is the "dirty hack" Xlib uses to
   * allow greater delta values: encode the delta value in a sequence of
   * xTextElt items with len set to 0 and delta set to the apropriate portion
   * of the delta.
   */

  while (endReq - pBuf > TextEltHeader) {
    (*n16)++;
    if (*n16 > 1)
      if ((items = (XTextItem16 *)
	   Xrealloc (items, *n16 * sizeof (XTextItem16))) == NULL) {
	*n16 = 0;
	return ((XTextItem16 *) NULL);
      }
    items[i].nchars = 0;
    items[i].delta = 0;
    items[i].chars = NULL;
    if (*pBuf == FontChange) {	/* it's a font */
      items[i].font =
	  ((XID) * (pBuf + 4))
	| ((XID) * (pBuf + 3)) << 8
	| ((XID) * (pBuf + 2)) << 16
	| ((XID) * (pBuf + 1)) << 24;
      /* map it */
      items[i].font = MapID (items[i].font, conn, FromClient);
      debug (_debug_requests, " font %d ", items[i].font);
      pBuf += FontShiftSize;
    }
    else {
      register int n_chars;

      /*
       * First comes the delta (first byte of xTextElt == 0).  If
       * there is one, may be more than one xTextElt to allow greater
       * delta values (see above)
       */
      items[i].delta = 0;
      while (!*pBuf) {
	/* -- skip over null byte -- */
	*pBuf++;
	items[i].delta += *pBuf++;
	/* -- adjust pointer to next text item -- */
	pNextElt = pBuf + TextEltHeader;

      }
      /* -- adjust pointer to next text item -- */
      pNextElt = pBuf + TextEltHeader + 2 * (*pBuf);
      items[i].nchars = n_chars = (int) *pBuf++;

      debug (_debug_requests, " %d chars ", items[i].nchars);
      /* -- last delta amount for this text item -- */
      items[i].delta += (INT8) * pBuf++;

      if ((items[i].chars = (XChar2b *)
	   Xmalloc (n_chars * sizeof (XChar2b))) ==
	  (XChar2b *) NULL) {
	ErrorF ("Out of memory!\n");
	*n16 = 0;
	return ((XTextItem16 *) NULL);
      }

      for (j = 0; j < n_chars; j++) {
	items[i].chars[j].byte1 = *pBuf++;
	items[i].chars[j].byte2 = *pBuf++;
      }
      items[i].font = None;
      pBuf = pNextElt;
    }
    i++;
  }
  return (items);
}

#undef TextEltHeader
#undef FontShiftSize

void
PSBuildColors (mask, req, colors, n)
  Mask mask;
  xQueryColorsReq *req;
  XColor *colors;
  int n;
{
  register unsigned long *pbuf = (unsigned long *) req;
  register int i;

  for (i = 0; i < n; i++) {
    if (mask & ColPixel)
      colors[i].pixel = *pbuf++;
    if (mask & ColRed)
      colors[i].red = *pbuf++;
    if (mask & ColGreen)
      colors[i].green = *pbuf++;
    if (mask & ColBlue)
      colors[i].blue = *pbuf++;
    if (mask & ColFlags)
      colors[i].flags = *pbuf++;
  }
}

void
PSBuildWindowChanges (mask, req, changes, connection)
  Mask mask;
  xConfigureWindowReq *req;
  XWindowChanges *changes;
  int connection;		/* if we have to map ID's */
{
  register unsigned long *pbuf = (unsigned long *) req;

  debug (_debug_requests, "Mask : %lx\n", mask);
  if (mask & CWX) {
    changes->x = *pbuf++;
    debug (_debug_requests, "WCh x : %d ", changes->x);
  }
  if (mask & CWY) {
    changes->y = *pbuf++;
    debug (_debug_requests, "WCh y : %d ", changes->y);
  }
  if (mask & CWWidth) {
    changes->width = *pbuf++;
    debug (_debug_requests, "WCh width  : %d ", changes->width);
  }
  if (mask & CWHeight) {
    changes->height = *pbuf++;
    debug (_debug_requests, "WCh height : %d ", changes->height);
  }
  if (mask & CWBorderWidth) {
    changes->border_width = *pbuf++;
    debug (_debug_requests, "WCh b_width : %d ", changes->width);
  }
  if (mask & CWSibling) {
    changes->sibling = *pbuf++;
    /* -- sibling is a window ID --> map it -- */
    changes->sibling = MapID (changes->sibling, connection, FromClient);
    debug (_debug_requests, "WCh sibling: 0x%lx ", changes->sibling);
  }
  if (mask & CWStackMode) {
    changes->stack_mode = *pbuf++;
    debug (_debug_requests, "WCh stack mode : %d ", changes->stack_mode);
  }
  debug (_debug_requests, "\n");
}

void
PSBuildKeyboardControl (mask, req, kb_control)
  Mask mask;
  xChangeKeyboardControlReq *req;
  XKeyboardControl *kb_control;
{
  register unsigned long *pbuf = (unsigned long *) req;

  debug (_debug_requests, "mask : %lx\n", mask);
  if (mask & KBKeyClickPercent) {
    kb_control->key_click_percent = *pbuf++;
    debug (_debug_requests, "KBC key_cl_perc : %u ",
	   kb_control->key_click_percent);
  }
  if (mask & KBBellPercent) {
    kb_control->bell_percent = *pbuf++;
    debug (_debug_requests, "KBC bell_perc : %u ",
	   kb_control->bell_percent);
  }
  if (mask & KBBellPitch) {
    kb_control->bell_pitch = *pbuf++;
    debug (_debug_requests, "KBC bell_pitch : %u ",
	   kb_control->bell_pitch);
  }
  if (mask & KBBellDuration) {
    kb_control->bell_duration = *pbuf++;
    debug (_debug_requests, "KBC bell_dur : %u ",
	   kb_control->bell_duration);
  }
  if (mask & KBLed) {
    kb_control->led = *pbuf++;
    debug (_debug_requests, "KBC led : %u ",
	   kb_control->led);
  }
  if (mask & KBLedMode) {
    kb_control->led_mode = *pbuf++;
    debug (_debug_requests, "KBC led_mode : %u ",
	   kb_control->led_mode);
  }
  if (mask & KBKey) {
    kb_control->key = *pbuf++;
    debug (_debug_requests, "KBC key : %u ",
	   kb_control->key);
  }
  if (mask & KBAutoRepeatMode) {
    kb_control->auto_repeat_mode = *pbuf++;
    debug (_debug_requests, "KBC auto_rep : %u ",
	   kb_control->auto_repeat_mode);
  }
  debug (_debug_requests, "\n");
}

void
PSBuildGCValues (valuemask, req, values, connection)
  Mask valuemask;
  xCreateGCReq *req;
  XGCValues *values;
  int connection;		/* if we have to map ID's */
{
  register unsigned long *pbuf = (unsigned long *) req;

  debug (_debug_requests, "Mask : %lx\n", valuemask);
  if (valuemask & GCFunction) {
    values->function = *pbuf++;
    debug (_debug_requests, "GC function :%u ", values->function);
  }
  if (valuemask & GCPlaneMask) {
    values->plane_mask = *pbuf++;
    debug (_debug_requests, "GC plane mask :%lx ", values->plane_mask);
  }
  if (valuemask & GCForeground) {
    values->foreground = *pbuf++;
    debug (_debug_requests, "GC foreground :%u ", values->foreground);
  }
  if (valuemask & GCBackground) {
    values->background = *pbuf++;
    debug (_debug_requests, "GC background :%u ", values->background);
  }
  if (valuemask & GCLineWidth) {
    values->line_width = *pbuf++;
    debug (_debug_requests, "GC line width :%u ", values->line_width);
  }
  if (valuemask & GCLineStyle) {
    values->line_style = *pbuf++;
    debug (_debug_requests, "GC line style :%u ", values->line_style);
  }
  if (valuemask & GCCapStyle) {
    values->cap_style = *pbuf++;
    debug (_debug_requests, "GC cap style :%u ", values->cap_style);
  }
  if (valuemask & GCJoinStyle) {
    values->join_style = *pbuf++;
    debug (_debug_requests, "GC join style :%u ", values->join_style);
  }
  if (valuemask & GCFillStyle) {
    values->fill_style = *pbuf++;
    debug (_debug_requests, "GC fill style :%u ", values->fill_style);
  }
  if (valuemask & GCFillRule) {
    values->fill_rule = *pbuf++;
    debug (_debug_requests, "GC fill rule :%u ", values->fill_rule);
  }
  if (valuemask & GCTile) {
    values->tile = *pbuf++;
    /* -- tile is a pixmap ID -> map it -- */
    values->tile = MapID (values->tile, connection, FromClient);
    debug (_debug_requests, "GC tile pixmap :0x%lx ", values->tile);
  }
  if (valuemask & GCStipple) {
    values->stipple = *pbuf++;
    /* -- stipple is a pixmap ID -> map it -- */
    values->stipple = MapID (values->stipple, connection, FromClient);
    debug (_debug_requests, "GC stipple pixmap :0x%lx ", values->stipple);
  }
  if (valuemask & GCTileStipXOrigin) {
    values->ts_x_origin = *pbuf++;
    debug (_debug_requests, "GC ts x orig :%u ", values->ts_x_origin);
  }
  if (valuemask & GCTileStipYOrigin) {
    values->ts_y_origin = *pbuf++;
    debug (_debug_requests, "GC ts y orig :%u ", values->ts_y_origin);
  }
  if (valuemask & GCFont) {
    values->font = *pbuf++;
    /* -- font is an font ID -> map it -- */
    values->font = MapID (values->font, connection, FromClient);
    debug (_debug_requests, "GC font :0x%lx ", values->font);
  }
  if (valuemask & GCSubwindowMode) {
    values->subwindow_mode = *pbuf++;
    debug (_debug_requests, "GC subwindow mode :%u ", values->subwindow_mode);
  }
  if (valuemask & GCGraphicsExposures) {
    values->graphics_exposures = *pbuf++;
    debug (_debug_requests, "GC gr exposures :%u ", values->graphics_exposures);
  }
  if (valuemask & GCClipXOrigin) {
    values->clip_x_origin = *pbuf++;
    debug (_debug_requests, "GC clip x orig :%u ", values->clip_x_origin);
  }
  if (valuemask & GCClipYOrigin) {
    values->clip_y_origin = *pbuf++;
    debug (_debug_requests, "GC clip y orig :%u ", values->clip_y_origin);
  }
  if (valuemask & GCClipMask) {
    values->clip_mask = *pbuf++;
    /* -- clip mask is an pixmap ID -> map it -- */
    values->clip_mask = MapID (values->clip_mask, connection, FromClient);
    debug (_debug_requests, "GC clip mask :0x%lx ", values->clip_mask);
  }
  if (valuemask & GCDashOffset) {
    values->dash_offset = *pbuf++;
    debug (_debug_requests, "GC dash offset :%u ", values->dash_offset);
  }
  if (valuemask & GCDashList) {
    values->dashes = *pbuf++;
    debug (_debug_requests, "GC dashes :%d ", values->dashes);
  }
  if (valuemask & GCArcMode) {
    values->arc_mode = *pbuf++;
    debug (_debug_requests, "GC arc mode :%u ", values->arc_mode);
  }
  debug (_debug_requests, "\n");
}

void
PSUpdateGCValues (valuemask, req, gc, connection)
  Mask valuemask;
  xCreateGCReq *req;
  GC gc;
  int connection;		/* if we have to map ID's */
{
  register unsigned long *pbuf = (unsigned long *) req;
  register XGCValues *values = &gc->values;

  debug (_debug_requests, "Mask : %lx\n", valuemask);
  if (valuemask & GCFunction) {
    values->function = *pbuf++;
    gc->dirty |= GCFunction;
    debug (_debug_requests, "GC function :%u ", values->function);
  }
  if (valuemask & GCPlaneMask) {
    values->plane_mask = *pbuf++;

    gc->dirty |= GCPlaneMask;
    debug (_debug_requests, "GC plane mask :%lx ", values->plane_mask);
  }
  if (valuemask & GCForeground) {
    values->foreground = *pbuf++;
    gc->dirty |= GCForeground;
    debug (_debug_requests, "GC foreground :%u ", values->foreground);
  }
  if (valuemask & GCBackground) {
    values->background = *pbuf++;
    gc->dirty |= GCBackground;
    debug (_debug_requests, "GC background :%u ", values->background);
  }
  if (valuemask & GCLineWidth) {
    values->line_width = *pbuf++;
    gc->dirty |= GCLineWidth;
    debug (_debug_requests, "GC line width :%u ", values->line_width);
  }
  if (valuemask & GCLineStyle) {
    values->line_style = *pbuf++;
    gc->dirty |= GCLineStyle;
    debug (_debug_requests, "GC line style :%u ", values->line_style);
  }
  if (valuemask & GCCapStyle) {
    values->cap_style = *pbuf++;
    gc->dirty |= GCCapStyle;
    debug (_debug_requests, "GC cap style :%u ", values->cap_style);
  }
  if (valuemask & GCJoinStyle) {
    values->join_style = *pbuf++;
    gc->dirty |= GCJoinStyle;
    debug (_debug_requests, "GC join style :%u ", values->join_style);
  }
  if (valuemask & GCFillStyle) {
    values->fill_style = *pbuf++;
    gc->dirty |= GCFillStyle;
    debug (_debug_requests, "GC fill style :%u ", values->fill_style);
  }
  if (valuemask & GCFillRule) {
    values->fill_rule = *pbuf++;
    gc->dirty |= GCFillRule;
    debug (_debug_requests, "GC fill rule :%u ", values->fill_rule);
  }
  if (valuemask & GCTile) {
    values->tile = *pbuf++;
    gc->dirty |= GCTile;
    /* -- tile is a pixmap ID -> map it -- */
    values->tile = MapID (values->tile, connection, FromClient);
    debug (_debug_requests, "GC tile pixmap :0x%lx ", values->tile);
  }
  if (valuemask & GCStipple) {
    values->stipple = *pbuf++;
    gc->dirty |= GCStipple;
    /* -- stipple is a pixmap ID -> map it -- */
    values->stipple = MapID (values->stipple, connection, FromClient);
    debug (_debug_requests, "GC stipple pixmap :0x%lx ", values->stipple);
  }
  if (valuemask & GCTileStipXOrigin) {
    values->ts_x_origin = *pbuf++;
    gc->dirty |= GCTileStipXOrigin;
    debug (_debug_requests, "GC ts x orig :%u ", values->ts_x_origin);
  }
  if (valuemask & GCTileStipYOrigin) {
    values->ts_y_origin = *pbuf++;
    gc->dirty |= GCTileStipYOrigin;
    debug (_debug_requests, "GC ts y orig :%u ", values->ts_y_origin);
  }
  if (valuemask & GCFont) {
    values->font = *pbuf++;
    gc->dirty |= GCFont;
    /* -- font is an font ID -> map it -- */
    values->font = MapID (values->font, connection, FromClient);
    debug (_debug_requests, "GC font :0x%lx ", values->font);
  }
  if (valuemask & GCSubwindowMode) {
    values->subwindow_mode = *pbuf++;
    gc->dirty |= GCSubwindowMode;
    debug (_debug_requests, "GC subwindow mode :%u ", values->subwindow_mode);
  }
  if (valuemask & GCGraphicsExposures) {
    values->graphics_exposures = *pbuf++;
    gc->dirty |= GCGraphicsExposures;
    debug (_debug_requests, "GC gr exposures :%u ",
	   values->graphics_exposures);
  }
  if (valuemask & GCClipXOrigin) {
    values->clip_x_origin = *pbuf++;
    gc->dirty |= GCClipXOrigin;
    debug (_debug_requests, "GC clip x orig :%u ", values->clip_x_origin);
  }
  if (valuemask & GCClipYOrigin) {
    values->clip_y_origin = *pbuf++;
    gc->dirty |= GCClipYOrigin;
    debug (_debug_requests, "GC clip y orig :%u ", values->clip_y_origin);
  }
  if (valuemask & GCClipMask) {
    values->clip_mask = *pbuf++;
    gc->dirty |= GCClipMask;
    /* -- clip mask is an pixmap ID -> map it -- */
    values->clip_mask = MapID (values->clip_mask, connection, FromClient);
    debug (_debug_requests, "GC clip mask :0x%lx ", values->clip_mask);
  }
  if (valuemask & GCDashOffset) {
    values->dash_offset = *pbuf++;
    gc->dirty |= GCDashOffset;
    debug (_debug_requests, "GC dash offset :%u ", values->dash_offset);
  }
  if (valuemask & GCDashList) {
    values->dashes = *pbuf++;
    gc->dirty |= GCDashList;
    debug (_debug_requests, "GC dashes :%s ", values->dashes);
  }
  if (valuemask & GCArcMode) {
    values->arc_mode = *pbuf++;
    gc->dirty |= GCArcMode;
    debug (_debug_requests, "GC arc mode :%u ", values->arc_mode);
  }
  debug (_debug_requests, "\n");
}

void
PSBuildSetWindowAttributes (valuemask, req, attributes, connection)
  Mask valuemask;
  xChangeWindowAttributesReq *req;
  XSetWindowAttributes *attributes;
  int connection;		/* if we have to map ID's */
{
  register unsigned long *pbuf = (unsigned long *) req;

  debug (_debug_requests, "value mask : %lx\n", valuemask);
  if (valuemask & CWBackPixmap) {
    attributes->background_pixmap = *pbuf++;
    /* -- background pixmap is a pixmap ID -> map it -- */
    attributes->background_pixmap =
      MapID (attributes->background_pixmap, connection, FromClient);
    debug (_debug_requests, "WA bg pixmap :0x%lx ",
	   attributes->background_pixmap);
  }
  if (valuemask & CWBackPixel) {
    attributes->background_pixel = *pbuf++;
    debug (_debug_requests, "WA bg pixel :%u ",
	   attributes->background_pixel);
  }
  if (valuemask & CWBorderPixmap) {
    attributes->border_pixmap = *pbuf++;
    /* -- border pixmap is a pixmap ID -> map it -- */
    attributes->border_pixmap =
      MapID (attributes->border_pixmap, connection, FromClient);
    debug (_debug_requests, "WA border pixmap :0x%lx ",
	   attributes->border_pixmap);
  }
  if (valuemask & CWBorderPixel) {
    attributes->border_pixel = *pbuf++;
    debug (_debug_requests, "WA border pixel :%u ",
	   attributes->border_pixel);
  }
  if (valuemask & CWBitGravity) {
    attributes->bit_gravity = *pbuf++;
    debug (_debug_requests, "WA bit gravity :%u ", attributes->bit_gravity);
  }
  if (valuemask & CWWinGravity) {
    attributes->win_gravity = *pbuf++;
    debug (_debug_requests, "WA window gravity :%u ", attributes->win_gravity);
  }
  if (valuemask & CWBackingStore) {
    attributes->backing_store = *pbuf++;
    debug (_debug_requests, "WA backing store :%u ", attributes->backing_store);
  }
  if (valuemask & CWBackingPlanes) {
    attributes->backing_planes = *pbuf++;
    debug (_debug_requests, "WA backing planes :%u ", attributes->backing_planes);
  }
  if (valuemask & CWBackingPixel) {
    attributes->backing_pixel = *pbuf++;
    debug (_debug_requests, "WA backing pixel :%u ", attributes->backing_pixel);
  }
  if (valuemask & CWOverrideRedirect) {
    attributes->override_redirect = *pbuf++;
    debug (_debug_requests, "WA override red :%u ", attributes->override_redirect);
  }
  if (valuemask & CWSaveUnder) {
    attributes->save_under = *pbuf++;
    debug (_debug_requests, "WA save under :%u ", attributes->save_under);
  }
  if (valuemask & CWEventMask) {
    attributes->event_mask = *pbuf++;
    debug (_debug_requests, "WA event mask :%lx ",
	   attributes->event_mask);
  }
  if (valuemask & CWDontPropagate) {
    attributes->do_not_propagate_mask = *pbuf++;
    debug (_debug_requests, "WA don't prop mask :%u ", attributes->do_not_propagate_mask);
  }
  if (valuemask & CWColormap) {
    attributes->colormap = *pbuf++;
    /* -- colormap is a color map ID -> map it -- */
    attributes->colormap =
      MapID (attributes->colormap, connection, FromClient);
    debug (_debug_requests, "WA colormap :0x%lx ",
	   attributes->colormap);
  }
  if (valuemask & CWCursor) {
    attributes->cursor = *pbuf++;
    /* -- cursor is a cursor ID -> map it -- */
    attributes->cursor =
      MapID (attributes->cursor, connection, FromClient);
    debug (_debug_requests, "WA cursor :0x%lx ", attributes->cursor);
  }
  debug (_debug_requests, "\n");
}

/* -- pad must be a power of 2 -- */
#define ROUNDUP( nbytes , pad ) \
          ( ( ( nbytes ) + ( ( pad ) - 1 ) ) & ~( long ) ( ( pad ) - 1 ) )
int
PSComputeBytesPerLine (image_width, image_format, image_depth, bitmap_pad,
		       bits_per_pixel)
  int image_width, image_format, image_depth, bitmap_pad, bits_per_pixel;
{
  register int bytes_per_line;

  if ((image_format != ZPixmap) || (image_depth == 1)) {
    bytes_per_line = (ROUNDUP ((long) image_width,
			       bitmap_pad) >> 3) * image_depth;
  }
  else
    bytes_per_line = ROUNDUP ((long) image_width * bits_per_pixel,
			      bitmap_pad) >> 3;
  return (bytes_per_line);
}

#undef ROUNDUP

int
PSComputeBitmapPadAndBitsPerPixel (dpy, image_format, image_depth,
				   bitmap_pad, bits_per_pixel)
  Display *dpy;
  int image_format, image_depth;
  int *bits_per_pixel, *bitmap_pad;
{
  register int n;
  register ScreenFormat *format;

  if ((image_format != ZPixmap) || (image_depth == 1)) {
    *bits_per_pixel = 1;
    *bitmap_pad = dpy->bitmap_pad;
    return (TRUE);
  }
  else {
    for (n = dpy->nformats, format = dpy->pixmap_format;
	 --n >= 0; format++)
      if (format->depth == image_depth) {
	*bits_per_pixel = format->bits_per_pixel;
	*bitmap_pad = format->scanline_pad;
	return (TRUE);
      }
  }
  return (FALSE);
}


/*
 * This array encodes the answer to the question "what is the log base 2 of
 * the number of pixels that fit in a scanline pad unit?" Note that ~0 is an
 * invalid entry (mostly for the benefit of the reader).
 */
static int answer[6][3] =
{
/* pad   pad   pad */
/* 8     16    32 */

  {3, 4, 5},			/* 1 bit per pixel */
  {1, 2, 3},			/* 4 bits per pixel */
  {0, 1, 2},			/* 8 bits per pixel */
  {~0, 0, 1},			/* 16 bits per pixel */
  {~0, ~0, 0},			/* 24 bits per pixel */
  {~0, ~0, 0}			/* 32 bits per pixel */
};

/*
 * This array gives the answer to the question "what is the first index for
 * the answer array above given the number of bits per pixel?" Note that ~0
 * is an invalid entry (mostly for the benefit of the reader).
 */
static int indexForBitsPerPixel[33] =
{
  ~0, 0, ~0, ~0,		/* 1 bit per pixel */
  1, ~0, ~0, ~0,		/* 4 bits per pixel */
  2, ~0, ~0, ~0,		/* 8 bits per pixel */
  ~0, ~0, ~0, ~0,
  3, ~0, ~0, ~0,		/* 16 bits per pixel */
  ~0, ~0, ~0, ~0,
  4, ~0, ~0, ~0,		/* 24 bits per pixel */
  ~0, ~0, ~0, ~0,
  5				/* 32 bits per pixel */
};

/*
 * This array gives the answer to the question "what is the second index for
 * the answer array above given the number of bits per scanline pad unit?"
 * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
 */
static int indexForScanlinePad[33] =
{
  ~0, ~0, ~0, ~0,
  ~0, ~0, ~0, ~0,
  0, ~0, ~0, ~0,		/* 8 bits per scanline pad unit */
  ~0, ~0, ~0, ~0,
  1, ~0, ~0, ~0,		/* 16 bits per scanline pad unit */
  ~0, ~0, ~0, ~0,
  ~0, ~0, ~0, ~0,
  ~0, ~0, ~0, ~0,
  2				/* 32 bits per scanline pad unit */
};

/* pad scanline to a longword */

#if defined(ibm) && defined(i386)
#define BITMAP_SCANLINE_UNIT	8
#else
#define BITMAP_SCANLINE_UNIT	32
#endif

#define BITMAP_SCANLINE_PAD  32

#define LOG2_BITMAP_PAD		5
#define LOG2_BYTES_PER_SCANLINE_PAD	2

/*
 * This returns the number of padding units, for depth d and width w. For
 * bitmaps this can be calculated with the macros above. Other depths require
 * either grovelling over the formats field of the screenInfo or hardwired
 * constants.
 */

typedef struct _PaddingInfo {
  int padRoundUp;		/* pixels per pad unit - 1 */
  int padPixelsLog2;		/* log 2 (pixels per pad unit) */
  int padBytesLog2;		/* log 2 (bytes per pad unit) */
} PaddingInfo;

static PaddingInfo PixmapWidthPaddingInfo[33];

#define PixmapWidthInPadUnits(w, d) \
    (((w) + PixmapWidthPaddingInfo[d].padRoundUp) >> \
	PixmapWidthPaddingInfo[d].padPixelsLog2)

/*
 * Return the number of bytes to which a scanline of the given depth and
 * width will be padded.
 */
#define PixmapBytePad(w, d) \
    (PixmapWidthInPadUnits(w, d) << PixmapWidthPaddingInfo[d].padBytesLog2)

void
InitPaddingInfo (dpy)
  Display *dpy;
{
  int j, k, format, bitsPerPixel, scanlinepad, depth;

  ScreenFormat *screenInfo = dpy->pixmap_format;

  j = indexForBitsPerPixel[1];
  k = indexForScanlinePad[BITMAP_SCANLINE_PAD];
  PixmapWidthPaddingInfo[1].padRoundUp = BITMAP_SCANLINE_PAD - 1;
  PixmapWidthPaddingInfo[1].padPixelsLog2 = answer[j][k];
  j = indexForBitsPerPixel[8];	/* bits per byte */
  PixmapWidthPaddingInfo[1].padBytesLog2 = answer[j][k];

  for (format = 0; format < dpy->nformats; format++) {
    depth = screenInfo[format].depth;
    bitsPerPixel = screenInfo[format].bits_per_pixel;
    scanlinepad = screenInfo[format].scanline_pad;
    j = indexForBitsPerPixel[bitsPerPixel];
    k = indexForScanlinePad[scanlinepad];
    PixmapWidthPaddingInfo[depth].padPixelsLog2 = answer[j][k];
    PixmapWidthPaddingInfo[depth].padRoundUp =
      (scanlinepad / bitsPerPixel) - 1;
    j = indexForBitsPerPixel[8];/* bits per byte */
    PixmapWidthPaddingInfo[depth].padBytesLog2 = answer[j][k];
  }
}

static int
Ones (mask)			/* HACKMEM 169 */
  Mask mask;
{
  register Mask y;

  y = (mask >> 1) & 033333333333;
  y = mask - y - ((y >> 1) & 033333333333);
  return (((y + (y >> 3)) & 030707070707) % 077);
}

int
PSComputeWidth (format, image_width, depth, plane_mask)
  int image_width, depth, format;
  unsigned long plane_mask;
{
  if (format == ZPixmap)
    return (PixmapBytePad (image_width, depth));
  else {
    unsigned long plane;

    plane = (1L) << (depth - 1);
    return (PixmapBytePad (image_width, 1) *
	    Ones (plane_mask & (plane | (plane - 1))));
  }
}
