1 /*
2  * Copyright (c) 1998 Guylhem Aznar <guylhem@oeil.qc.ca>
3  * Copyright (c) 1991 David A. Curry <davy@itstd.sri.com>
4  * Copyright (c) 1996 Michael J. Hammel <mjhammel@csn.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * xpostit.c - Post-It Notes for the X Window System.
21  *
22  * You can get David A. Curry's original public domain version on :
23  * ftp://ftp.ers.ibm.com/pub/davy/xpostit3.3.2.tar.gz
24  *
25  */
26 
27 #include <X11/StringDefs.h>
28 #include <X11/Intrinsic.h>
29 #include <X11/Shell.h>
30 #include <X11/Xatom.h>
31 #include <X11/Xos.h>
32 #include <X11/Xaw/SimpleMenu.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 
37 #include "xpostit.h"
38 #include "version.h"
39 
40 /*
41  * Command line options and the resources they set.
42  */
43 static XrmOptionDescRec options[] =
44 {
45     {"-bs", ".bufSize", XrmoptionSepArg, NULL},
46     {"-dir", ".noteDir", XrmoptionSepArg, NULL},
47     {"-interval", ".interval", XrmoptionSepArg, NULL},
48     {"-sb", ".scrollBar", XrmoptionNoArg, "true"},
49     {"-sv", ".saveNotes", XrmoptionNoArg, "true"},
50     {"-c", ".compatibility", XrmoptionNoArg, "true"},
51     {"-nw", ".nameWidth", XrmoptionSepArg, NULL},
52     {"-ns", ".noSave", XrmoptionNoArg, "true"},
53     {"-na", ".noAlarm", XrmoptionNoArg, "true"},
54     {"-help", ".help", XrmoptionNoArg, "true"},
55     {"-h", ".help", XrmoptionNoArg, "true"},
56     {"-version", ".version", XrmoptionNoArg, "true"},
57     {"-V", ".version", XrmoptionNoArg, "true"},
58     {"-?", ".help", XrmoptionNoArg, "true"},
59     {"-ao", ".anchorOffset", XrmoptionSepArg, NULL},
60     {"-tmpdir", ".tmpDir", XrmoptionSepArg, NULL},
61     {"-printcmd", ".printCmd", XrmoptionSepArg, NULL},
62     {"-calendarcmd", ".calendarCmd", XrmoptionSepArg, NULL},
63     {"-emailcmd", ".emailCmd", XrmoptionSepArg, NULL},
64     {"-homedir", ".homeDir", XrmoptionSepArg, NULL},
65 };
66 
67 /*
68  * Fallback resources.
69  */
70 static String fallback_resources[] =
71 {
72 #include "app_defaults.h"
73     NULL
74 };
75 
76 /*
77  * Resources we maintain besides those maintained by the toolkit.
78  */
79 static XtResource resources[] =
80 {
81 #define offset(field)	XtOffset(AppResPtr,field)
82     {"bufSize", "BufSize", XtRInt, sizeof(int),
83      offset(buf_size), XtRImmediate, (caddr_t) DefaultBufSize},
84     {"noteDir", "NoteDir", XtRString, sizeof(String),
85      offset(note_dir), XtRString, DefaultNoteDir},
86     {"interval", "Interval", XtRInt, sizeof(int),
87      offset(interval), XtRImmediate, (caddr_t) DefaultInterval},
88     {"saveNotes", "SaveNotes", XtRBoolean, sizeof(Boolean),
89      offset(save_notes), XtRImmediate, (caddr_t) False},
90     {"scrollBar", "Scroll", XtRBoolean, sizeof(Boolean),
91      offset(scroll_bar), XtRImmediate, (caddr_t) False},
92     {"compatibility", "Compatibility", XtRBoolean, sizeof(Boolean),
93      offset(compatibility), XtRImmediate, (caddr_t) False},
94     {"nameWidth", "NameWidth", XtRInt, sizeof(int),
95      offset(name_width), XtRImmediate, (caddr_t) DefaultNameWidth},
96     {"noSave", "NoSave", XtRBoolean, sizeof(Boolean),
97      offset(nosave), XtRImmediate, (caddr_t) False},
98     {"noAlarm", "NoAlarm", XtRBoolean, sizeof(Boolean),
99      offset(noalarm), XtRImmediate, (caddr_t) False},
100     {"help", "Help", XtRBoolean, sizeof(Boolean),
101      offset(help), XtRImmediate, (caddr_t) False},
102     {"version", "Version", XtRBoolean, sizeof(Boolean),
103      offset(version), XtRImmediate, (caddr_t) False},
104     {"anchorOffset", "AnchorOffset", XtRInt, sizeof(int),
105      offset(anchor_offset), XtRImmediate, (caddr_t) DefaultAnchorOffset},
106     {"tmpDir", "TmpDir", XtRString, sizeof(String),
107      offset(tmp_dir), XtRString, (caddr_t) DefaultTmpDir},
108     {"printCmd", "PrintCmd", XtRString, sizeof(String),
109      offset(print_cmd), XtRString, (caddr_t) DefaultPrintCmd},
110     {"calendarCmd", "CalendarCmd", XtRString, sizeof(String),
111      offset(calendar_cmd), XtRString, (caddr_t) DefaultCalendarCmd},
112     {"emailCmd", "EmailCmd", XtRString, sizeof(String),
113      offset(email_cmd), XtRString, (caddr_t) DefaultEmailCmd},
114     {"homeDir", "HomeDir", XtRString, sizeof(String),
115      offset(home_dir), XtRString, (caddr_t) DefaultHomeDir},
116 #undef offset
117 };
118 
119 static Atom wm_delete_window, wm_save_yourself, wm_protocols, wm_command;
120 static void WMProtocolsHandler();
121 
122 AppRes app_res;			/* xpostit application resources        */
123 Widget toplevel;		/* top level application shell widget   */
124 int screen;                     /* screen of the display                */
125 Display *display;		/* pointer to the display we're on      */
126 XtAppContext appcontext;	/* application context                  */
127 int curr_screenx, curr_screeny;	/* size of current screen */
128 XtIntervalId timer;		/* used for auto-save feature */
129 XtIntervalId alarm_timer;	/* used for alarms feature */
130 
131 unsigned long timer_interval;	/* auto-save interval */
132 unsigned long alarm_interval;	/* alarm check interval */
133 
main(argc,argv)134 int main(argc, argv)
135 char **argv;
136 int argc;
137 {
138     char *appname;
139     Atom protos[2];
140     Boolean setsigs = False;
141 
142     /*
143      * Ignore signals for now, but record whether they were
144      * already ignored or not so we can catch them later if
145      * need be.
146      */
147     if ((signal(SIGQUIT, SIG_IGN) != SIG_IGN) &&
148 	(signal(SIGINT, SIG_IGN) != SIG_IGN))
149 	setsigs = True;
150 
151     /*
152      * Get application name.
153      */
154     if ((appname = rindex(*argv, '/')) == NULL)
155 	appname = *argv;
156     else
157 	appname++;
158 
159     /*
160      * Initialize the toolkit and create an application shell.
161      */
162     toplevel = XtAppInitialize(&appcontext, PostItNoteClass, options,
163 		      XtNumber(options), &argc, argv, fallback_resources,
164 			       NULL, 0);
165 
166     display = XtDisplay(toplevel);
167 
168     screen = DefaultScreen(display);
169     curr_screenx = DisplayHeight(display, screen);
170     curr_screeny = DisplayWidth(display, screen);
171 
172     /*
173      * If we need to handle keyboard signals, do it now.
174      */
175     if (setsigs) {
176 	signal(SIGQUIT, ByeBye);
177 	signal(SIGINT, ByeBye);
178     }
179     /*
180      * Always handle these.
181      */
182     signal(SIGTERM, ByeBye);
183     signal(SIGHUP, ByeBye);
184 
185     /*
186      * Send X errors to the exit routine.
187      */
188     XSetErrorHandler((XErrorHandler) ByeBye);
189 
190     /*
191      * Now get any resources we're interested in.
192      */
193     XtGetApplicationResources(toplevel, &app_res, resources,
194 		   XtNumber(resources), (ArgList) argv, (Cardinal) argc);
195 
196     /*
197      * if the user requested help, provide it
198      */
199     if (app_res.help) {
200 	printf(USAGE);
201 	exit(0);
202     }
203     /*
204      * if the user requested the version, provide it
205      */
206     if (app_res.version) {
207 	printf("aspostit %s Copyright (c) 1998 Guylhem Aznar\n", AS_VERSION);
208 	printf("xpostit+ v%s\n", VERSION);
209 	printf("Copyright 1994-1996 Michael J. Hammel\n\n");
210 	exit(0);
211     }
212     /*
213      * Construct the path to the directory notes are
214      * stored in.
215      */
216     SetNoteDir();
217 
218     /*
219      * Construct the path to the temporary directory ...
220      */
221     SetTempDir();
222 
223     /*
224      * Create the plaid, menu, and list widgets.
225      */
226     CreatePlaidWidget();
227     CreateMenuWidget();
228 
229     /*
230      * Let the top level shell know about the menus.
231      */
232     XawSimpleMenuAddGlobalActions(appcontext);
233     XtRealizeWidget(menuwidget);
234 
235     /*
236      * Realize the top level and flush the server, which will
237      * let the user position the plaid window and map it.
238      */
239     XtRealizeWidget(toplevel);
240 
241     /*
242      * Set some properties for the window manager.
243      */
244     wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);
245     wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
246     wm_save_yourself = XInternAtom(display, "WM_SAVE_YOURSELF", False);
247 
248     protos[0] = wm_delete_window;
249     protos[1] = wm_save_yourself;
250     XSetWMProtocols(display, XtWindow(toplevel), protos, 2);
251     XtAddEventHandler(toplevel, 0, True, WMProtocolsHandler, NULL);
252     XtVaSetValues(toplevel, XtNwindowGroup, XtWindow(toplevel), NULL);
253 
254     /* Flush */
255     XFlush(display);
256 
257     /*
258      * Load the notes the user has saved, and create widgets
259      * for them.
260      */
261     LoadSavedNotes();
262 
263     /*
264      * Start the autosave timer, unless requested not to
265      */
266     if (!app_res.nosave) {
267 	timer_interval = app_res.interval * 60 * 1000;
268 	timer = XtAppAddTimeOut(
269 				   XtWidgetToApplicationContext(toplevel),
270 				   timer_interval,
271 				   AutoSave,
272 				   NULL);
273     }
274     /*
275      * Start the alarm timer (once a minute)
276      */
277     if (!app_res.noalarm) {
278 	alarm_interval = 60 * 1000;
279 	alarm_timer = XtAppAddTimeOut(
280 				  XtWidgetToApplicationContext(toplevel),
281 					 alarm_interval,
282 					 AlarmCheck,
283 					 NULL);
284     }
285     /*
286      * Never returns.
287      */
288     XtAppMainLoop(appcontext);
289 }
290 
291 
292 /*
293  * WMProtocolsHandler - top level WM protocol handler.  WM_DELETE_WINDOW
294  *                      is quit xpostit, WM_SAVE_YOURSELF is save all notes.
295  */
WMProtocolsHandler(w,client_data,event,continue_to_dispatch)296 static void WMProtocolsHandler(w, client_data, event, continue_to_dispatch)
297 Boolean *continue_to_dispatch;
298 XtPointer client_data;
299 XEvent *event;
300 Widget w;
301 {
302     XClientMessageEvent *c_event = (XClientMessageEvent *) event;
303 
304     if (event->type != ClientMessage ||
305 	c_event->message_type != wm_protocols)
306 	return;
307 
308     if (c_event->data.l[0] == wm_delete_window) {
309 	ByeBye();
310     } else if (c_event->data.l[0] == wm_save_yourself) {
311 	if (app_res.save_notes)
312 	    SaveAllNotes();
313 	/*
314 	 * Let session manager know we've saved ourself by doing
315 	 * a zero-length append on the WM_COMMAND property.
316 	 */
317 	XChangeProperty(XtDisplay(w), XtWindow(w), wm_command,
318 		  XA_STRING, 8, PropModeAppend, (unsigned char *) "", 0);
319     }
320 }
321