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