/*
 * Copyright (c) 1998 Guylhem Aznar <guylhem@oeil.qc.ca>
 * Copyright (c) 1991 David A. Curry <davy@itstd.sri.com>
 * Copyright (c) 1996 Michael J. Hammel <mjhammel@csn.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * xpostit.c - Post-It Notes for the X Window System.
 * 
 * You can get David A. Curry's original public domain version on :
 * ftp://ftp.ers.ibm.com/pub/davy/xpostit3.3.2.tar.gz
 *
 */

#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <X11/Xaw/SimpleMenu.h>
#include <signal.h>
#include <stdio.h>

#include "xpostit.h"
#include "version.h"

/*
 * Command line options and the resources they set.
 */
static XrmOptionDescRec options[] =
{
    {"-bs", ".bufSize", XrmoptionSepArg, NULL},
    {"-dir", ".noteDir", XrmoptionSepArg, NULL},
    {"-interval", ".interval", XrmoptionSepArg, NULL},
    {"-sb", ".scrollBar", XrmoptionNoArg, "true"},
    {"-sv", ".saveNotes", XrmoptionNoArg, "true"},
    {"-c", ".compatibility", XrmoptionNoArg, "true"},
    {"-nw", ".nameWidth", XrmoptionSepArg, NULL},
    {"-ns", ".noSave", XrmoptionNoArg, "true"},
    {"-na", ".noAlarm", XrmoptionNoArg, "true"},
    {"-help", ".help", XrmoptionNoArg, "true"},
    {"-h", ".help", XrmoptionNoArg, "true"},
    {"-version", ".version", XrmoptionNoArg, "true"},
    {"-V", ".version", XrmoptionNoArg, "true"},
    {"-?", ".help", XrmoptionNoArg, "true"},
    {"-ao", ".anchorOffset", XrmoptionSepArg, NULL},
    {"-tmpdir", ".tmpDir", XrmoptionSepArg, NULL},
    {"-printcmd", ".printCmd", XrmoptionSepArg, NULL},
    {"-calendarcmd", ".calendarCmd", XrmoptionSepArg, NULL},
    {"-emailcmd", ".emailCmd", XrmoptionSepArg, NULL},
    {"-homedir", ".homeDir", XrmoptionSepArg, NULL},
};

/*
 * Fallback resources.
 */
static String fallback_resources[] =
{
#include "app_defaults.h"
    NULL
};

/*
 * Resources we maintain besides those maintained by the toolkit.
 */
static XtResource resources[] =
{
#define offset(field)	XtOffset(AppResPtr,field)
    {"bufSize", "BufSize", XtRInt, sizeof(int),
     offset(buf_size), XtRImmediate, (caddr_t) DefaultBufSize},
    {"noteDir", "NoteDir", XtRString, sizeof(String),
     offset(note_dir), XtRString, DefaultNoteDir},
    {"interval", "Interval", XtRInt, sizeof(int),
     offset(interval), XtRImmediate, (caddr_t) DefaultInterval},
    {"saveNotes", "SaveNotes", XtRBoolean, sizeof(Boolean),
     offset(save_notes), XtRImmediate, (caddr_t) False},
    {"scrollBar", "Scroll", XtRBoolean, sizeof(Boolean),
     offset(scroll_bar), XtRImmediate, (caddr_t) False},
    {"compatibility", "Compatibility", XtRBoolean, sizeof(Boolean),
     offset(compatibility), XtRImmediate, (caddr_t) False},
    {"nameWidth", "NameWidth", XtRInt, sizeof(int),
     offset(name_width), XtRImmediate, (caddr_t) DefaultNameWidth},
    {"noSave", "NoSave", XtRBoolean, sizeof(Boolean),
     offset(nosave), XtRImmediate, (caddr_t) False},
    {"noAlarm", "NoAlarm", XtRBoolean, sizeof(Boolean),
     offset(noalarm), XtRImmediate, (caddr_t) False},
    {"help", "Help", XtRBoolean, sizeof(Boolean),
     offset(help), XtRImmediate, (caddr_t) False},
    {"version", "Version", XtRBoolean, sizeof(Boolean),
     offset(version), XtRImmediate, (caddr_t) False},
    {"anchorOffset", "AnchorOffset", XtRInt, sizeof(int),
     offset(anchor_offset), XtRImmediate, (caddr_t) DefaultAnchorOffset},
    {"tmpDir", "TmpDir", XtRString, sizeof(String),
     offset(tmp_dir), XtRString, (caddr_t) DefaultTmpDir},
    {"printCmd", "PrintCmd", XtRString, sizeof(String),
     offset(print_cmd), XtRString, (caddr_t) DefaultPrintCmd},
    {"calendarCmd", "CalendarCmd", XtRString, sizeof(String),
     offset(calendar_cmd), XtRString, (caddr_t) DefaultCalendarCmd},
    {"emailCmd", "EmailCmd", XtRString, sizeof(String),
     offset(email_cmd), XtRString, (caddr_t) DefaultEmailCmd},
    {"homeDir", "HomeDir", XtRString, sizeof(String),
     offset(home_dir), XtRString, (caddr_t) DefaultHomeDir},
#undef offset
};

static Atom wm_delete_window, wm_save_yourself, wm_protocols, wm_command;
static void WMProtocolsHandler();

AppRes app_res;			/* xpostit application resources        */
Widget toplevel;		/* top level application shell widget   */
int screen;                     /* screen of the display                */
Display *display;		/* pointer to the display we're on      */
XtAppContext appcontext;	/* application context                  */
int curr_screenx, curr_screeny;	/* size of current screen */
XtIntervalId timer;		/* used for auto-save feature */
XtIntervalId alarm_timer;	/* used for alarms feature */

