1 /*
2 * Various popups, such as the About... dialog.
3 *
4 * create_about_popup()
5 * Create About info popup
6 * create_error_popup(widget, error, fmt, ...)
7 * Create error popup with Unix error
8 * create_nodaemon_popup()
9 * Create no-daemon warning popup
10 * create_multiple_popup()
11 * Create multiple-plan's warning popup
12 * multiple_writer_warning_popup()
13 * Create popup with write warning
14 */
15
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <string.h>
21 #include <stdarg.h>
22 #include <sys/types.h>
23 #if defined(__EMX__) || defined(LINUX) || defined(MACOSX)
24 #include <sys/wait.h>
25 #endif
26 #include <Xm/Xm.h>
27 #include <Xm/MessageB.h>
28 #include <Xm/Protocols.h>
29 #include "cal.h"
30 #include "version.h"
31
32 #define NODAEMON_ONCE /* if defined, the error popup that offers */
33 /* to start pland comes up only once. */
34 static Boolean suppress_daemon_warning = False;
35
36 #ifndef __DATE__
37 #define __DATE__ ""
38 #endif
39
40 extern char *progname; /* argv[0] */
41 extern Display *display; /* everybody uses the same server */
42 extern Widget mainwindow; /* popup menus hang off main window */
43 extern XtAppContext app; /* application handle */
44 extern BOOL interactive; /* interactive or fast appt entry? */
45 extern BOOL startup_lock(BOOL, BOOL);
46
47
48 /*---------------------------------------------------------- about ----------*/
49 static char about_message[] = "\
50 \n\
51 Day Planner version %s\n\
52 Compiled %s\n\n\
53 Author: Thomas Driemeyer\n\
54 <thomas@bitrot.de>\n\
55 http://www.bitrot.de\n\n\
56 The sources are available at\n\
57 ftp://ftp.bitrot.de and\n\
58 ftp://plan.ftp.fu-berlin.de\
59 \n";
60
61
create_about_popup(void)62 void create_about_popup(void)
63 {
64 char msg[512];
65 Widget dialog;
66 XmString s;
67 Arg args[10];
68 int n;
69
70 sprintf(msg, _(about_message), VERSION JAPANVERSION, __DATE__);
71 s = XmStringCreateLtoR(msg, XmSTRING_DEFAULT_CHARSET);
72 n = 0;
73 XtSetArg(args[n], XmNmessageString, s); n++;
74 dialog = XmCreateInformationDialog(mainwindow, _("About"), args, n);
75 XmStringFree(s);
76 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
77 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
78 (void)XmInternAtom(display, "WM_DELETE_WINDOW", False);
79 XtManageChild(dialog);
80 }
81
82
83 /*---------------------------------------------------------- errors ---------*/
create_error_popup(Widget widget,UNUSED int error,char * fmt,...)84 void create_error_popup(
85 Widget widget,
86 UNUSED int error,
87 char *fmt, ...)
88 {
89 va_list parm;
90 char msg[10240];
91 Widget dialog;
92 XmString string;
93 Arg args;
94
95 if (!widget)
96 widget = mainwindow;
97 strcpy(msg, _("ERROR:\n\n"));
98
99 va_start(parm, fmt);
100 vsprintf(msg + strlen(msg), fmt, parm);
101 va_end(parm);
102 # if defined(sgi) || defined(_sgi)
103 if (error) {
104 strcat(msg, "\n");
105 strcat(msg, sys_errlist[error]);
106 }
107 # endif
108 if (!interactive || !widget) {
109 fputs(msg, stderr);
110 return;
111 }
112 string = XmStringCreateLtoR(msg, XmSTRING_DEFAULT_CHARSET);
113 XtSetArg(args, XmNmessageString, string);
114 dialog = XmCreateWarningDialog(widget, _("Error"), &args, 1);
115 XmStringFree(string);
116 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
117 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
118 (void)XmInternAtom(display, "WM_DELETE_WINDOW", False);
119 XtManageChild(dialog);
120 }
121
122
123 /*---------------------------------------------------------- no daemon ------*/
124 static char nodaemon_message[] = "\
125 Warning:\n\
126 There is no Scheduler daemon. Without a daemon,\n\
127 no action will be taken when an alarm triggers.\n\
128 Please start \"%s\" in your ~/.xsession or\n\
129 ~/.sgisession file, or run plan with the -S option.";
130
131 void run_daemon(Widget dialog);
132 static void cancel_callback(Widget dialog);
133 static BOOL running;
134
create_nodaemon_popup(void)135 void create_nodaemon_popup(void)
136 {
137 char msg[512];
138 Widget dialog;
139 XmString s1, s2, s3;
140 Arg args[10];
141 int n;
142
143 if (running)
144 return;
145 running = TRUE;
146 #ifdef NODAEMON_ONCE
147 if (suppress_daemon_warning)
148 return;
149 #endif
150 sprintf(msg, _(nodaemon_message), DAEMON_FN);
151 s1 = XmStringCreateLtoR(msg, XmSTRING_DEFAULT_CHARSET);
152 s2 = XmStringCreateSimple(_("Start daemon now"));
153 s3 = XmStringCreateSimple(_("Continue without daemon"));
154 n = 0;
155 XtSetArg(args[n], XmNmessageString, s1); n++;
156 XtSetArg(args[n], XmNokLabelString, s2); n++;
157 XtSetArg(args[n], XmNcancelLabelString, s3); n++;
158 dialog = XmCreateWarningDialog(mainwindow, _("Warning"), args, n);
159 XmStringFree(s1);
160 XmStringFree(s2);
161 XmStringFree(s3);
162 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)
163 run_daemon, (XtPointer)NULL);
164 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)
165 cancel_callback, (XtPointer)NULL);
166 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
167 (void)XmInternAtom(display, "WM_DELETE_WINDOW", False);
168 XtManageChild(dialog);
169 }
170
171
172 /*
173 * start the daemon. Nohup the daemon process so that it survives the death
174 * of its parent. Also used by the -S autostart option. pland immediately
175 * backgrounds itself, so the main process must call wait() to avoid zombies.
176 */
177
178 /*ARGSUSED*/
run_daemon(UNUSED Widget dialog)179 void run_daemon(
180 UNUSED Widget dialog) /* not used */
181 {
182 char path[1024];
183 PID_T pid;
184
185 running = FALSE;
186 if (!find_file(path, DAEMON_FN, TRUE)) {
187 fprintf(stderr, _("%s: WARNING: can't find %s\n"),
188 progname, DAEMON_FN);
189 create_nodaemon_popup();
190 return;
191 }
192 pid = fork();
193 if (pid > 0) {
194 wait(0);
195 return;
196 }
197 if (pid == 0) {
198 fprintf(stderr, _("%s: starting %s\n"), progname, DAEMON_FN);
199 #if defined(BSD) || defined(MIPS)
200 setpgrp(0, 0);
201 #else
202 #ifdef __EMX__
203
204 #else
205 setsid();
206 #endif
207 #endif
208 detach_from_network();
209 execl(path, DAEMON_FN, (char *)0);
210 }
211 fprintf(stderr, _("%s: WARNING: can't start %s: "), progname,
212 DAEMON_FN);
213 perror("");
214 create_nodaemon_popup();
215 }
216
217
218 /*
219 * don't start the daemon, and set the flag that prevents the popup in the
220 * future.
221 */
222
223 /*ARGSUSED*/
cancel_callback(UNUSED Widget dialog)224 static void cancel_callback(
225 UNUSED Widget dialog)
226 {
227 running = FALSE;
228 suppress_daemon_warning = True;
229 }
230
231
232 /*---------------------------------------------------------- multiple plan's */
233 static char multiple_message[] = "\
234 Warning:\n\
235 Another %s program is running.\n\
236 %s\n\
237 Press Continue to start up anyway, or Kill to\n\
238 attempt to kill the other program. Continuing\n\
239 may cause loss of new appointment entries, and\n\
240 command-line entry of appointments will not work.";
241
242 static void kill_callback(Widget, XtPointer, XtPointer);
243 static void cont_callback(Widget, XtPointer, XtPointer);
244 static BOOL cont;
245
create_multiple_popup(BOOL nolock)246 void create_multiple_popup(
247 BOOL nolock) /* tried to kill competitor */
248 {
249 char msg[512];
250 Widget dialog;
251 XmString s1, s2, s3;
252 Arg args[10];
253 int n;
254
255 cont = FALSE;
256 sprintf(msg, _(multiple_message), progname,
257 nolock ? _("The other program could not be killed.\n") : "");
258 s1 = XmStringCreateLtoR(msg, XmSTRING_DEFAULT_CHARSET);
259 s2 = XmStringCreateSimple(_("Kill"));
260 s3 = XmStringCreateSimple(_("Continue"));
261 n = 0;
262 XtSetArg(args[n], XmNmessageString, s1); n++;
263 XtSetArg(args[n], XmNokLabelString, s2); n++;
264 XtSetArg(args[n], XmNcancelLabelString, s3); n++;
265 XtSetArg(args[n], XmNdialogStyle,
266 XmDIALOG_FULL_APPLICATION_MODAL); n++;
267 dialog = XmCreateWarningDialog(mainwindow, _("Warning"), args, n);
268 XmStringFree(s1);
269 XmStringFree(s2);
270 XmStringFree(s3);
271 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)
272 kill_callback, (XtPointer)NULL);
273 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)
274 cont_callback, (XtPointer)NULL);
275 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
276 (void)XmInternAtom(display, "WM_DELETE_WINDOW", False);
277 XtManageChild(dialog);
278 while (!cont) {
279 XEvent event;
280 XtAppNextEvent(app, &event);
281 XtDispatchEvent(&event);
282 }
283 }
284
285
286 /*
287 * The user pressed Kill. Try to acquire a lock, then let
288 * create_multiple_popup continue so that the main plan window can come up.
289 */
290
291 /*ARGSUSED*/
kill_callback(UNUSED Widget dialog,UNUSED XtPointer a,UNUSED XtPointer b)292 static void kill_callback(
293 UNUSED Widget dialog,
294 UNUSED XtPointer a,
295 UNUSED XtPointer b)
296 {
297 if (!startup_lock(FALSE, TRUE))
298 create_multiple_popup(TRUE);
299 cont = TRUE;
300 }
301
302
303 /*
304 * The user pressed Continue. Let create_multiple_popup continue so that the
305 * main plan window can come up.
306 */
307
308 /*ARGSUSED*/
cont_callback(UNUSED Widget dialog,UNUSED XtPointer a,UNUSED XtPointer b)309 static void cont_callback(
310 UNUSED Widget dialog,
311 UNUSED XtPointer a,
312 UNUSED XtPointer b)
313 {
314 cont = TRUE;
315 }
316
317
318 /*---------------------------------------------------------- multiple wr ----*/
multiple_writer_warning_popup(Widget widget)319 void multiple_writer_warning_popup(
320 Widget widget) /* install near this widget */
321 {
322 Widget dialog;
323 XmString string;
324 Arg args[2];
325
326 string = XmStringCreateLtoR(
327 _("WARNING:\n\n\
328 You can now edit other users' appointments.\n\
329 plan will normally notice multiple writes at the same\n\
330 time (except over NFS), but will not notice if another\n\
331 user has modified the same appointment file while you\n\
332 were changing it. The older changes will get lost in\n\
333 this case. Watch out!)"), XmSTRING_DEFAULT_CHARSET);
334 XtSetArg(args[0], XmNmessageString, string);
335 XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
336 dialog = XmCreateWarningDialog(widget, _("Error"), args, 2);
337 XmStringFree(string);
338 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
339 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
340 (void)XmInternAtom(display, "WM_DELETE_WINDOW", False);
341 XtManageChild(dialog);
342 }
343
344
345 /*---------------------------------------------------------- multiple wr ----*/
new_language_popup(Widget widget)346 void new_language_popup(
347 Widget widget) /* install near this widget */
348 {
349 Widget dialog;
350 XmString string;
351 Arg args[2];
352
353 string = XmStringCreateLtoR(_("The new language will be effective\n"
354 "after plan is restarted."), XmSTRING_DEFAULT_CHARSET);
355 XtSetArg(args[0], XmNmessageString, string);
356 XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
357 dialog = XmCreateWarningDialog(widget, _("Warning"), args, 2);
358 XmStringFree(string);
359 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
360 XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
361 (void)XmInternAtom(display, "WM_DELETE_WINDOW", False);
362 XtManageChild(dialog);
363 }
364