home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / awm2 / part06 / Titlebar.c < prev   
Encoding:
C/C++ Source or Header  |  1989-02-20  |  18.4 KB  |  691 lines

  1.  
  2.  
  3.  
  4. #ifndef lint
  5. static char *rcsid_TitleBar_c = "$Header: /usr/graph2/X11.3/contrib/windowmgrs/awm/RCS/Titlebar.c,v 1.2 89/02/07 21:23:59 jkh Exp $";
  6. #endif    lint
  7.  
  8. #include "X11/copyright.h"
  9. /*
  10.  *
  11.  * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
  12.  *
  13.  * Copyright 1987 by Jordan Hubbard.
  14.  *
  15.  *
  16.  *                         All Rights Reserved
  17.  *
  18.  * Permission to use, copy, modify, and distribute this software and its
  19.  * documentation for any purpose and without fee is hereby granted,
  20.  * provided that the above copyright notice appear in all copies and that
  21.  * both that copyright notice and this permission notice appear in
  22.  * supporting documentation, and that the name of Ardent Computer
  23.  * Corporation or Jordan Hubbard not be used in advertising or publicity
  24.  * pertaining to distribution of the software without specific, written
  25.  * prior permission.
  26.  *
  27.  */
  28.  
  29. /*
  30.  * MODIFICATION HISTORY
  31.  *
  32.  * 002 -- Jordan Hubbard, U.C. Berkeley.
  33.  Title bar support routines.
  34.  * 1.2 -- Fairly major restructuring to uncouple title bars and
  35.  * border contexts.
  36.  * 1.3 -- Handling of colors revamped significantly to deal with
  37.  * different colormaps.
  38.  */
  39.  
  40. #include "awm.h"
  41. #include "X11/Xutil.h"
  42. #include "X11/cursorfont.h"
  43.  
  44. unsigned int TB_wide, TB_high, TBB_wide, TBB_high, BC_wide, BC_high;
  45. unsigned int BCB_wide, BCB_high;
  46.  
  47. extern XContext AwmContext;
  48.  
  49. #define BLANK_WIDE    16
  50. #define BLANK_HIGH    16
  51. static char blank_bits[] = {
  52.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  53.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  54.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  55.  
  56. static Boolean Title_res, Frame_res;
  57.  
  58. void Init_Titles()
  59. {
  60.   extern XFontStruct *GetFontRes();
  61.  
  62.      TFontInfo = GetFontRes("title.font", DEF_TITLE_FONT);
  63.      TFontBoldInfo = GetFontRes("title.boldFont", (char *) NULL);
  64.      TBackPixmapData = GetPixmapDataRes("title.pixmap", &TB_wide, &TB_high);
  65.      TBoldPixmapData = GetPixmapDataRes("title.boldPixmap", &TBB_wide,
  66.                     &TBB_high);
  67.      TForeground = GetStringRes("title.foreground", Foreground);
  68.      TBackground = GetStringRes("title.background", Background);
  69.      TTextForeground = GetStringRes("title.text.foreground", TForeground);
  70.      TTextBackground = GetStringRes("title.text.background", TBackground);
  71.  
  72.      TCursor = GetIntRes("title.cursor", DEF_TITLE_CURSOR);
  73.  
  74.      TitleHeight = GetIntRes("title.height", 0);
  75.      TitlePad = GetIntRes("title.pad", DEF_TITLE_PAD);
  76.      NameOffset = GetIntRes("windowName.offset", 0);
  77.      titleHeight = TFontInfo->max_bounds.ascent +
  78.       TFontInfo->max_bounds.descent + (TitlePad * 2);
  79.      /* we've specified a bold pixmap, but no back pixmap. Use blank. */
  80.      if (TBoldPixmapData && !TBackPixmapData) {
  81.       TBackPixmapData = blank_bits;
  82.       TB_wide = BLANK_WIDE;
  83.       TB_high = BLANK_HIGH;
  84.      }
  85.      if (TFontBoldInfo) {
  86.       int foo;
  87.       
  88.       foo = TFontBoldInfo->max_bounds.ascent +
  89.            TFontBoldInfo->max_bounds.descent + (TitlePad * 2);
  90.       if (foo > titleHeight)
  91.            titleHeight = foo;
  92.      }
  93.      if (titleHeight < gadgetHeight)
  94.       titleHeight = gadgetHeight;
  95.      if (TitleHeight) /* Specified height overrides derived height */
  96.       titleHeight = TitleHeight;
  97.      TitleCursor = XCreateFontCursor(dpy, TCursor);
  98.      if (!TitleCursor) {
  99.        char temp[80];
  100.        sprintf("Init_Titles: Can't get title cursor #%d!\n", TCursor);
  101.        Error(temp);
  102.      }
  103.      /* Gadgets can't exist without titles, so we'll init them here */
  104.      GadgetPad = GetIntRes("gadget.pad", DEF_GADGET_PAD);
  105.      GadgetBorder = GetIntRes("gadget.border", DEF_GADGET_BORDER);
  106.  
  107.      Title_res = TRUE;
  108. }
  109.  
  110. void Init_Frames()
  111. {
  112.      
  113.      Entry("Init_Frames")
  114.  
  115.      BForeground = GetStringRes("borderContext.foreground", Foreground);
  116.      BBackground = GetStringRes("borderContext.background", Background);
  117.  
  118.      BCursor = GetIntRes("borderContext.cursor", DEF_BCONTEXT_CURSOR);
  119.  
  120.      BBackPixmapData = GetPixmapDataRes("borderContext.pixmap", &BC_wide,
  121.                     &BC_high);
  122.      BBoldPixmapData = GetPixmapDataRes("borderContext.boldPixmap", &BCB_wide,
  123.                     &BCB_high);
  124.      /* we've specified a bold BC pixmap, but no back pixmap. Use blank. */
  125.      if (BBoldPixmapData && !BBackPixmapData) {
  126.       BBackPixmapData = blank_bits;
  127.       BC_wide = BLANK_WIDE;
  128.       BC_high = BLANK_HIGH;
  129.      }
  130.      FrameCursor = XCreateFontCursor(dpy, BCursor);
  131.      if (!FrameCursor) {
  132.        char temp[80];
  133.        sprintf("Init_Frames: Can't get border cursor #%d!\n", BCursor);
  134.        Error(temp);
  135.      }
  136.      Frame_res = TRUE;
  137.      Leave_void
  138. }
  139.  
  140. char *GetTitleName(w)
  141. Window w;
  142. {
  143.      char *cp = 0, *tmp;
  144.      
  145.      Entry("GetTitleName")
  146.       
  147.      if (!XFetchName(dpy, w, &cp) || !cp)
  148.       cp = "Untitled Window";
  149.      tmp = (char *)malloc(strlen(cp) + 3);
  150.      
  151.      /*
  152.       * We add a space on both ends for asthetic effect
  153.       * (only apparent if we're using inverse video).
  154.       */
  155.      tmp[0] = ' ';
  156.      strcpy(tmp + 1, cp);
  157.      strcat(tmp, " ");
  158.      Leave(tmp)
  159. }
  160.  
  161. /*
  162.  * Reparent window 'w' into a frame, making the frame the right
  163.  * size to hold any other window related decorations that may be
  164.  * added later. If window 'w' already has a frame, then it resizes
  165.  * it if necessary.
  166.  */
  167. Window Reparent(w)
  168. Window w;
  169. {
  170.      Window foster;
  171.      XWindowAttributes xwa;
  172.      XSetWindowAttributes swa;
  173.      XWMHints *wm_hints;
  174.      XSizeHints sz_hints;
  175.      XClassHint class_hints;
  176.      AwmInfoPtr awi;
  177.      char *icon_name;
  178.      int bch, bcv, x, y;
  179.      unsigned int width, height, bw;
  180.      int clnt_x, clnt_y;
  181.      unsigned long valuemask;
  182.      Boolean decorated = FALSE;
  183.      Colormap cmap;
  184.      Pixel bfore, bback;
  185.  
  186.      Entry("Reparent")
  187.  
  188.      awi = GetAwmInfo(w);
  189.      if (!awi) {
  190.       fprintf(stderr, "Reparent: Window %x isn't registered!\n", w);
  191.       Leave((Window)NULL)
  192.      }
  193.      if (awi->frame && (awi->state & ST_DECORATED))
  194.       Leave((Window)NULL)
  195.  
  196.      if (!Frame_res)
  197.       Init_Frames();
  198.  
  199.      if (awi->attrs & AT_TITLE && !Title_res)
  200.       Init_Titles();
  201.  
  202.      if (!awi->frame)
  203.       XGetWindowAttributes(dpy, awi->client, &xwa);
  204.      else
  205.       XGetWindowAttributes(dpy, awi->frame, &xwa);
  206.      valuemask = CWEventMask | CWBorderPixel | CWBackPixel | CWColormap;
  207.      swa.event_mask = (SubstructureRedirectMask | SubstructureNotifyMask);
  208.      bw = xwa.border_width;
  209.      x = xwa.x;
  210.      y = xwa.y;
  211.      height = xwa.height;
  212.      width = xwa.width;
  213.      cmap = xwa.colormap;
  214.      bfore = GetPixel(BForeground, cmap);
  215.      bback = GetPixel(BBackground, cmap);
  216.      clnt_y = clnt_x = 0;
  217.      if (awi->attrs & AT_BORDER) {
  218.       XSetWindowAttributes cswa;
  219.      
  220.       swa.event_mask |= (ButtonPressMask | ButtonReleaseMask);
  221.           bcv = BContext + 1;
  222.       bch = bcv * 2;
  223.  
  224.       cswa.do_not_propagate_mask =
  225.            (ButtonPressMask | ButtonReleaseMask);
  226.       XChangeWindowAttributes(dpy, awi->client, CWDontPropagate, &cswa);
  227.      }
  228.      else
  229.           bch = bcv = 0;
  230.      if (FrameFocus)
  231.       swa.event_mask |= (LeaveWindowMask | EnterWindowMask);
  232.      if (awi->attrs & AT_BORDER) {
  233.       swa.background_pixel = bfore;
  234.       swa.border_pixel = bback;
  235.       decorated = TRUE;
  236.      }
  237.      else if (awi->attrs & AT_TITLE) {
  238.       swa.background_pixel = GetPixel(TBackground, cmap);
  239.       swa.border_pixel = GetPixel(TForeground, cmap);
  240.      }
  241.      else {
  242.       swa.background_pixel = GetPixel(Background, cmap);
  243.       swa.border_pixel = GetPixel(Foreground, cmap);
  244.      }
  245.      swa.colormap = cmap;
  246.      if (PushDown == FALSE) {
  247.       if (awi->attrs & AT_TITLE)
  248.            y -= (titleHeight + 2);
  249.       else if (awi->attrs & AT_BORDER)
  250.            y -= BContext;
  251.      }
  252.      /* calculate size for frame */
  253.      if (awi->attrs & AT_TITLE)
  254.       height += titleHeight + 2;
  255.      if (awi->attrs & AT_BORDER) {
  256.       if (!(awi->attrs & AT_TITLE))
  257.            height += (bcv * 2);
  258.       else
  259.            height += bcv;
  260.       width += bch;
  261.      }
  262.      if (awi->attrs & AT_TITLE)
  263.       clnt_y = titleHeight + 2;
  264.      
  265.      if (awi->attrs & AT_BORDER) {
  266.       if (!(awi->attrs & AT_TITLE))
  267.            clnt_y = BContext;
  268.       clnt_x = BContext;
  269.      }
  270.  
  271.      if (!awi->frame) {
  272.       foster = XCreateWindow(dpy, RootWindow(dpy, scr), x, y, width,
  273.                  height, (bw ? bw : (unsigned int) 1),
  274.                  xwa.depth, xwa.class,
  275.                  xwa.visual, valuemask, &swa);
  276.       if (!foster)
  277.            Error("Reparent: Can't create foster parent!");
  278.  
  279.       if (awi->attrs & AT_BORDER)
  280.            XDefineCursor(dpy, foster, FrameCursor);
  281.  
  282.       XAddToSaveSet(dpy, awi->client);
  283.           XSetWindowBorderWidth(dpy, awi->client,
  284.                    (unsigned int)((awi->attrs&AT_BORDER) ? 1 : 0));
  285.       XReparentWindow(dpy, awi->client, foster, clnt_x, clnt_y);
  286.       XSync(dpy, FALSE);
  287.  
  288.       if (BBackPixmapData) { /* we have a border context tile */
  289.            awi->BC_back = GetPixmapFromCache(foster,
  290.                          BBackPixmapData,
  291.                          BC_wide, BC_high,
  292.                          bfore, bback,
  293.                          xwa.depth);
  294.            if (!awi->BC_back)
  295.             Error("Reparent: Can't get pixmap for border context.");
  296.            else
  297.             XSetWindowBackgroundPixmap(dpy, foster, awi->BC_back);
  298.       }
  299.       if (BBoldPixmapData) { /* we have a bold border context tile */
  300.            awi->BC_bold = GetPixmapFromCache(foster,
  301.                          BBoldPixmapData,
  302.                          BCB_wide, BCB_high,
  303.                          bfore, bback,
  304.                          xwa.depth);
  305.            if (!awi->BC_bold)
  306.             Error("Reparent: Can't get bold pixmap for border context.");
  307.       }
  308.       awi->frame = foster;
  309.       awi->border_width = bw;
  310.       awi->name = GetTitleName(awi->client);
  311.  
  312.       /* Make titlebar "frame" inherit characteristics of victim */
  313.       XStoreName(dpy, foster, awi->name);
  314.       if (XGetIconName(dpy, w, &icon_name)) {
  315.            XSetIconName(dpy, foster, icon_name);
  316.            XFree(icon_name);
  317.       }
  318.       if (wm_hints = XGetWMHints(dpy, awi->client)) {
  319.            XSetWMHints(dpy, foster, wm_hints);
  320.            XFree(wm_hints);
  321.       }
  322.       XGetNormalHints(dpy, awi->client, &sz_hints);
  323.       XSetNormalHints(dpy, foster, &sz_hints);
  324.       XGetZoomHints(dpy, awi->client, &sz_hints);
  325.       XSetZoomHints(dpy, foster, &sz_hints);
  326.       class_hints.res_name = class_hints.res_class = (char *)NULL;
  327.       if (XGetClassHint(dpy, awi->client, &class_hints) == Success) {
  328.            if (class_hints.res_name || class_hints.res_class)
  329.             XSetClassHint(dpy, foster, &class_hints);
  330.       }
  331.       XSaveContext(dpy, foster, AwmContext, (caddr_t) awi);
  332.      }
  333.      else {
  334.       XMoveResizeWindow(dpy, awi->frame, xwa.x, xwa.y, width, height);
  335.       XMoveWindow(dpy, awi->client, clnt_x, clnt_y);
  336.       if (awi->attrs & AT_BORDER)
  337.            decorated = TRUE;
  338.       foster = awi->frame;
  339.      }
  340. #ifdef RAINBOW
  341.      if (BorderHilite)
  342.       SetBorderPixmaps(awi, awi->grayPixmap);
  343. #endif
  344.      if (decorated)
  345.       awi->state |= ST_DECORATED;
  346.      Leave(foster)
  347. }
  348.      
  349. void AddTitle(w)
  350. Window w;
  351. {
  352.      int bch;
  353.      Window title;
  354.      AwmInfoPtr awi;
  355.      unsigned long valuemask;
  356.      XWindowAttributes xwa;
  357.      XSetWindowAttributes swa;
  358.      XWindowChanges wc;
  359.      Pixel tfore, tback;
  360.  
  361.      Entry("AddTitle")
  362.  
  363.      awi = GetAwmInfo(w);
  364.  
  365.      if (!awi) {
  366.       fprintf(stderr, "AddTitle: Window %x is not registered!\n", w);
  367.       Leave_void
  368.      }
  369.      if (!awi->frame) 
  370.       Leave_void
  371.      if (awi->title)
  372.       Leave_void
  373.      if (!(awi->attrs & AT_TITLE))
  374.       Leave_void
  375.  
  376.      XGetWindowAttributes(dpy, awi->client, &xwa);
  377.      swa.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask);
  378.      swa.colormap = xwa.colormap;
  379.      tfore = GetPixel(TForeground, xwa.colormap);
  380.      tback = GetPixel(TBackground, xwa.colormap);
  381.      swa.background_pixel = tback;
  382.      swa.border_pixel = tfore;
  383.      valuemask = (CWEventMask | CWColormap | CWBackPixel | CWBorderPixel);
  384.      if (awi->attrs & AT_BORDER)
  385.       bch = (BContext * 2) + 2;
  386.      else
  387.       bch = 0;
  388.      title = XCreateWindow(dpy, awi->frame, 0, 0, (xwa.width - 2) + bch,
  389.                titleHeight,
  390.                1, xwa.depth, xwa.class, xwa.visual,
  391.                valuemask, &swa);
  392.      if (!title)
  393.       Error("AddTitle: Can't create title bar!");
  394.      if (TBackPixmapData) {
  395.       awi->back = GetPixmapFromCache(title, TBackPixmapData,
  396.                      TB_wide, TB_high,
  397.                      tfore, tback,
  398.                      xwa.depth);
  399.       if (!awi->back)
  400.            Error("AddTitle: Can't create pixmap for title background");
  401.       else
  402.            XSetWindowBackgroundPixmap(dpy, title, awi->back);
  403.      }
  404.      if (TBoldPixmapData) {
  405.       awi->bold = GetPixmapFromCache(title, TBoldPixmapData,
  406.                      TBB_wide, TBB_high,
  407.                      tfore, tback,
  408.                      xwa.depth);
  409.       if (!awi->bold)
  410.            Error("AddTitle: Can't create pixmap for bold background");
  411.      }
  412.      wc.sibling = awi->client;
  413.      wc.stack_mode = Above;
  414.      XConfigureWindow(dpy, title, CWSibling|CWStackMode, &wc);
  415.      XDefineCursor(dpy, title, TitleCursor);
  416.      XSelectInput(dpy, title, (ExposureMask | ButtonPressMask |
  417.                ButtonReleaseMask));
  418.      XMapWindow(dpy, title);
  419.      awi->title = title;
  420.      awi->state |= ST_DECORATED;
  421.      XSaveContext(dpy, title, AwmContext, (caddr_t) awi);
  422. }
  423.  
  424. /*ARGSUSED*/
  425. Boolean FNoDecorate(w, mask, button, x, y)
  426. Window w;
  427. int mask, button, x, y;
  428. {
  429.      Entry("FNoDecorate")
  430.       
  431.      if (w == RootWindow(dpy, scr))
  432.       Leave(FALSE)
  433.      NoDecorate(w, FALSE);
  434.      Leave(TRUE)
  435. }
  436.  
  437. void NoDecorate(w, destroy)
  438. Window w;
  439. Boolean destroy;
  440. {
  441.      XWindowAttributes xwa;
  442.      AwmInfoPtr awi;
  443.      extern void DestroyGadgets();
  444.  
  445.      Entry("NoDecorate")
  446.  
  447.      awi = GetAwmInfo(w);
  448.      if (!awi || !awi->frame)
  449.      Leave_void
  450.  
  451.      if (!(awi->state & ST_DECORATED))
  452.      Leave_void
  453.      if (awi->gadgets)
  454.       DestroyGadgets(w);
  455.      if (awi->title) {
  456.       XDeleteContext(dpy, awi->title, AwmContext);
  457.       if (awi->back)
  458.            FreePixmapFromCache(awi->back);
  459.       if (awi->bold)
  460.            FreePixmapFromCache(awi->bold);
  461.       XDestroyWindow(dpy, awi->title);
  462.       awi->title = awi->back = awi->bold = (Drawable)NULL;
  463.      }
  464.      if (destroy) {
  465.       XDeleteContext(dpy, awi->frame, AwmContext);
  466.       if (awi->BC_back)
  467.            FreePixmapFromCache(awi->BC_back);
  468.       if (awi->BC_bold)
  469.            FreePixmapFromCache(awi->BC_bold);
  470.       free(awi->name);
  471.       awi->name = (char *)NULL;
  472.       XDestroyWindow(dpy, awi->frame);
  473.       awi->frame = awi->BC_back = awi->BC_bold = (Drawable)NULL;
  474.      }
  475.      else {
  476.       XGetWindowAttributes(dpy, awi->client, &xwa);
  477.       XResizeWindow(dpy, awi->frame, (unsigned int) xwa.width,
  478.             (unsigned int) xwa.height);
  479.       XMoveWindow(dpy, awi->client, 0, 0);
  480.       awi->state ^= ST_DECORATED;
  481.      }
  482.      XSync(dpy, FALSE);
  483.      Leave_void
  484. }
  485.  
  486. /*ARGSUSED*/
  487. Boolean FDecorate(window, mask, button, x, y)
  488. Window window;
  489. int mask;
  490. int button;
  491. int x, y;
  492. {
  493.      Window fr;
  494.  
  495.      Entry("FDecorate")
  496.  
  497.      if (window == RootWindow(dpy, scr))
  498.       Leave(FALSE)
  499.      fr = Decorate(window);
  500.      if (fr)
  501.       XMapWindow(dpy, fr);
  502.      XSync(dpy, FALSE);
  503.      Leave(FALSE)
  504. }
  505.  
  506. Window Decorate(w)
  507. Window w;
  508. {
  509.      Window ret;
  510.  
  511.      Entry("Decorate")
  512.  
  513.      ret = Reparent(w);
  514.      if (ret) {
  515.       AddTitle(ret);
  516.       PutGadgets(ret);
  517.      }
  518.      Leave(ret)
  519. }
  520.  
  521. /*ARGSUSED*/
  522. void PaintTitle(w, reversed)
  523. Window w;
  524. Boolean reversed;
  525. {
  526.      int x, y;
  527.      XWindowAttributes xwa;
  528.      XFontStruct *f_info;
  529.      AwmInfoPtr awi;
  530.      XGCValues gcv;
  531.      Colormap cmap;
  532.  
  533.      Entry("PaintTitle")
  534.  
  535.      if (!(awi = IsTitled(w)))
  536.      Leave_void
  537.      XGetWindowAttributes(dpy, awi->title, &xwa);
  538.      cmap = xwa.colormap;
  539.      if (reversed && TFontBoldInfo)
  540.       f_info = TFontBoldInfo;
  541.      else
  542.       f_info = TFontInfo;
  543.      gcv.font = f_info->fid;
  544.      gcv.foreground = (reversed && !TFontBoldInfo) ?
  545.       GetPixel(TTextBackground, cmap) : GetPixel(TTextForeground, cmap);
  546.      gcv.background = (reversed && !TFontBoldInfo) ?
  547.       GetPixel(TTextForeground, cmap) : GetPixel(TTextBackground, cmap);
  548.      XChangeGC(dpy, awi->winGC, (GCFont | GCForeground | GCBackground), &gcv);
  549.      XClearWindow(dpy, awi->title);
  550.      if (ShowName) {    /* print window names? */
  551.       int textlen;
  552.  
  553.       textlen = XTextWidth(f_info, awi->name, strlen(awi->name));
  554.  
  555.       if (!NameOffset)
  556.            x = (xwa.width - textlen) / 2;
  557.       else {
  558.            if (NameOffset < 0)
  559.             x = (xwa.width - textlen) + NameOffset;
  560.            else
  561.             x = NameOffset;
  562.            if (x + textlen > xwa.width)
  563.             x = (xwa.width - textlen) + 1;
  564.       }
  565.       y = (xwa.height + f_info->max_bounds.ascent -
  566.            f_info->max_bounds.descent) / 2;
  567.  
  568.       XDrawImageString(dpy, awi->title, awi->winGC, x, y, awi->name,
  569.                strlen(awi->name));
  570.      }
  571.      Leave_void
  572. }
  573.  
  574. AwmInfoPtr IsTitled(w)
  575. Window w;
  576. {
  577.      AwmInfoPtr tmp;
  578.  
  579.      Entry("IsTitled")
  580.  
  581.      if (tmp = GetAwmInfo(w))
  582.       if (tmp->title)
  583.            Leave(tmp)
  584.      Leave((AwmInfoPtr)NULL)
  585. }
  586.  
  587. /*
  588.  * These routines deal with a sort of "pixmap cache" that is needed
  589.  * to minimize the number of pixmaps created by awm. Awm operates on the
  590.  * assumption that the user may have an arbitrary number of windows at
  591.  * arbitrary depths. Since awm likes to create resources at the same
  592.  * depth as the client window, some sort of mechanism is needed to insure
  593.  * that as few are created as possible.
  594.  */
  595.  
  596. struct _resInfo {
  597.      struct _resInfo *next;
  598.      Drawable res; 
  599.      char *res_data;
  600.      Pixel res_fore, res_back;
  601.      int res_depth;
  602.      int ref_count;
  603. } *CacheHead;
  604.  
  605. struct _resInfo *allocResNode()
  606. {
  607.      struct _resInfo *ptr;
  608.  
  609.      Entry("allocResNode")
  610.  
  611.      ptr = (struct _resInfo *)malloc(sizeof(struct _resInfo));
  612.      if (!ptr)
  613.       fprintf(stderr, "allocResNode: Out of memory!\n");
  614.      Leave(ptr)
  615. }
  616.  
  617. /*
  618.  * Look for pixmap in cache and returns it or allocate new pixmap,
  619.  * store it in cache and return it.
  620.  */
  621. Drawable GetPixmapFromCache(d, data, wide, high, fore, back, depth)
  622. Drawable d;
  623. char *data;
  624. unsigned int wide, high;
  625. Pixel fore, back;
  626. int depth;
  627. {
  628.      struct _resInfo *cptr, *iptr;
  629.  
  630.      cptr = iptr = CacheHead;
  631.      while (cptr) {
  632.       if (cptr->res_depth > depth)
  633.            break;
  634.       if (cptr->res_depth == depth) {
  635.            if (cptr->res_data > data)
  636.             break;
  637.            else if (cptr->res_data == data) {
  638.             if (cptr->res_fore == fore && cptr->res_back == back) {
  639.              cptr->ref_count++;
  640.              Leave(cptr->res)
  641.             }
  642.            }
  643.       }
  644.       iptr = cptr;
  645.       cptr = cptr->next;
  646.      }
  647.      /* fell through, create another resource */
  648.      if (!iptr || cptr == CacheHead)    /* need to initialize list */
  649.       CacheHead = iptr = allocResNode();
  650.      else {
  651.       iptr->next = allocResNode();
  652.       iptr = iptr->next;
  653.      }
  654.      iptr->next = cptr;
  655.      iptr->res_depth = depth;
  656.      iptr->res_data = data;
  657.      iptr->res_fore = fore;
  658.      iptr->res_back = back;
  659.      iptr->res = XCreatePixmapFromBitmapData(dpy, d, data, wide, high,
  660.                          fore, back, (unsigned int) depth);
  661.      iptr->ref_count = 1;
  662.      Leave(iptr->res)
  663. }
  664.  
  665. /*
  666.  * Free pixmap (and associated cache cell) if no longer needed.
  667.  */
  668. void FreePixmapFromCache(pix)
  669. Pixmap pix;
  670. {
  671.      struct _resInfo *ptr, *tmp;
  672.  
  673.      ptr = tmp = CacheHead;
  674.      while (ptr) {
  675.       if (ptr->res == pix)
  676.            break;
  677.       tmp = ptr;
  678.       ptr = ptr->next;
  679.      }
  680.      if (!ptr)
  681.       Leave_void
  682.      if (--ptr->ref_count == 0) { /* last ref */
  683.       if (ptr == CacheHead)
  684.            CacheHead = CacheHead->next;
  685.       else
  686.            tmp->next = ptr->next;
  687.       XFreePixmap(dpy, ptr->res);
  688.       free(ptr);
  689.      }
  690. }
  691.