diff options
Diffstat (limited to 'Mailbox.c')
-rw-r--r-- | Mailbox.c | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/Mailbox.c b/Mailbox.c new file mode 100644 index 0000000..eb6aad6 --- /dev/null +++ b/Mailbox.c @@ -0,0 +1,687 @@ +/* $XConsortium: Mailbox.c,v 1.64 94/04/17 20:43:26 rws Exp $ */ +/* + +Copyright (c) 1988 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ +/* $XFree86: xc/programs/xbiff/Mailbox.c,v 1.5 2001/10/28 03:34:25 tsi Exp $ */ + +/* + * Author: Jim Fulton, MIT X Consortium + * + * I recommend that you use the new mailfull and mailempty bitmaps instead of + * the ugly mailboxes: + * + * XBiff*fullPixmap: mailfull + * XBiff*emptyPixmap: mailempty + */ + +#include <X11/IntrinsicP.h> /* for toolkit stuff */ +#include <X11/StringDefs.h> /* for useful atom names */ +#include <X11/cursorfont.h> /* for cursor constants */ +#include <X11/Xosdefs.h> /* for X_NOT_POSIX def */ +#include <stdlib.h> +#ifdef WIN32 +#include <X11/Xw32defs.h> +#else +#include <pwd.h> /* for getting username */ +#endif +#include <sys/stat.h> /* for stat() ** needs types.h ***/ +#include <stdio.h> /* for printing error messages */ +#include <unistd.h> + +#ifndef X_NOT_POSIX +#ifdef _POSIX_SOURCE +# include <sys/wait.h> +#else +#define _POSIX_SOURCE +# include <sys/wait.h> +#undef _POSIX_SOURCE +#endif +# define waitCode(w) WEXITSTATUS(w) +# define waitSig(w) WIFSIGNALED(w) +typedef int waitType; +# define INTWAITTYPE +#else /* ! X_NOT_POSIX */ +#ifdef SYSV +# define waitCode(w) (((w) >> 8) & 0x7f) +# define waitSig(w) ((w) & 0xff) +typedef int waitType; +# define INTWAITTYPE +#else +#ifdef WIN32 +#include <process.h> +# define INTWAITTYPE +typedef int waitType; +# define waitCode(w) (w) +# define waitSig(w) (0) +#else +# include <sys/wait.h> +# define waitCode(w) ((w).w_T.w_Retcode) +# define waitSig(w) ((w).w_T.w_Termsig) +typedef union wait waitType; +#endif /* WIN32 else */ +#endif /* SYSV else */ +#endif /* ! X_NOT_POSIX else */ + +#include <X11/bitmaps/mailfull> /* for flag up (mail present) bits */ +#include <X11/bitmaps/mailempty> /* for flag down (mail not here) */ + +#include <X11/Xaw/XawInit.h> +#include "MailboxP.h" /* for implementation mailbox stuff */ +#include <X11/Xmu/Drawing.h> +#include <X11/extensions/shape.h> + +/* + * The default user interface is to have the mailbox turn itself off whenever + * the user presses a button in it. Expert users might want to make this + * happen on EnterWindow. It might be nice to provide support for some sort of + * exit callback so that you can do things like press q to quit. + */ + +static char defaultTranslations[] = + "<ButtonPress>: unset()"; + +static void Check(), Set(), Unset(); + +static XtActionsRec actionsList[] = { + { "check", Check }, + { "unset", Unset }, + { "set", Set }, +}; + + +/* Initialization of defaults */ + +#define offset(field) XtOffsetOf(MailboxRec, mailbox.field) +#define goffset(field) XtOffsetOf(WidgetRec, core.field) + +static Dimension defDim = 48; +static Pixmap nopix = None; + +static XtResource resources[] = { + { XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension), + goffset (width), XtRDimension, (XtPointer)&defDim }, + { XtNheight, XtCHeight, XtRDimension, sizeof (Dimension), + goffset (height), XtRDimension, (XtPointer)&defDim }, + { XtNupdate, XtCInterval, XtRInt, sizeof (int), + offset (update), XtRString, "30" }, + { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel), + offset (foreground_pixel), XtRString, XtDefaultForeground }, + { XtNfile, XtCFile, XtRString, sizeof (String), + offset (filename), XtRString, NULL }, + { XtNcheckCommand, XtCCheckCommand, XtRString, sizeof(char*), + offset (check_command), XtRString, NULL}, + { XtNvolume, XtCVolume, XtRInt, sizeof(int), + offset (volume), XtRString, "33"}, + { XtNonceOnly, XtCBoolean, XtRBoolean, sizeof(Boolean), + offset (once_only), XtRImmediate, (XtPointer)False }, + { XtNfullPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap), + offset (full.bitmap), XtRString, "flagup" }, + { XtNfullPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap), + offset (full.mask), XtRBitmap, (XtPointer) &nopix }, + { XtNemptyPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap), + offset (empty.bitmap), XtRString, "flagdown" }, + { XtNemptyPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap), + offset (empty.mask), XtRBitmap, (XtPointer) &nopix }, + { XtNflip, XtCFlip, XtRBoolean, sizeof(Boolean), + offset (flipit), XtRString, "true" }, + { XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof(Boolean), + offset (shapeit), XtRString, "false" }, +}; + +#undef offset +#undef goffset + +static void GetMailFile(), CloseDown(); +static void check_mailbox(), redraw_mailbox(), beep(); +static void Initialize(), Realize(), Destroy(), Redisplay(); +static Boolean SetValues(); + +MailboxClassRec mailboxClassRec = { + { /* core fields */ + /* superclass */ (WidgetClass) &simpleClassRec, + /* class_name */ "Mailbox", + /* widget_size */ sizeof(MailboxRec), + /* class_initialize */ XawInitializeWidgetSet, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ Initialize, + /* initialize_hook */ NULL, + /* realize */ Realize, + /* actions */ actionsList, + /* num_actions */ XtNumber(actionsList), + /* resources */ resources, + /* resource_count */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ Destroy, + /* resize */ NULL, + /* expose */ Redisplay, + /* set_values */ SetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ defaultTranslations, + /* query_geometry */ XtInheritQueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + }, + { /* simple fields */ + /* change_sensitive */ XtInheritChangeSensitive + }, + { /* mailbox fields */ + /* ignore */ 0 + } +}; + +WidgetClass mailboxWidgetClass = (WidgetClass) &mailboxClassRec; + + +/* + * widget initialization + */ + +static GC get_mailbox_gc (w) + MailboxWidget w; +{ + XtGCMask valuemask; + XGCValues xgcv; + + valuemask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures; + xgcv.foreground = w->mailbox.foreground_pixel; + xgcv.background = w->core.background_pixel; + xgcv.function = GXcopy; + xgcv.graphics_exposures = False; /* this is Bool, not Boolean */ + return (XtGetGC ((Widget) w, valuemask, &xgcv)); +} + + +/* ARGSUSED */ +static void Initialize (request, new, args, num_args) + Widget request, new; + ArgList args; + Cardinal *num_args; +{ + MailboxWidget w = (MailboxWidget) new; + int shape_event_base, shape_error_base; + + if (w->core.width <= 0) w->core.width = 1; + if (w->core.height <= 0) w->core.height = 1; + + if (w->mailbox.shapeit && !XShapeQueryExtension (XtDisplay (w), + &shape_event_base, + &shape_error_base)) + w->mailbox.shapeit = False; + w->mailbox.shape_cache.mask = None; + w->mailbox.gc = get_mailbox_gc (w); + w->mailbox.interval_id = (XtIntervalId) 0; + w->mailbox.full.pixmap = None; + w->mailbox.empty.pixmap = None; + w->mailbox.flag_up = FALSE; + w->mailbox.last_size = 0; + if (!w->mailbox.filename) GetMailFile (w); + return; +} + + +/* + * action procedures + */ + +/* + * pretend there is new mail; put widget in flagup state + */ + +/* ARGSUSED */ +static void Set (gw, event, params, nparams) + Widget gw; + XEvent *event; + String *params; + Cardinal *nparams; +{ + MailboxWidget w = (MailboxWidget) gw; + + w->mailbox.last_size = -1; + + check_mailbox (w, TRUE, FALSE); /* redraw, no reset */ + + return; +} + + +/* + * ack the existing mail; put widget in flagdown state + */ + +/* ARGSUSED */ +static void Unset (gw, event, params, nparams) + Widget gw; + XEvent *event; + String *params; + Cardinal *nparams; +{ + MailboxWidget w = (MailboxWidget) gw; + + check_mailbox (w, TRUE, TRUE); /* redraw, reset */ + + return; +} + + +/* + * look to see if there is new mail; if so, Set, else Unset + */ + +/* ARGSUSED */ +static void Check (gw, event, params, nparams) + Widget gw; + XEvent *event; + String *params; + Cardinal *nparams; +{ + MailboxWidget w = (MailboxWidget) gw; + + check_mailbox (w, TRUE, FALSE); /* redraw, no reset */ + + return; +} + + +/* ARGSUSED */ +static void clock_tic (client_data, id) + XtPointer client_data; + XtIntervalId *id; +{ + MailboxWidget w = (MailboxWidget) client_data; + + check_mailbox (w, FALSE, FALSE); /* no redraw, no reset */ + + /* + * and reset the timer + */ + + w->mailbox.interval_id = + XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w), + w->mailbox.update * 1000, clock_tic, client_data); + + return; +} + +static Pixmap make_pixmap (dpy, w, bitmap, depth, flip, widthp, heightp) + Display *dpy; + MailboxWidget w; + Pixmap bitmap; + Boolean flip; + int depth; + int *widthp, *heightp; +{ + Window root; + int x, y; + unsigned int width, height, bw, dep; + unsigned long fore, back; + + if (!XGetGeometry (dpy, bitmap, &root, &x, &y, &width, &height, &bw, &dep)) + return None; + + *widthp = (int) width; + *heightp = (int) height; + if (flip) { + fore = w->core.background_pixel; + back = w->mailbox.foreground_pixel; + } else { + fore = w->mailbox.foreground_pixel; + back = w->core.background_pixel; + } + return XmuCreatePixmapFromBitmap (dpy, w->core.window, bitmap, + width, height, depth, fore, back); +} + +static void Realize (gw, valuemaskp, attr) + Widget gw; + XtValueMask *valuemaskp; + XSetWindowAttributes *attr; +{ + MailboxWidget w = (MailboxWidget) gw; + register Display *dpy = XtDisplay (w); + int depth = w->core.depth; + + *valuemaskp |= (CWBitGravity | CWCursor); + attr->bit_gravity = ForgetGravity; + attr->cursor = XCreateFontCursor (dpy, XC_top_left_arrow); + + (*mailboxWidgetClass->core_class.superclass->core_class.realize) + (gw, valuemaskp, attr); + + /* + * build up the pixmaps that we'll put into the image + */ + if (w->mailbox.full.bitmap == None) { + w->mailbox.full.bitmap = + XCreateBitmapFromData (dpy, w->core.window, (char *) mailfull_bits, + mailfull_width, mailfull_height); + } + if (w->mailbox.empty.bitmap == None) { + w->mailbox.empty.bitmap = + XCreateBitmapFromData (dpy, w->core.window, (char *) mailempty_bits, + mailempty_width, mailempty_height); + } + + w->mailbox.empty.pixmap = make_pixmap (dpy, w, w->mailbox.empty.bitmap, + depth, False, + &w->mailbox.empty.width, + &w->mailbox.empty.height); + w->mailbox.full.pixmap = make_pixmap (dpy, w, w->mailbox.full.bitmap, + depth, w->mailbox.flipit, + &w->mailbox.full.width, + &w->mailbox.full.height); + + if (w->mailbox.empty.mask == None && w->mailbox.full.mask == None) + w->mailbox.shapeit = False; + + w->mailbox.interval_id = + XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w), + w->mailbox.update * 1000, clock_tic, (XtPointer) w); + + w->mailbox.shape_cache.mask = None; + + check_mailbox (w, TRUE, FALSE); + + return; +} + + +static void Destroy (gw) + Widget gw; +{ + MailboxWidget w = (MailboxWidget) gw; + Display *dpy = XtDisplay (gw); + + XtFree (w->mailbox.filename); + if (w->mailbox.interval_id) XtRemoveTimeOut (w->mailbox.interval_id); + XtReleaseGC(gw, w->mailbox.gc); +#define freepix(p) if (p) XFreePixmap (dpy, p) + freepix (w->mailbox.full.bitmap); /* until cvter does ref cnt */ + freepix (w->mailbox.full.mask); /* until cvter does ref cnt */ + freepix (w->mailbox.full.pixmap); + freepix (w->mailbox.empty.bitmap); /* until cvter does ref cnt */ + freepix (w->mailbox.empty.mask); /* until cvter does ref cnt */ + freepix (w->mailbox.empty.pixmap); + freepix (w->mailbox.shape_cache.mask); +#undef freepix + return; +} + + +static void Redisplay (gw, event, region) + Widget gw; + XEvent *event; + Region region; +{ + MailboxWidget w = (MailboxWidget) gw; + + check_mailbox (w, TRUE, FALSE); +} + + +static void check_mailbox (w, force_redraw, reset) + MailboxWidget w; + Boolean force_redraw, reset; +{ + long mailboxsize = 0; + Boolean readSinceLastWrite = FALSE; + + if (w->mailbox.check_command != NULL) { + waitType wait_status; + int check_status; +#ifdef INTWAITTYPE + wait_status = system(w->mailbox.check_command); +#else + wait_status.w_status = system(w->mailbox.check_command); +#endif + check_status = waitCode(wait_status); + + /* error in sh checkCommand execution */ + if (waitSig(wait_status)) + check_status = 2; /* act as if there is no mail */ + + switch (check_status) { + case 0: + mailboxsize = w->mailbox.last_size + 1; + break; + case 2: + mailboxsize = 0; + break; + default: /* treat everything else as no change */ + /* case 1 is no change */ + mailboxsize = w->mailbox.last_size; + } + } else { + struct stat st; + if (stat (w->mailbox.filename, &st) == 0) { + mailboxsize = st.st_size; + readSinceLastWrite = (st.st_atime > st.st_mtime); + } + } + + /* + * Now check for changes. If reset is set then we want to pretent that + * there is no mail. If the mailbox is empty then we want to turn off + * the flag. Otherwise if the mailbox has changed size then we want to + * put the flag up, unless the mailbox has been read since the last + * write. + * + * The cases are: + * o forced reset by user DOWN + * o no mailbox or empty (zero-sized) mailbox DOWN + * o if read after most recent write DOWN + * o same size as last time no change + * o bigger than last time UP + * o smaller than last time but non-zero UP + * + * The last two cases can be expressed as different from last + * time and non-zero. + */ + + if (reset) { /* forced reset */ + w->mailbox.flag_up = FALSE; + force_redraw = TRUE; + } else if (mailboxsize == 0) { /* no mailbox or empty */ + w->mailbox.flag_up = FALSE; + if (w->mailbox.last_size > 0) force_redraw = TRUE; /* if change */ + } else if (readSinceLastWrite) { /* only when checkCommand is NULL */ + /* mailbox has been read after most recent write */ + if (w->mailbox.flag_up) { + w->mailbox.flag_up = FALSE; + force_redraw = TRUE; + } + } else if (mailboxsize != w->mailbox.last_size) { /* different size */ + if (!w->mailbox.once_only || !w->mailbox.flag_up) + beep(w); + if (!w->mailbox.flag_up) + force_redraw = w->mailbox.flag_up = TRUE; + } + + w->mailbox.last_size = mailboxsize; + if (force_redraw) redraw_mailbox (w); + return; +} + +/* + * get user name for building mailbox + */ + +static void GetMailFile (w) + MailboxWidget w; +{ + char *username; + char *mailpath; +#ifdef WIN32 + if (!(username = getenv("USERNAME"))) { + fprintf (stderr, "%s: unable to find a username for you.\n", + "Mailbox widget"); + CloseDown (w, 1); + } +#else + char *getlogin(); + + username = getlogin (); + if (!username) { + struct passwd *pw = getpwuid (getuid ()); + + if (!pw) { + fprintf (stderr, "%s: unable to find a username for you.\n", + "Mailbox widget"); + CloseDown (w, 1); + } + username = pw->pw_name; + } +#endif + if ((mailpath = getenv("MAIL"))) { + w->mailbox.filename = (String) XtMalloc (strlen (mailpath) + 1); + strcpy (w->mailbox.filename, mailpath); + } else { + w->mailbox.filename = (String) XtMalloc (strlen (MAILBOX_DIRECTORY) + 1 + + strlen (username) + 1); + strcpy (w->mailbox.filename, MAILBOX_DIRECTORY); + strcat (w->mailbox.filename, "/"); + strcat (w->mailbox.filename, username); + } + return; +} + +static void CloseDown (w, status) + MailboxWidget w; + int status; +{ + Display *dpy = XtDisplay (w); + + XtDestroyWidget ((Widget)w); + XCloseDisplay (dpy); + exit (status); +} + + +/* ARGSUSED */ +static Boolean SetValues (gcurrent, grequest, gnew, args, num_args) + Widget gcurrent, grequest, gnew; + ArgList args; + Cardinal *num_args; +{ + MailboxWidget current = (MailboxWidget) gcurrent; + MailboxWidget new = (MailboxWidget) gnew; + Boolean redisplay = FALSE; + + if (current->mailbox.update != new->mailbox.update) { + if (current->mailbox.interval_id) + XtRemoveTimeOut (current->mailbox.interval_id); + new->mailbox.interval_id = + XtAppAddTimeOut (XtWidgetToApplicationContext(gnew), + new->mailbox.update * 1000, clock_tic, + (XtPointer) gnew); + } + + if (current->mailbox.foreground_pixel != new->mailbox.foreground_pixel || + current->core.background_pixel != new->core.background_pixel) { + XtReleaseGC (gcurrent, current->mailbox.gc); + new->mailbox.gc = get_mailbox_gc (new); + redisplay = TRUE; + } + + return (redisplay); +} + + +/* + * drawing code + */ + +static void redraw_mailbox (w) + MailboxWidget w; +{ + register Display *dpy = XtDisplay (w); + register Window win = XtWindow (w); + register int x, y; + GC gc = w->mailbox.gc; + Pixel back = w->core.background_pixel; + struct _mbimage *im; + + /* center the picture in the window */ + + if (w->mailbox.flag_up) { /* paint the "up" position */ + im = &w->mailbox.full; + if (w->mailbox.flipit) back = w->mailbox.foreground_pixel; + } else { /* paint the "down" position */ + im = &w->mailbox.empty; + } + x = (((int)w->core.width) - im->width) / 2; + y = (((int)w->core.height) - im->height) / 2; + + XSetWindowBackground (dpy, win, back); + XClearWindow (dpy, win); + XCopyArea (dpy, im->pixmap, win, gc, 0, 0, im->width, im->height, x, y); + + /* + * XXX - temporary hack; walk up widget tree to find top most parent (which + * will be a shell) and mash it to have our shape. This will be replaced + * by a special shell widget. + */ + if (w->mailbox.shapeit) { + Widget parent; + + for (parent = (Widget) w; XtParent(parent); + parent = XtParent(parent)) { + x += parent->core.x + parent->core.border_width; + y += parent->core.y + parent->core.border_width; + } + + if (im->mask != w->mailbox.shape_cache.mask || + x != w->mailbox.shape_cache.x || y != w->mailbox.shape_cache.y) { + XShapeCombineMask (XtDisplay(parent), XtWindow(parent), + ShapeBounding, x, y, im->mask, ShapeSet); + w->mailbox.shape_cache.mask = im->mask; + w->mailbox.shape_cache.x = x; + w->mailbox.shape_cache.y = y; + } + } + + return; +} + + +static void beep (w) + MailboxWidget w; +{ + XBell (XtDisplay (w), w->mailbox.volume); + return; +} |