home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Mailbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-13  |  17.8 KB  |  636 lines

  1. /*
  2.  * $XConsortium: Mailbox.c,v 1.58 91/06/13 16:50:32 keith Exp $
  3.  *
  4.  * Copyright 1988 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted, provided
  8.  * that the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * Author:  Jim Fulton, MIT X Consortium
  17.  *
  18.  * I recommend that you use the new mailfull and mailempty bitmaps instead of
  19.  * the ugly mailboxes:
  20.  *
  21.  *         XBiff*fullPixmap:  mailfull
  22.  *         XBiff*emptyPixmap:  mailempty
  23.  */
  24.  
  25. #include <X11/IntrinsicP.h>        /* for toolkit stuff */
  26. #include <X11/StringDefs.h>        /* for useful atom names */
  27. #include <X11/cursorfont.h>        /* for cursor constants */
  28. #include <X11/Xosdefs.h>        /* for X_NOT_POSIX def */
  29. #include <sys/stat.h>            /* for stat() ** needs types.h ***/
  30. #include <stdio.h>            /* for printing error messages */
  31. #include <pwd.h>            /* for getting username */
  32.  
  33. #ifndef X_NOT_POSIX
  34. #ifdef _POSIX_SOURCE
  35. # include <sys/wait.h>
  36. #else
  37. #define _POSIX_SOURCE
  38. # include <sys/wait.h>
  39. #undef _POSIX_SOURCE
  40. #endif
  41. # define waitCode(w)    WEXITSTATUS(w)
  42. # define waitSig(w)    WIFSIGNALED(w)
  43. typedef int        waitType;
  44. # define INTWAITTYPE
  45. #else /* ! X_NOT_POSIX */
  46. #ifdef SYSV
  47. # define waitCode(w)    (((w) >> 8) & 0x7f)
  48. # define waitSig(w)    ((w) & 0xff)
  49. typedef int        waitType;
  50. # define INTWAITTYPE
  51. #else
  52. # include    <sys/wait.h>
  53. # define waitCode(w)    ((w).w_T.w_Retcode)
  54. # define waitSig(w)    ((w).w_T.w_Termsig)
  55. typedef union wait    waitType;
  56. #endif /* SYSV else */
  57. #endif /* ! X_NOT_POSIX else */
  58.  
  59. #include <X11/bitmaps/mailfull>        /* for flag up (mail present) bits */
  60. #include <X11/bitmaps/mailempty>    /* for flag down (mail not here) */
  61.  
  62. #include <X11/Xaw/XawInit.h>
  63. #include <X11/Xaw/MailboxP.h>        /* for implementation mailbox stuff */
  64. #include <X11/Xmu/Drawing.h>
  65. #include <X11/extensions/shape.h>
  66.  
  67. /*
  68.  * The default user interface is to have the mailbox turn itself off whenever
  69.  * the user presses a button in it.  Expert users might want to make this 
  70.  * happen on EnterWindow.  It might be nice to provide support for some sort of
  71.  * exit callback so that you can do things like press q to quit.
  72.  */
  73.  
  74. static char defaultTranslations[] = 
  75.   "<ButtonPress>:  unset()";
  76.  
  77. static void Check(), Set(), Unset();
  78.  
  79. static XtActionsRec actionsList[] = { 
  80.     { "check",    Check },
  81.     { "unset",    Unset },
  82.     { "set",    Set },
  83. };
  84.  
  85.  
  86. /* Initialization of defaults */
  87.  
  88. #define offset(field) XtOffsetOf(MailboxRec, mailbox.field)
  89. #define goffset(field) XtOffsetOf(WidgetRec, core.field)
  90.  
  91. static Dimension defDim = 48;
  92. static Pixmap nopix = None;
  93.  
  94. static XtResource resources[] = {
  95.     { XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension), 
  96.     goffset (width), XtRDimension, (XtPointer)&defDim },
  97.     { XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
  98.     goffset (height), XtRDimension, (XtPointer)&defDim },
  99.     { XtNupdate, XtCInterval, XtRInt, sizeof (int),
  100.     offset (update), XtRString, "30" },
  101.     { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
  102.     offset (foreground_pixel), XtRString, XtDefaultForeground },
  103.     { XtNfile, XtCFile, XtRString, sizeof (String),
  104.     offset (filename), XtRString, NULL },
  105.     { XtNcheckCommand, XtCCheckCommand, XtRString, sizeof(char*),
  106.     offset (check_command), XtRString, NULL},
  107.     { XtNvolume, XtCVolume, XtRInt, sizeof(int),
  108.     offset (volume), XtRString, "33"},
  109.     { XtNonceOnly, XtCBoolean, XtRBoolean, sizeof(Boolean),
  110.     offset (once_only), XtRImmediate, (XtPointer)False },
  111.     { XtNfullPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
  112.     offset (full.bitmap), XtRString, "flagup" },
  113.     { XtNfullPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
  114.     offset (full.mask), XtRBitmap, (XtPointer) &nopix },
  115.     { XtNemptyPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
  116.     offset (empty.bitmap), XtRString, "flagdown" },
  117.     { XtNemptyPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
  118.     offset (empty.mask), XtRBitmap, (XtPointer) &nopix },
  119.     { XtNflip, XtCFlip, XtRBoolean, sizeof(Boolean),
  120.     offset (flipit), XtRString, "true" },
  121.     { XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof(Boolean),
  122.         offset (shapeit), XtRString, "false" },
  123. };
  124.  
  125. #undef offset
  126. #undef goffset
  127.  
  128. static void GetMailFile(), CloseDown();
  129. static void check_mailbox(), redraw_mailbox(), beep();
  130. static void Initialize(), Realize(), Destroy(), Redisplay();
  131. static Boolean SetValues();
  132.  
  133. MailboxClassRec mailboxClassRec = {
  134.     { /* core fields */
  135.     /* superclass        */    (WidgetClass) &simpleClassRec,
  136.     /* class_name        */    "Mailbox",
  137.     /* widget_size        */    sizeof(MailboxRec),
  138.     /* class_initialize        */    XawInitializeWidgetSet,
  139.     /* class_part_initialize    */    NULL,
  140.     /* class_inited        */    FALSE,
  141.     /* initialize        */    Initialize,
  142.     /* initialize_hook        */    NULL,
  143.     /* realize            */    Realize,
  144.     /* actions            */    actionsList,
  145.     /* num_actions        */    XtNumber(actionsList),
  146.     /* resources        */    resources,
  147.     /* resource_count        */    XtNumber(resources),
  148.     /* xrm_class        */    NULLQUARK,
  149.     /* compress_motion        */    TRUE,
  150.     /* compress_exposure    */    TRUE,
  151.     /* compress_enterleave    */    TRUE,
  152.     /* visible_interest        */    FALSE,
  153.     /* destroy            */    Destroy,
  154.     /* resize            */    NULL,
  155.     /* expose            */    Redisplay,
  156.     /* set_values        */    SetValues,
  157.     /* set_values_hook        */    NULL,
  158.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  159.     /* get_values_hook        */    NULL,
  160.     /* accept_focus        */    NULL,
  161.     /* version            */    XtVersion,
  162.     /* callback_private        */    NULL,
  163.     /* tm_table            */    defaultTranslations,
  164.     /* query_geometry        */    XtInheritQueryGeometry,
  165.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  166.     /* extension        */    NULL
  167.     },
  168.     { /* simple fields */
  169.     /* change_sensitive         */    XtInheritChangeSensitive
  170.     },
  171.     { /* mailbox fields */
  172.     /* ignore                   */    0
  173.     }
  174. };
  175.  
  176. WidgetClass mailboxWidgetClass = (WidgetClass) &mailboxClassRec;
  177.  
  178.  
  179. /*
  180.  * widget initialization
  181.  */
  182.  
  183. static GC get_mailbox_gc (w)
  184.     MailboxWidget w;
  185. {
  186.     XtGCMask valuemask;
  187.     XGCValues xgcv;
  188.  
  189.     valuemask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
  190.     xgcv.foreground = w->mailbox.foreground_pixel;
  191.     xgcv.background = w->core.background_pixel;
  192.     xgcv.function = GXcopy;
  193.     xgcv.graphics_exposures = False;    /* this is Bool, not Boolean */
  194.     return (XtGetGC ((Widget) w, valuemask, &xgcv));
  195. }
  196.  
  197.  
  198. /* ARGSUSED */
  199. static void Initialize (request, new)
  200.     Widget request, new;
  201. {
  202.     MailboxWidget w = (MailboxWidget) new;
  203.     int shape_event_base, shape_error_base;
  204.  
  205.     if (w->core.width <= 0) w->core.width = 1;
  206.     if (w->core.height <= 0) w->core.height = 1;
  207.  
  208.     if (w->mailbox.shapeit && !XShapeQueryExtension (XtDisplay (w),
  209.                              &shape_event_base,
  210.                              &shape_error_base))
  211.       w->mailbox.shapeit = False;
  212.     w->mailbox.shape_cache.mask = None;
  213.     w->mailbox.gc = get_mailbox_gc (w);
  214.     w->mailbox.interval_id = (XtIntervalId) 0;
  215.     w->mailbox.full.pixmap = None;
  216.     w->mailbox.empty.pixmap = None;
  217.     w->mailbox.flag_up = FALSE;
  218.     w->mailbox.last_size = 0;
  219.     if (!w->mailbox.filename) GetMailFile (w);
  220.     return;
  221. }
  222.  
  223.  
  224. /*
  225.  * action procedures
  226.  */
  227.  
  228. /*
  229.  * pretend there is new mail; put widget in flagup state
  230.  */
  231.  
  232. /* ARGSUSED */
  233. static void Set (gw, event, params, nparams)
  234.     Widget gw;
  235.     XEvent *event;
  236.     String *params;
  237.     Cardinal *nparams;
  238. {
  239.     MailboxWidget w = (MailboxWidget) gw;
  240.  
  241.     w->mailbox.last_size = -1;
  242.  
  243.     check_mailbox (w, TRUE, FALSE);    /* redraw, no reset */
  244.  
  245.     return;
  246. }
  247.  
  248.  
  249. /*
  250.  * ack the existing mail; put widget in flagdown state
  251.  */
  252.  
  253. /* ARGSUSED */
  254. static void Unset (gw, event, params, nparams)
  255.     Widget gw;
  256.     XEvent *event;
  257.     String *params;
  258.     Cardinal *nparams;
  259. {
  260.     MailboxWidget w = (MailboxWidget) gw;
  261.  
  262.     check_mailbox (w, TRUE, TRUE);    /* redraw, reset */
  263.  
  264.     return;
  265. }
  266.  
  267.  
  268. /*
  269.  * look to see if there is new mail; if so, Set, else Unset
  270.  */
  271.  
  272. /* ARGSUSED */
  273. static void Check (gw, event, params, nparams)
  274.     Widget gw;
  275.     XEvent *event;
  276.     String *params;
  277.     Cardinal *nparams;
  278. {
  279.     MailboxWidget w = (MailboxWidget) gw;
  280.  
  281.     check_mailbox (w, TRUE, FALSE);    /* redraw, no reset */
  282.  
  283.     return;
  284. }
  285.  
  286.  
  287. /* ARGSUSED */
  288. static void clock_tic (client_data, id)
  289.     XtPointer client_data;
  290.     XtIntervalId *id;
  291. {
  292.     MailboxWidget w = (MailboxWidget) client_data;
  293.  
  294.     check_mailbox (w, FALSE, FALSE);    /* no redraw, no reset */
  295.  
  296.     /*
  297.      * and reset the timer
  298.      */
  299.  
  300.     w->mailbox.interval_id =
  301.     XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  302.              w->mailbox.update * 1000, clock_tic, client_data);
  303.  
  304.     return;
  305. }
  306.  
  307. static Pixmap make_pixmap (dpy, w, bitmap, depth, flip, widthp, heightp)
  308.     Display *dpy;
  309.     MailboxWidget w;
  310.     Pixmap bitmap;
  311.     Boolean flip;
  312.     int depth;
  313.     int *widthp, *heightp;
  314. {
  315.     Window root;
  316.     int x, y;
  317.     unsigned int width, height, bw, dep;
  318.     unsigned long fore, back;
  319.  
  320.     if (!XGetGeometry (dpy, bitmap, &root, &x, &y, &width, &height, &bw, &dep))
  321.       return None;
  322.  
  323.     *widthp = (int) width;
  324.     *heightp = (int) height;
  325.     if (flip) {
  326.     fore = w->core.background_pixel;
  327.     back = w->mailbox.foreground_pixel;
  328.     } else {
  329.     fore = w->mailbox.foreground_pixel;
  330.     back = w->core.background_pixel;
  331.     }
  332.     return XmuCreatePixmapFromBitmap (dpy, w->core.window, bitmap, 
  333.                       width, height, depth, fore, back);
  334. }
  335.  
  336. static void Realize (gw, valuemaskp, attr)
  337.     Widget gw;
  338.     XtValueMask *valuemaskp;
  339.     XSetWindowAttributes *attr;
  340. {
  341.     MailboxWidget w = (MailboxWidget) gw;
  342.     register Display *dpy = XtDisplay (w);
  343.     int depth = w->core.depth;
  344.  
  345.     *valuemaskp |= (CWBitGravity | CWCursor);
  346.     attr->bit_gravity = ForgetGravity;
  347.     attr->cursor = XCreateFontCursor (dpy, XC_top_left_arrow);
  348.  
  349.     (*mailboxWidgetClass->core_class.superclass->core_class.realize)
  350.     (gw, valuemaskp, attr);
  351.  
  352.     /*
  353.      * build up the pixmaps that we'll put into the image
  354.      */
  355.     if (w->mailbox.full.bitmap == None) {
  356.     w->mailbox.full.bitmap = 
  357.       XCreateBitmapFromData (dpy, w->core.window, (char *) mailfull_bits,
  358.                  mailfull_width, mailfull_height);
  359.     }
  360.     if (w->mailbox.empty.bitmap == None) {
  361.     w->mailbox.empty.bitmap =
  362.       XCreateBitmapFromData (dpy, w->core.window, (char *) mailempty_bits,
  363.                  mailempty_width, mailempty_height);
  364.     }
  365.  
  366.     w->mailbox.empty.pixmap = make_pixmap (dpy, w, w->mailbox.empty.bitmap,
  367.                        depth, False,
  368.                        &w->mailbox.empty.width,
  369.                        &w->mailbox.empty.height);
  370.     w->mailbox.full.pixmap = make_pixmap (dpy, w, w->mailbox.full.bitmap,
  371.                       depth, w->mailbox.flipit,
  372.                       &w->mailbox.full.width,
  373.                       &w->mailbox.full.height);
  374.              
  375.     if (w->mailbox.empty.mask == None && w->mailbox.full.mask == None)
  376.       w->mailbox.shapeit = False;
  377.  
  378.     w->mailbox.interval_id = 
  379.     XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
  380.              w->mailbox.update * 1000, clock_tic, (XtPointer) w);
  381.  
  382.     w->mailbox.shape_cache.mask = None;
  383.  
  384.     check_mailbox (w, TRUE, FALSE);
  385.  
  386.     return;
  387. }
  388.  
  389.  
  390. static void Destroy (gw)
  391.     Widget gw;
  392. {
  393.     MailboxWidget w = (MailboxWidget) gw;
  394.     Display *dpy = XtDisplay (gw);
  395.  
  396.     XtFree (w->mailbox.filename);
  397.     if (w->mailbox.interval_id) XtRemoveTimeOut (w->mailbox.interval_id);
  398.     XtReleaseGC(gw, w->mailbox.gc);
  399. #define freepix(p) if (p) XFreePixmap (dpy, p)
  400.     freepix (w->mailbox.full.bitmap);        /* until cvter does ref cnt */
  401.     freepix (w->mailbox.full.mask);        /* until cvter does ref cnt */
  402.     freepix (w->mailbox.full.pixmap);
  403.     freepix (w->mailbox.empty.bitmap);        /* until cvter does ref cnt */
  404.     freepix (w->mailbox.empty.mask);        /* until cvter does ref cnt */
  405.     freepix (w->mailbox.empty.pixmap);
  406.     freepix (w->mailbox.shape_cache.mask);
  407. #undef freepix
  408.     return;
  409. }
  410.  
  411.  
  412. static void Redisplay (gw)
  413.     Widget gw;
  414. {
  415.     MailboxWidget w = (MailboxWidget) gw;
  416.  
  417.     check_mailbox (w, TRUE, FALSE);
  418. }
  419.  
  420.  
  421. static void check_mailbox (w, force_redraw, reset)
  422.     MailboxWidget w;
  423.     Boolean force_redraw, reset;
  424. {
  425.     long mailboxsize = 0;
  426.     Boolean readSinceLastWrite = FALSE;
  427.  
  428.     if (w->mailbox.check_command != NULL) {
  429.     waitType wait_status;
  430.     int    check_status;
  431. #ifdef INTWAITTYPE
  432.     wait_status = system(w->mailbox.check_command);
  433. #else
  434.     wait_status.w_status = system(w->mailbox.check_command);
  435. #endif
  436.     check_status = waitCode(wait_status);
  437.  
  438.     /* error in sh checkCommand execution */
  439.     if (waitSig(wait_status))
  440.         check_status = 2;        /* act as if there is no mail */
  441.  
  442.     switch (check_status) {
  443.       case 0:
  444.         mailboxsize = w->mailbox.last_size + 1;
  445.         break;
  446.       case 2:
  447.         mailboxsize = 0;
  448.         break;
  449.       default:    /* treat everything else as no change */
  450.                     /* case 1 is no change */
  451.         mailboxsize = w->mailbox.last_size;
  452.     }
  453.     } else {
  454.     struct stat st;
  455.     if (stat (w->mailbox.filename, &st) == 0) {
  456.         mailboxsize = st.st_size;
  457.         readSinceLastWrite = (st.st_atime > st.st_mtime);
  458.     }
  459.     }
  460.  
  461.     /*
  462.      * Now check for changes.  If reset is set then we want to pretent that
  463.      * there is no mail.  If the mailbox is empty then we want to turn off
  464.      * the flag.  Otherwise if the mailbox has changed size then we want to
  465.      * put the flag up, unless the mailbox has been read since the last 
  466.      * write.
  467.      *
  468.      * The cases are:
  469.      *    o  forced reset by user                        DOWN
  470.      *    o  no mailbox or empty (zero-sized) mailbox    DOWN
  471.      *    o  if read after most recent write          DOWN
  472.      *    o  same size as last time                      no change
  473.      *    o  bigger than last time                       UP
  474.      *    o  smaller than last time but non-zero         UP
  475.      *
  476.      * The last two cases can be expressed as different from last
  477.      * time and non-zero.
  478.      */
  479.  
  480.     if (reset) {            /* forced reset */
  481.     w->mailbox.flag_up = FALSE;
  482.     force_redraw = TRUE;
  483.     } else if (mailboxsize == 0) {    /* no mailbox or empty */
  484.     w->mailbox.flag_up = FALSE;
  485.     if (w->mailbox.last_size > 0) force_redraw = TRUE;  /* if change */
  486.     } else if (readSinceLastWrite) {     /* only when checkCommand is NULL */
  487.     /* mailbox has been read after most recent write */
  488.     if (w->mailbox.flag_up) {
  489.         w->mailbox.flag_up = FALSE;
  490.         force_redraw = TRUE;
  491.     }
  492.     } else if (mailboxsize != w->mailbox.last_size) {  /* different size */
  493.     if (!w->mailbox.once_only || !w->mailbox.flag_up)
  494.         beep(w); 
  495.     if (!w->mailbox.flag_up)
  496.         force_redraw = w->mailbox.flag_up = TRUE;
  497.     } 
  498.  
  499.     w->mailbox.last_size = mailboxsize;
  500.     if (force_redraw) redraw_mailbox (w);
  501.     return;
  502. }
  503.  
  504. /*
  505.  * get user name for building mailbox
  506.  */
  507.  
  508. static void GetMailFile (w)
  509.     MailboxWidget w;
  510. {
  511.     char *getlogin();
  512.     char *username;
  513.  
  514.     username = getlogin ();
  515.     if (!username) {
  516.     struct passwd *pw = getpwuid (getuid ());
  517.  
  518.     if (!pw) {
  519.         fprintf (stderr, "%s:  unable to find a username for you.\n",
  520.              "Mailbox widget");
  521.         CloseDown (w, 1);
  522.     }
  523.     username = pw->pw_name;
  524.     }
  525.     w->mailbox.filename = (String) XtMalloc (strlen (MAILBOX_DIRECTORY) + 1 +
  526.                             strlen (username) + 1);
  527.     strcpy (w->mailbox.filename, MAILBOX_DIRECTORY);
  528.     strcat (w->mailbox.filename, "/");
  529.     strcat (w->mailbox.filename, username);
  530.     return;
  531. }
  532.  
  533. static void CloseDown (w, status)
  534.     MailboxWidget w;
  535.     int status;
  536. {
  537.     Display *dpy = XtDisplay (w);
  538.  
  539.     XtDestroyWidget ((Widget)w);
  540.     XCloseDisplay (dpy);
  541.     exit (status);
  542. }
  543.  
  544.  
  545. /* ARGSUSED */
  546. static Boolean SetValues (gcurrent, grequest, gnew)
  547.     Widget gcurrent, grequest, gnew;
  548. {
  549.     MailboxWidget current = (MailboxWidget) gcurrent;
  550.     MailboxWidget new = (MailboxWidget) gnew;
  551.     Boolean redisplay = FALSE;
  552.  
  553.     if (current->mailbox.update != new->mailbox.update) {
  554.     if (current->mailbox.interval_id) 
  555.       XtRemoveTimeOut (current->mailbox.interval_id);
  556.     new->mailbox.interval_id =
  557.         XtAppAddTimeOut (XtWidgetToApplicationContext(gnew),
  558.                  new->mailbox.update * 1000, clock_tic,
  559.                  (XtPointer) gnew);
  560.     }
  561.  
  562.     if (current->mailbox.foreground_pixel != new->mailbox.foreground_pixel ||
  563.     current->core.background_pixel != new->core.background_pixel) {
  564.     XtReleaseGC (gcurrent, current->mailbox.gc);
  565.     new->mailbox.gc = get_mailbox_gc (new);
  566.     redisplay = TRUE;
  567.     }
  568.  
  569.     return (redisplay);
  570. }
  571.  
  572.  
  573. /*
  574.  * drawing code
  575.  */
  576.  
  577. static void redraw_mailbox (w)
  578.     MailboxWidget w;
  579. {
  580.     register Display *dpy = XtDisplay (w);
  581.     register Window win = XtWindow (w);
  582.     register int x, y;
  583.     GC gc = w->mailbox.gc;
  584.     Pixel back = w->core.background_pixel;
  585.     struct _mbimage *im;
  586.  
  587.     /* center the picture in the window */
  588.  
  589.     if (w->mailbox.flag_up) {        /* paint the "up" position */
  590.     im = &w->mailbox.full;
  591.     if (w->mailbox.flipit) back = w->mailbox.foreground_pixel;
  592.     } else {                /* paint the "down" position */
  593.     im = &w->mailbox.empty;
  594.     }
  595.     x = (((int)w->core.width) - im->width) / 2;
  596.     y = (((int)w->core.height) - im->height) / 2;
  597.  
  598.     XSetWindowBackground (dpy, win, back);
  599.     XClearWindow (dpy, win);
  600.     XCopyArea (dpy, im->pixmap, win, gc, 0, 0, im->width, im->height, x, y);
  601.  
  602.     /*
  603.      * XXX - temporary hack; walk up widget tree to find top most parent (which
  604.      * will be a shell) and mash it to have our shape.  This will be replaced
  605.      * by a special shell widget.
  606.      */
  607.     if (w->mailbox.shapeit) {
  608.     Widget parent;
  609.  
  610.     for (parent = (Widget) w; XtParent(parent);
  611.          parent = XtParent(parent)) {
  612.         x += parent->core.x + parent->core.border_width;
  613.         y += parent->core.y + parent->core.border_width;
  614.     }
  615.  
  616.     if (im->mask != w->mailbox.shape_cache.mask ||
  617.         x != w->mailbox.shape_cache.x || y != w->mailbox.shape_cache.y) {
  618.         XShapeCombineMask (XtDisplay(parent), XtWindow(parent),
  619.                    ShapeBounding, x, y, im->mask, ShapeSet);
  620.         w->mailbox.shape_cache.mask = im->mask;
  621.         w->mailbox.shape_cache.x = x;
  622.         w->mailbox.shape_cache.y = y;
  623.     }
  624.     }
  625.  
  626.     return;
  627. }
  628.  
  629.  
  630. static void beep (w)
  631.     MailboxWidget w;
  632. {
  633.     XBell (XtDisplay (w), w->mailbox.volume);
  634.     return;
  635. }
  636.