123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655 |
- /* $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.4 2001/08/01 00:45:02 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 Set (Widget gw, XEvent *event, String *params, Cardinal *nparams);
- static void Check(Widget gw, XEvent *event, String *params, Cardinal *nparams);
- static void Unset(Widget gw, XEvent *event, String *params, Cardinal *nparams);
- 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(MailboxWidget w);
- static void CloseDown (MailboxWidget w, int status);
- static void check_mailbox(MailboxWidget w, Boolean force_redraw, Boolean reset);
- static void redraw_mailbox (MailboxWidget w);
- static void beep (MailboxWidget w);
- static void Initialize (Widget request, Widget new,
- ArgList args, Cardinal *num_args);
- static void Realize (Widget gw, XtValueMask *valuemaskp,
- XSetWindowAttributes *attr);
- static void Destroy (Widget gw);
- static void Redisplay (Widget gw, XEvent *event, Region region);
- static Boolean SetValues (Widget gcurrent, Widget grequest, Widget gnew,
- ArgList args, Cardinal *num_args);
- 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 (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 (Widget request, Widget 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 (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 */
- }
- /*
- * ack the existing mail; put widget in flagdown state
- */
- /* ARGSUSED */
- static void Unset (Widget gw, XEvent *event, String *params, Cardinal *nparams)
- {
- MailboxWidget w = (MailboxWidget) gw;
- check_mailbox (w, TRUE, TRUE); /* redraw, reset */
- }
- /*
- * look to see if there is new mail; if so, Set, else Unset
- */
- /* ARGSUSED */
- static void Check (Widget gw, XEvent *event, String *params, Cardinal *nparams)
- {
- MailboxWidget w = (MailboxWidget) gw;
- check_mailbox (w, TRUE, FALSE); /* redraw, no reset */
- }
- /* ARGSUSED */
- static void clock_tic (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 (Display *dpy, MailboxWidget w, Pixmap bitmap,
- int depth, Boolean flip, int *widthp, int *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 (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 (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
- }
- static void Redisplay (Widget gw, XEvent *event, Region region)
- {
- MailboxWidget w = (MailboxWidget) gw;
- check_mailbox (w, TRUE, FALSE);
- }
- static void check_mailbox (MailboxWidget w, Boolean force_redraw, Boolean 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 (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
- 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 (MailboxWidget 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 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 (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 (MailboxWidget w)
- {
- XBell (XtDisplay (w), w->mailbox.volume);
- return;
- }
|