/* * @(#)Mailwatch.c - MODIFIED for use as an active icon in the xmail program. * * Author: Dan Heller * This code was stolen from Mailbox.c --the widget which supports "xbiff" * written by Jim Fulton which was apparently stolen from Clock.c, the widget * which supports "xclock." Note, you are witnessing the big bang theory of * software development (everything is a subclass of universeWidgetClass). * * Major changes: * XtRemoveTimeOut() is called before calling XtAddTimeOut(). The original * xbiff would eventually timeout all the time rather than every 30 seconds * because the old timer was never removed. * * User can specify any icon he chooses for either the up flag or the down * flag. Icons don't need to be the same size (defaults to flagup/flagdown). * * When new mail comes in, a user supplied callback function is invoked. * * The mailbox flag goes up when there is new mail _and_ the user hasn't * read it yet. As soon as the user updates the access time on the mailbox, * the flag goes down. This removes the incredibly annoying habit xbiff * had where you read some mail but not delete it from the mailbox and the * flag would remain up. * * Destroy() will now destroy the flagup and flagdown pixmaps. * ** July 1991 - Michael C. Wagnitz - National Semiconductor Corporation ** The following modifications were made for use in xmail. ** ** Added support for colored icons via the XPixMap format library libXpm.a ** ** November 1990 - Michael C. Wagnitz - National Semiconductor Corporation ** The following modifications were made for use in xmail. ** ** Added options to display username or host name in icon window. ** ** November 1989 - Michael C. Wagnitz - National Semiconductor Corporation ** ** Removed button handler, custom cursor, and 'from()' reader functions. ** Added reset_mailbox() function, my own icons (56x56 bits), and also ** added timer initialization to Initialize() routine (we might not ever be ** Realized, if the user never iconifies my parent). This also fixes a Sun4 ** bug for trying to remove an initial interval_id with a garbage address. ** Also changed check_mailbox() to test access time vs. modified and zero size ** of file, rather than trying to track our last access or increase in size. ** ** Copyright 1990,1991 by National Semiconductor Corporation ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose is hereby granted without fee, provided that ** the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation, and that the name of National Semiconductor Corporation not ** be used in advertising or publicity pertaining to distribution of the ** software without specific, written prior permission. ** ** NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE ** SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" ** WITHOUT EXPRESS OR IMPLIED WARRANTY. NATIONAL SEMICONDUCTOR CORPORATION ** DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO ** EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION 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. ** ** The following software modules were created and are Copyrighted by National ** Semiconductor Corporation: ** ** 1. reset_mailbox, ** 2. set_host, ** 3. set_user, ** 4. set_none, ** 5. GetHostName, and ** 6. XMyLocateXPixmapFile. ** ** Author: Michael C. Wagnitz - National Semiconductor Corporation */ #include #include /* for toolkit stuff */ #include /* for cursor constants */ #include /* for useful atom names */ #include #include "MailwatchP.h" /* for implementation mailbox stuff */ #include /* for printing error messages */ #include /* for stat() */ #include /* for MAXHOSTNAMELEN */ #include /* for getting username */ #ifndef XPM #include /* for XmuCvtStringToBitmap */ #include "icon.mail" /* for flag up (mail present) bits */ #include "icon.nomail" /* for flag down (mail not here) */ #else #include /* for XPixMap colored icons */ #include #include "mail.xpm" /* for flag up (mail present) bits */ #include "nomail.xpm" /* for flag down (mail not here) */ #define mail_width 64 #define mail_height 64 #define nomail_width 64 #define nomail_height 64 #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #define between(x, i, y) ((i) < (x) ? (x) : (i) > (y) ? (y) : (i)) #define REMOVE_TIMEOUT(id) if (!id) ; else XtRemoveTimeOut(id) extern XtActionProc Quit(); /* termination procedure */ static struct stat stbuf; static Boolean SetValues(Widget gcurrent, Widget grequest, Widget gnew, ArgList, Cardinal *); static Pixmap make_pixmap(Display *dpy, MailwatchWidget w, Pixmap bitmap, int depth, int *widthp, int *heightp); static GC GetNormalGC(MailwatchWidget w), GetInvertGC(MailwatchWidget w); static void GetMailFile(MailwatchWidget w), GetUserName(MailwatchWidget w), GetHostName(MailwatchWidget w), CloseDown(MailwatchWidget w, int status), check_mailbox(MailwatchWidget w, Boolean force_redraw), redraw_mailbox(MailwatchWidget m), ClassInitialize(void), Initialize(Widget request, Widget new, ArgList, Cardinal *), Destroy(Widget gw), Realize(Widget gw, XtValueMask *valuemaskp, XSetWindowAttributes *attr), Redisplay(Widget gw, XEvent *, Region), clock_tic(XtPointer client_data, XtIntervalId *id), set_title(String str); extern void reset_mailbox(Widget gw, int down), set_host(Widget, XEvent *, String *, Cardinal *), set_user(Widget, XEvent *, String *, Cardinal *), set_none(Widget, XEvent *, String *, Cardinal *); extern Widget toplevel; extern int RootWidth; extern int RootHeight; #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) static char defaultTranslations[] = "h: set-host() \n\ q: Quit(q) \n\ u: set-user() \n\ space: set-none()"; static XtActionsRec actionsList[] = { { "set-host", set_host }, { "set-user", set_user }, { "set-none", set_none }, }; /* Initialization of defaults */ #define offset(field) XtOffset(MailwatchWidget,mailbox.field) #define goffset(field) XtOffset(Widget,core.field) static XtResource resources[] = { {XtNupdate, XtCInterval, XtRInt, sizeof(int), offset(update), XtRImmediate, (XtPointer) 30 }, {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(foreground_pixel), XtRString, XtDefaultForeground }, {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), goffset(background_pixel), XtRString, XtDefaultBackground }, {XtNreverseVideo, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(reverseVideo), XtRImmediate, (XtPointer) False }, {XtNbell, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(bell), XtRImmediate, (XtPointer) True }, {XtNfile, XtCFile, XtRString, sizeof(String), offset(filename), XtRString, NULL}, #ifndef XPM {XtNmailFlag, XtCMailFlag, XtRBitmap, sizeof(Pixmap), offset(mail.bitmap), XtRString, NULL}, {XtNnoMailFlag, XtCNoMailFlag, XtRBitmap, sizeof(Pixmap), offset(nomail.bitmap), XtRString, NULL}, #else {XtNmailFlag, XtCMailFlag, XtRString, sizeof(String), offset(mail.bitmap), XtRString, NULL}, {XtNnoMailFlag, XtCNoMailFlag, XtRString, sizeof(String), offset(nomail.bitmap), XtRString, NULL}, #endif {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), offset(callback), XtRCallback, NULL}, {"useName", XtCBoolean, XtRBoolean, sizeof(Boolean), offset(useName), XtRString, "FALSE" }, {"useHost", XtCBoolean, XtRBoolean, sizeof(Boolean), offset(useHost), XtRString, "FALSE" }, { XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), offset(font), XtRString, XtDefaultFont}, }; #undef offset #undef goffset MailwatchClassRec mailwatchClassRec = { { /* core fields */ /* superclass */ &widgetClassRec, /* class_name */ "Mailwatch", /* widget_size */ sizeof(MailwatchRec), /* class_initialize */ ClassInitialize, /* 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 */ 0, /* 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 */ NULL, } }; WidgetClass mailwatchWidgetClass = (WidgetClass) & mailwatchClassRec; /* * private procedures */ static Pixmap make_pixmap (Display *dpy, MailwatchWidget w, Pixmap bitmap, int depth, int *widthp, int *heightp) { Window root; int x, y; unsigned int width, height, bw, dep; unsigned long fore, back; if (bitmap == 0 || ! XGetGeometry(dpy, bitmap, &root, &x, &y, &width, &height, &bw, &dep)) return None; *widthp = (int) width; *heightp = (int) height; fore = w->mailbox.foreground_pixel; back = w->core.background_pixel; return XmuCreatePixmapFromBitmap(dpy, w->core.window, bitmap, width, height, depth, fore, back); } static void ClassInitialize(void) { #ifndef XPM static XtConvertArgRec screenConvertArg[] = { { XtWidgetBaseOffset, (XtPointer) XtOffset(Widget, core.screen), sizeof(Screen *) } }; #endif XawInitializeWidgetSet(); #ifndef XPM XtAddConverter (XtRString, XtRBitmap, XmuCvtStringToBitmap, screenConvertArg, XtNumber(screenConvertArg)); #endif return; } /* ClassInitialize */ /* ARGSUSED */ static void Initialize(Widget request, Widget new, ArgList args, Cardinal *numArgs) { MailwatchWidget w = (MailwatchWidget) new; GetUserName(w); GetHostName(w); if (!w->mailbox.filename) GetMailFile(w); if (w->mailbox.reverseVideo) { Pixel tmp; tmp = w->mailbox.foreground_pixel; w->mailbox.foreground_pixel = w->core.background_pixel; w->core.background_pixel = tmp; } GetNormalGC(w); GetInvertGC(w); w->mailbox.flag_up = FALSE; /* because it hasn't been shown yet */ w->mailbox.mail.pixmap = None; w->mailbox.nomail.pixmap = None; w->mailbox.last_access = (stat(w->mailbox.filename, &stbuf) == 0) ? stbuf.st_atime : 0 ; /* last accessed */ return; } /* ARGSUSED */ static void clock_tic(XtPointer client_data, XtIntervalId *id) { MailwatchWidget w = (MailwatchWidget) client_data; check_mailbox(w, FALSE); } static void set_title(String str) { String c, name, title; Window win = XtWindow(toplevel); Display *dpy = XtDisplay(toplevel); (void) XFetchName(dpy, win, &name); if (! name) name = XtNewString("xmail"); else if ((c = (char *)strrchr(name, '_')) != NULL) *c = '\0'; if (! *str) title = (String) XtMalloc((unsigned) strlen(name) + 1); else title = (String) XtMalloc((unsigned) strlen(name) + strlen(str) + 2); if (! title) XtError("xmail: Insufficient memory to allocate title space"); if (! *str) (void) sprintf(title, "%s", name); else (void) sprintf(title, "%s_%s", name, str); XStoreName(dpy, win, title); XtFree((String) title); XtFree((String) name); } /* end - set_title */ void set_host(Widget widget, XEvent *event, String *params, Cardinal *num_params) { register MailwatchWidget m = (MailwatchWidget) widget; register Display *dpy = XtDisplay(m); register Window win = XtWindow(m); register int x, y, h, w; set_title(m->mailbox.mailhost); m->mailbox.useHost = True; m->mailbox.useName = False; h = m->mailbox.font->max_bounds.width - m->mailbox.font->max_bounds.lbearing; w = strlen(m->mailbox.mailhost); h = (h * w) - 2; x = max((int)m->core.width - h, 2); /* if (x < 2) x = 2; */ x /= 2; y = m->core.height - m->mailbox.font->descent; XFillRectangle(dpy, win, m->mailbox.invert_GC, 0, y - m->mailbox.font->ascent, m->core.width, m->mailbox.font->ascent + m->mailbox.font->descent); XDrawString(dpy, win, m->mailbox.normal_GC, x, y, m->mailbox.mailhost, w); } /* end - set_host */ void set_user(Widget widget, XEvent *event, String *params, Cardinal *numParams) { register MailwatchWidget m = (MailwatchWidget) widget; register Display *dpy = XtDisplay(m); register Window win = XtWindow(m); register int x, y, h, w; set_title(m->mailbox.username); m->mailbox.useHost = False; m->mailbox.useName = True; h = m->mailbox.font->max_bounds.width - m->mailbox.font->max_bounds.lbearing; w = strlen(m->mailbox.username); h = (h * w) - 2; x = max((int)m->core.width - h, 2); /* if (x < 2) x = 2; */ x /= 2; y = m->core.height - m->mailbox.font->descent; XFillRectangle(dpy, win, m->mailbox.invert_GC, 0, y - m->mailbox.font->ascent, m->core.width, m->mailbox.font->ascent + m->mailbox.font->descent); XDrawString(dpy, win, m->mailbox.normal_GC, x, y, m->mailbox.username, w); } /* end - set_user */ void set_none(Widget w, XEvent *event, String *params, Cardinal *num_params) { MailwatchWidget m = (MailwatchWidget) w; set_title(""); m->mailbox.useHost = m->mailbox.useName = False; redraw_mailbox(m); } /* end - set_none */ static GC GetNormalGC(MailwatchWidget 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; w->mailbox.normal_GC = XtGetGC((Widget) w, valuemask, &xgcv); } static GC GetInvertGC(MailwatchWidget w) { XtGCMask valuemask; XGCValues xgcv; valuemask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures; xgcv.foreground = w->core.background_pixel; xgcv.background = w->mailbox.foreground_pixel; xgcv.function = GXcopy; xgcv.graphics_exposures = False; /* this is Bool, not Boolean */ w->mailbox.invert_GC = XtGetGC((Widget) w, valuemask, &xgcv); } #ifdef XPM /* * split_path_string - split a colon-separated list into its constituent * parts; to release, free list[0] and list. From libXmu LocBitmap.c */ static char ** split_path_string (src) String src; { int nelems = 1; String dst; String *elemlist, *elem; /* count the number of elements */ for (dst = src; *dst; dst++) if (*dst == ':') nelems++; /* get memory for everything */ dst = (String) XtMalloc ((unsigned) (dst - src) + 1); if (!dst) return NULL; elemlist = (String *) XtMalloc ((unsigned) (nelems + 1) * sizeof(String)); if (!elemlist) { XtFree ((String) dst); return NULL; } /* copy to new list and walk up nulling colons and setting list pointers */ (void) strcpy (dst, src); for (elem = elemlist, src = dst; *src; src++) { if (*src == ':') { *elem++ = dst; *src = '\0'; dst = src + 1; } } *elem = dst; return elemlist; } String *bitmap_file_paths = NULL; #ifndef MAXPATHLEN #define MAXPATHLEN 256 #endif #ifndef BITMAPDIR #define BITMAPDIR "/usr/include/X11/bitmaps" #endif /* ** @(#)XMyLocateXPixmapFile() - Cloned from libXmu LocBitmap.c for use in XPM */ static Pixmap XMyLocateXPixmapFile(w, name, widthp, heightp) Widget w; char *name; int *widthp, *heightp; /* RETURN */ { int i; Bool try_plain_name = True; Display *dpy = XtDisplay(w); Pixmap pixmap; /* RETURN */ XrmName xrm_name[2]; XrmClass xrm_class[2]; XrmRepresentation rep_type; XrmValue value; char filename[MAXPATHLEN]; char **file_paths = NULL; XpmAttributes pmAttr; XrmDatabase db; /* ** look for bitmap path (only once, because we're going to call this twice) */ if (bitmap_file_paths == NULL) { xrm_name[0] = XrmStringToName ("bitmapFilePath"); xrm_name[1] = (XrmName) NULL; xrm_class[0] = XrmStringToClass ("BitmapFilePath"); xrm_class[1] = (XrmClass) NULL; db = XrmGetDatabase( dpy ); /* ** XXX - warning, derefing Display * until XDisplayDatabase */ if (!db) (void) XGetDefault (dpy, "", ""); db = XrmGetDatabase( dpy ); if (XrmQGetResource (db, xrm_name, xrm_class, &rep_type, &value) && rep_type == XrmStringToQuark(XtRString)) { bitmap_file_paths = split_path_string(value.addr); } } file_paths = bitmap_file_paths; /* ** Search order: ** 1. name if it begins with / or ./ ** 2. "each prefix in file_paths"/name ** 3. BITMAPDIR/name ** 4. name if didn't begin with / or . */ for (i = 1; i <= 4; i++) { String fn = filename; switch (i) { case 1: if (!(name[0] == '/' || (name[0] == '.') && name[1] == '/')) continue; fn = name; try_plain_name = False; break; case 2: if (file_paths && *file_paths) { (void) sprintf (filename, "%s/%s", *file_paths, name); file_paths++; i--; break; } continue; case 3: (void) sprintf (filename, "%s/%s", BITMAPDIR, name); break; case 4: if (!try_plain_name) continue; fn = name; break; } pmAttr.valuemask = XpmReturnPixels; if (PixmapSuccess == XpmReadFileToPixmap(dpy, w->core.window, fn, &pixmap, NULL, &pmAttr)) { *widthp = pmAttr.width; *heightp = pmAttr.height; return pixmap; } } return None; } #endif static void Realize(Widget gw, XtValueMask *valuemaskp, XSetWindowAttributes *attr) { #ifdef XPM int x, y; Pixmap bitmap, XmuLocateBitmapFile(); XpmAttributes pmAttr; #endif MailwatchWidget w = (MailwatchWidget) gw; int depth = w->core.depth; register Display *dpy = XtDisplay(w); Arg args[2]; XtCreateWindow(gw, InputOutput, (Visual *) CopyFromParent, *valuemaskp, attr); /* ** build up the pixmaps that we'll put into the icon image */ if (w->mailbox.mail.bitmap == None) { /* if user failed to specify an icon */ #ifndef XPM /* Non-XPM uses [no]mail.bitmap as a pixmap */ w->mailbox.mail.bitmap = XCreateBitmapFromData(dpy, w->core.window, mail_bits, mail_width, mail_height); w->mailbox.mail.pixmap = make_pixmap(dpy, w, w->mailbox.mail.bitmap, depth, &w->mailbox.mail.width, &w->mailbox.mail.height); } else { /* non-XPM used XmuConvertStringToPixmap */ w->mailbox.mail.pixmap = make_pixmap(dpy, w, w->mailbox.mail.bitmap, depth, &w->mailbox.mail.width, &w->mailbox.mail.height); #else pmAttr.valuemask = XpmReturnPixels; XpmCreatePixmapFromData(dpy, w->core.window, mail_xpm, &w->mailbox.mail.pixmap, NULL, &pmAttr); w->mailbox.mail.width = pmAttr.width; w->mailbox.mail.height = pmAttr.height; } else { /* ** Because for XPM we define mailbox.[no]mail.bitmap as a string, ** we must do the file conversion ourselves. First, see if it is ** a plain old bitmap file. Failing that, try for an XPM format ** file. Failing that, default to our internally defined xpm icon. */ if (bitmap = XmuLocateBitmapFile(w->core.screen, w->mailbox.mail.bitmap, NULL, 0, &w->mailbox.mail.width, &w->mailbox.mail.height, &x, &y)) w->mailbox.mail.pixmap = make_pixmap(dpy, w, bitmap, depth, &w->mailbox.mail.width, &w->mailbox.mail.height); else if (! (w->mailbox.mail.pixmap = XMyLocateXPixmapFile((Widget) w, w->mailbox.mail.bitmap, &w->mailbox.mail.width, &w->mailbox.mail.height))) { pmAttr.valuemask = XpmReturnPixels; XpmCreatePixmapFromData(dpy, w->core.window, mail_xpm, &w->mailbox.mail.pixmap, NULL, &pmAttr); w->mailbox.mail.width = pmAttr.width; w->mailbox.mail.height = pmAttr.height; } #endif } if (w->mailbox.nomail.bitmap == None) { #ifndef XPM w->mailbox.nomail.bitmap = XCreateBitmapFromData(dpy, w->core.window, no_mail_bits, no_mail_width, no_mail_height); w->mailbox.nomail.pixmap = make_pixmap(dpy, w, w->mailbox.nomail.bitmap, depth, &w->mailbox.nomail.width, &w->mailbox.nomail.height); } else { w->mailbox.nomail.pixmap = make_pixmap(dpy, w, w->mailbox.nomail.bitmap, depth, &w->mailbox.nomail.width, &w->mailbox.nomail.height); #else pmAttr.valuemask = XpmReturnPixels; XpmCreatePixmapFromData(dpy, w->core.window, nomail_xpm, &w->mailbox.nomail.pixmap, NULL, &pmAttr); w->mailbox.nomail.width = pmAttr.width; w->mailbox.nomail.height = pmAttr.height; } else { if (bitmap = XmuLocateBitmapFile(w->core.screen, w->mailbox.nomail.bitmap, NULL, 0, &w->mailbox.nomail.width, &w->mailbox.nomail.height, &x, &y)) w->mailbox.nomail.pixmap = make_pixmap(dpy, w, bitmap, depth, &w->mailbox.nomail.width, &w->mailbox.nomail.height); else if (! (w->mailbox.nomail.pixmap = XMyLocateXPixmapFile((Widget) w, w->mailbox.nomail.bitmap, &w->mailbox.nomail.width, &w->mailbox.nomail.height))) { pmAttr.valuemask = XpmReturnPixels; XpmCreatePixmapFromData(dpy, w->core.window, nomail_xpm, &w->mailbox.nomail.pixmap, NULL, &pmAttr); w->mailbox.nomail.width = pmAttr.width; w->mailbox.nomail.height = pmAttr.height; } #endif } /* ** the size of the icon should be the size of the larger icon image. */ w->core.width = max(w->mailbox.mail.width, w->mailbox.nomail.width); w->core.height = max(w->mailbox.mail.height, w->mailbox.nomail.height); XtSetArg(args[0], XtNwidth, (XtArgVal) w->core.width); XtSetArg(args[1], XtNheight, (XtArgVal) w->core.height); XtSetValues(XtNameToWidget(toplevel, "icon"), args, 2); /* set status check timer */ w->mailbox.interval_id = XtAddTimeOut(w->mailbox.update * 1000, clock_tic, (XtPointer) w); #ifdef XPM if (bitmap_file_paths) { XtFree((String) bitmap_file_paths[0]); XtFree((String) bitmap_file_paths); } #endif } static void Destroy(Widget gw) { MailwatchWidget w = (MailwatchWidget) gw; Display *dpy = XtDisplay(gw); XtFree((String) w->mailbox.filename); XtFree((String) w->mailbox.username); XtFree((String) w->mailbox.mailhost); REMOVE_TIMEOUT(w->mailbox.interval_id); XtReleaseGC((Widget)w, w->mailbox.normal_GC); #ifndef XPM XFreePixmap(dpy, w->mailbox.mail.bitmap); XFreePixmap(dpy, w->mailbox.nomail.bitmap); #endif XFreePixmap(dpy, w->mailbox.mail.pixmap); XFreePixmap(dpy, w->mailbox.nomail.pixmap); } static void Redisplay(Widget gw, XEvent *event, Region r) { MailwatchWidget w = (MailwatchWidget) gw; REMOVE_TIMEOUT(w->mailbox.interval_id); check_mailbox(w, TRUE); } /* ** Modified to NOT update the mail file timestamp via utimes(), and to ** ignore state change where mail adds a status record to the message. ** The first eliminates collisions with mail during delivery, and the ** second eliminates false triggers for new mail. The number of times ** the terminal bell is rung is controlled by the same .mailrc resource ** (bell) used by Sunview's mailtool. */ static void check_mailbox(MailwatchWidget w, Boolean force_redraw) { int i, redraw = 0; char *p = NULL; if (stat(w->mailbox.filename, &stbuf) < 0) { /* no mail file */ if (w->mailbox.flag_up == TRUE) { force_redraw = 0; UnsetNewmail(w, NULL, NULL); } } else { if (stbuf.st_atime > stbuf.st_mtime && stbuf.st_atime >= w->mailbox.last_access) { /* mail was seen */ w->mailbox.last_access = stbuf.st_atime; if (w->mailbox.flag_up == TRUE) { force_redraw = 0; UnsetNewmail(w, NULL, NULL); } } else { if (stbuf.st_size != 0 && stbuf.st_mtime > w->mailbox.last_access) { /* got new mail */ w->mailbox.last_access = stbuf.st_mtime; if (w->mailbox.flag_up == FALSE) { if (w->mailbox.bell) { i = 1; if (p = (char *)GetMailrc("bell")) (void) sscanf(p, "%d", &i); i = between(1, i, 5); for (; i > 0; i--) XBell(XtDisplay(w), MAILBOX_VOLUME); } w->mailbox.flag_up = TRUE; redraw = TRUE; XtCallCallbacks((Widget)w, XtNcallback, NULL); } } } } if (redraw || force_redraw) redraw_mailbox(w); /* reset timer */ w->mailbox.interval_id = XtAddTimeOut(w->mailbox.update * 1000, clock_tic, (XtPointer) w); } /* check_mailbox */ /* ** Retrieve the user's mailbox filename - use MAIL environment value, if set */ static void GetMailFile(MailwatchWidget w) { if (! (w->mailbox.filename = (String) GetMailEnv("MAIL"))) { if (! (w->mailbox.filename = (String) XtMalloc((unsigned) strlen(MAILBOX_DIRECTORY) + 2 + strlen(w->mailbox.username) + 1))) { (void) fprintf(stderr, "Mailbox widget: can't allocate enough memory.\n"); CloseDown(w, 1); } (void) sprintf(w->mailbox.filename, "%s/%s\0", MAILBOX_DIRECTORY, w->mailbox.username); } } /* GetMailFile */ /* ** Retrieve the mailbox user's name */ static void GetUserName(MailwatchWidget w) { char *username = (char *)getlogin(); if (! username) { struct passwd *pw = getpwuid((uid_t) getuid()); if (! pw) { (void) fprintf(stderr, "Mailbox widget: can't find your username.\n"); CloseDown(w, 1); } username = pw->pw_name; } if (! (w->mailbox.username = XtNewString(username))) { XtWarning("Mailbox widget: can't allocate space for username.\n"); CloseDown(w, 1); } } /* GetUserName */ /* ** Retrieve the process host name */ static void GetHostName(MailwatchWidget w) { char hostname[MAXHOSTNAMELEN]; (void) gethostname(hostname, MAXHOSTNAMELEN); if (! (w->mailbox.mailhost = XtNewString(hostname))) { XtWarning("Mailbox widget: can't allocate space for hostname.\n"); CloseDown(w, 1); } } /* GetHostName */ static void CloseDown(MailwatchWidget w, int status) { Display *dpy = XtDisplay(w); XtDestroyWidget((Widget)w); XCloseDisplay(dpy); _exit(status); } /* ARGSUSED */ static Boolean SetValues(Widget gcurrent, Widget grequest, Widget gnew, ArgList a, Cardinal *num_args) { MailwatchWidget current = (MailwatchWidget) gcurrent; MailwatchWidget new = (MailwatchWidget) gnew; Boolean redisplay = FALSE; if (current->mailbox.update != new->mailbox.update) { REMOVE_TIMEOUT(current->mailbox.interval_id); new->mailbox.interval_id = XtAddTimeOut(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((Widget)current, current->mailbox.normal_GC); GetNormalGC(new); redisplay = TRUE; } return (redisplay); } /* * drawing code */ static void redraw_mailbox(MailwatchWidget m) { register Display *dpy = XtDisplay(m); register Window win = XtWindow(m); register int x, y; Pixel back = m->core.background_pixel; GC gc = m->mailbox.normal_GC; struct _mbimage *im; if (m->mailbox.flag_up) /* paint the "up" position */ im = &m->mailbox.mail; else /* paint the "down" position */ im = &m->mailbox.nomail; /* center the picture in the window */ x = ((int)m->core.width - im->width) / 2; y = ((int)m->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); if (m->mailbox.useHost || m->mailbox.useName) { if (m->mailbox.useHost) set_host((Widget)m, (XEvent *) NULL, (String *) NULL, (Cardinal *) NULL); else set_user((Widget)m, (XEvent *)NULL, (String *) NULL, (Cardinal *) NULL); } } void reset_mailbox(Widget gw, int down) { MailwatchWidget w = (MailwatchWidget) gw; char *p; int i; if (down) w->mailbox.flag_up = FALSE; else { if (w->mailbox.flag_up == FALSE) { if (w->mailbox.bell) { i = 1; if (p = (char *)GetMailrc("bell")) (void) sscanf(p, "%d", &i); i = between(1, i, 5); for (; i > 0; i--) XBell(XtDisplay(w), MAILBOX_VOLUME); } } w->mailbox.flag_up = TRUE; } redraw_mailbox(w); } /* reset_mailbox */