unsigned long timer_interval;	/* auto-save interval */
unsigned long alarm_interval;	/* alarm check interval */

void main(argc, argv)
char **argv;
int argc;
{
    char *appname;
    Atom protos[2];
    Boolean setsigs = False;

    /*
     * Ignore signals for now, but record whether they were
     * already ignored or not so we can catch them later if
     * need be.
     */
    if ((signal(SIGQUIT, SIG_IGN) != SIG_IGN) &&
	(signal(SIGINT, SIG_IGN) != SIG_IGN))
	setsigs = True;

    /*
     * Get application name.
     */
    if ((appname = rindex(*argv, '/')) == NULL)
	appname = *argv;
    else
	appname++;

    /*
     * Initialize the toolkit and create an application shell.
     */
    toplevel = XtAppInitialize(&appcontext, PostItNoteClass, options,
		      XtNumber(options), &argc, argv, fallback_resources,
			       NULL, 0);

    display = XtDisplay(toplevel);

    screen = DefaultScreen(display);
    curr_screenx = DisplayHeight(display, screen);
    curr_screeny = DisplayWidth(display, screen);

    /*
     * If we need to handle keyboard signals, do it now.
     */
    if (setsigs) {
	signal(SIGQUIT, ByeBye);
	signal(SIGINT, ByeBye);
    }
    /*
     * Always handle these.
     */
    signal(SIGTERM, ByeBye);
    signal(SIGHUP, ByeBye);

    /*
     * Send X errors to the exit routine.
     */
    XSetErrorHandler((XErrorHandler) ByeBye);

    /*
     * Now get any resources we're interested in.
     */
    XtGetApplicationResources(toplevel, &app_res, resources,
		   XtNumber(resources), (ArgList) argv, (Cardinal) argc);

    /*
     * if the user requested help, provide it
     */
    if (app_res.help) {
	printf(USAGE);
	exit(0);
    }
    /*
     * if the user requested the version, provide it
     */
    if (app_res.version) {
	printf("aspostit %s Copyright (c) 1998 Guylhem Aznar\n", AS_VERSION);
	printf("xpostit+ v%s\n", VERSION);
	printf("Copyright 1994-1996 Michael J. Hammel\n\n");
	exit(0);
    }
    /*
     * Construct the path to the directory notes are
     * stored in.
     */
    SetNoteDir();

    /*
     * Construct the path to the temporary directory ...
     */
    SetTempDir();

    /*
     * Create the plaid, menu, and list widgets.
     */
    CreatePlaidWidget();
    CreateMenuWidget();

    /*
     * Let the top level shell know about the menus.
     */
    XawSimpleMenuAddGlobalActions(appcontext);
    XtRealizeWidget(menuwidget);

    /*
     * Realize the top level and flush the server, which will
     * let the user position the plaid window and map it.
     */
    XtRealizeWidget(toplevel);

    /*
     * Set some properties for the window manager.
     */
    wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);
    wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
    wm_save_yourself = XInternAtom(display, "WM_SAVE_YOURSELF", False);

    protos[0] = wm_delete_window;
    protos[1] = wm_save_yourself;
    XSetWMProtocols(display, XtWindow(toplevel), protos, 2);
    XtAddEventHandler(toplevel, 0, True, WMProtocolsHandler, NULL);
    XtVaSetValues(toplevel, XtNwindowGroup, XtWindow(toplevel), NULL);

    /* Flush */
    XFlush(display);

    /*
     * Load the notes the user has saved, and create widgets
     * for them.
     */
    LoadSavedNotes();

    /*
     * Start the autosave timer, unless requested not to
     */
    if (!app_res.nosave) {
	timer_interval = app_res.interval * 60 * 1000;
	timer = XtAppAddTimeOut(
				   XtWidgetToApplicationContext(toplevel),
				   timer_interval,
				   AutoSave,
				   NULL);
    }
    /*
     * Start the alarm timer (once a minute)
     */
    if (!app_res.noalarm) {
	alarm_interval = 60 * 1000;
	alarm_timer = XtAppAddTimeOut(
				  XtWidgetToApplicationContext(toplevel),
					 alarm_interval,
					 AlarmCheck,
					 NULL);
    }
    /*
     * Never returns.
     */
    XtAppMainLoop(appcontext);
}


/*
 * WMProtocolsHandler - top level WM protocol handler.  WM_DELETE_WINDOW
 *                      is quit xpostit, WM_SAVE_YOURSELF is save all notes.
 */
static void WMProtocolsHandler(w, client_data, event, continue_to_dispatch)
Boolean *continue_to_dispatch;
XtPointer client_data;
XEvent *event;
Widget w;
{
    XClientMessageEvent *c_event = (XClientMessageEvent *) event;

    if (event->type != ClientMessage ||
	c_event->message_type != wm_protocols)
	return;

    if (c_event->data.l[0] == wm_delete_window) {
	ByeBye();
    } else if (c_event->data.l[0] == wm_save_yourself) {
	if (app_res.save_notes)
	    SaveAllNotes();
	/*
	 * Let session manager know we've saved ourself by doing
	 * a zero-length append on the WM_COMMAND property.
	 */
	XChangeProperty(XtDisplay(w), XtWindow(w), wm_command,
		  XA_STRING, 8, PropModeAppend, (unsigned char *) "", 0);
    }
}
