1    | /*
2    |  * Copyright 1991 University of Wisconsin-Madison
3    |  *
4    |  * Permission to use, copy, modify, distribute, and sell this software and its
5    |  * documentation for any purpose is hereby granted without fee, provided that
6    |  * the above copyright notice appear in all copies and that both that
7    |  * copyright notice and this permission notice appear in supporting
8    |  * documentation, and that the name of the University of Wisconsin-Madison not
9    |  * be used in advertising or publicity pertaining to distribution of the
10   |  * software without specific, written prior permission.  The University of
11   |  * Wisconsin-Madison makes no representations about the suitability of this
12   |  * software for any purpose.  It is provided "as is" without express or
13   |  * implied warranty.
14   |  *
15   |  * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO
16   |  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17   |  * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR
18   |  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19   |  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20   |  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21   |  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22   |  *
23   |  * Author:  Tim Theisen             Department of Computer Sciences
24   |  *          tim@cs.wisc.edu         University of Wisconsin-Madison
25   |  *          uwvax!tim               1210 West Dayton Street
26   |  *          (608)262-0438           Madison, WI   53706
27   |  *
28   |  *
29   |  * Modified 12/91 by Dean Luick.  Tim graciously donated this piece of code
30   |  * from his program ghostview, an X11 front end for ghostscript.
31   |  *
32   |  *    + Make the cancel button optional.
33   |  *    + Put an #ifdef SPECIAL_CMAP around code to fix a colormap bug.
34   |  *	We don't need it here.
35   |  *    + Add the function positionpopup() from another part of ghostview
36   |  *	to this code.
37   |  *
38   |  * Modified 2/93, Various.
39   |  *    + Added workaround for SYSV include problem.
40   |  *    + Changed the default width response text widget to be as wide as the
41   |  *	window itself.  Suggestion from David E. Wexelblat, dwex@goblin.org.
42   |  */
43   | 
44   | #ifndef SYSV
45   | #define PRESERVE_NO_SYSV	/* X11 include files may define SYSV */
46   | #endif
47   | 
48   | #include <X11/Intrinsic.h>
49   | #include <X11/StringDefs.h>
50   | #include <X11/Xos.h>
51   | #include <X11/Xaw/Cardinals.h>
52   | #include <X11/Xaw/Form.h>
53   | #include <X11/Xaw/Label.h>
54   | #include <X11/Xaw/AsciiText.h>
55   | #include <X11/Xaw/Command.h>
56   | 
57   | #ifdef PRESERVE_NO_SYSV
58   | # ifdef SYSV
59   | #  undef SYSV
60   | # endif
61   | # undef PRESERVE_NO_SYSV
62   | #endif
63   | 
64   | #include "config.h"	/* #define for const for non __STDC__ compilers */
65   | 
66   | /* ":" added to both translations below to allow limited redefining of
67   |  * keysyms before testing for keysym values -- dlc */
68   | static const char okay_accelerators[] =
69   |     "#override\n\
70   |      :<Key>Return: set() notify() unset()\n";
71   | 
72   | static const char cancel_accelerators[] =
73   |     "#override\n\
74   |      :<Key>Escape: set() notify() unset()\n\
75   |      :<Ctrl>[: set() notify() unset()\n";	/* for keyboards w/o an ESC */
76   | 
77   | 
78   | /* Create a dialog widget.  It is just a form widget with
79   |  *	a label prompt
80   |  *	a text response
81   |  *	an okay button
82   |  *	an optional cancel button
83   |  */
84   | Widget
85   | CreateDialog(parent, name, okay_callback, cancel_callback)
86   |     Widget parent;
87   |     String name;
88   |     XtCallbackProc okay_callback;
89   |     XtCallbackProc cancel_callback;
90   | {
91   |     Widget form, prompt, response, okay, cancel;
92   |     Arg args[20];
93   |     Cardinal num_args;
94   | 
95   | 							num_args = 0;
96   | #ifdef SPECIAL_CMAP
97   |     if (special_cmap) {
98   | 	XtSetArg(args[num_args], XtNbackground, white);	num_args++;
99   |     }
100  | #endif
101  |     form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args);
102  | 
103  | 							num_args = 0;
104  | #ifdef SPECIAL_CMAP
105  |     if (special_cmap) {
106  | 	XtSetArg(args[num_args], XtNforeground, black);	num_args++;
107  | 	XtSetArg(args[num_args], XtNbackground, white);	num_args++;
108  |     }
109  | #endif
110  |     XtSetArg(args[num_args], XtNtop, XtChainTop);	num_args++;
111  |     XtSetArg(args[num_args], XtNbottom, XtChainTop);	num_args++;
112  |     XtSetArg(args[num_args], XtNleft, XtChainLeft);	num_args++;
113  |     XtSetArg(args[num_args], XtNright, XtChainLeft);	num_args++;
114  |     XtSetArg(args[num_args], XtNresizable, True);	num_args++;
115  |     XtSetArg(args[num_args], XtNborderWidth, 0);	num_args++;
116  |     prompt = XtCreateManagedWidget("prompt", labelWidgetClass,
117  | 				   form, args, num_args);
118  | 
119  | 							num_args = 0;
120  | #ifdef SPECIAL_CMAP
121  |     if (special_cmap) {
122  | 	XtSetArg(args[num_args], XtNforeground, black);	num_args++;
123  | 	XtSetArg(args[num_args], XtNbackground, white);	num_args++;
124  |     }
125  | #endif
126  |     XtSetArg(args[num_args], XtNfromVert, prompt);	num_args++;
127  |     XtSetArg(args[num_args], XtNtop, XtChainTop);	num_args++;
128  |     XtSetArg(args[num_args], XtNbottom, XtChainTop);	num_args++;
129  |     XtSetArg(args[num_args], XtNleft, XtChainLeft);	num_args++;
130  |     XtSetArg(args[num_args], XtNright, XtChainLeft);	num_args++;
131  |     XtSetArg(args[num_args], XtNresizable, True);	num_args++;
132  |     XtSetArg(args[num_args], XtNeditType, XawtextEdit);	num_args++;
133  |     XtSetArg(args[num_args], XtNresize, XawtextResizeWidth);	num_args++;
134  |     XtSetArg(args[num_args], XtNstring, "");		num_args++;
135  |     response = XtCreateManagedWidget("response", asciiTextWidgetClass,
136  | 				     form, args, num_args);
137  | 
138  | 							num_args = 0;
139  | #ifdef SPECIAL_CMAP
140  |     if (special_cmap) {
141  | 	XtSetArg(args[num_args], XtNforeground, black);	num_args++;
142  | 	XtSetArg(args[num_args], XtNbackground, white);	num_args++;
143  |     }
144  | #endif
145  |     XtSetArg(args[num_args], XtNfromVert, response);	num_args++;
146  |     XtSetArg(args[num_args], XtNtop, XtChainTop);	num_args++;
147  |     XtSetArg(args[num_args], XtNbottom, XtChainTop);	num_args++;
148  |     XtSetArg(args[num_args], XtNleft, XtChainLeft);	num_args++;
149  |     XtSetArg(args[num_args], XtNright, XtChainLeft);	num_args++;
150  |     XtSetArg(args[num_args], XtNresizable, True);	num_args++;
151  |     XtSetArg(args[num_args], XtNaccelerators,
152  | 	     XtParseAcceleratorTable(okay_accelerators));	num_args++;
153  |     okay = XtCreateManagedWidget("okay", commandWidgetClass,
154  | 				 form, args, num_args);
155  |     XtAddCallback(okay, XtNcallback, okay_callback, form);
156  | 
157  |     /* Only create cancel button if there is a callback for it. */
158  |     if (cancel_callback) {
159  | 								num_args = 0;
160  | #ifdef SPECIAL_CMAP
161  | 	if (special_cmap) {
162  | 	    XtSetArg(args[num_args], XtNforeground, black);	num_args++;
163  | 	    XtSetArg(args[num_args], XtNbackground, white);	num_args++;
164  | 	}
165  | #endif
166  | 	XtSetArg(args[num_args], XtNfromVert, response);	num_args++;
167  | 	XtSetArg(args[num_args], XtNfromHoriz, okay);		num_args++;
168  | 	XtSetArg(args[num_args], XtNtop, XtChainTop);		num_args++;
169  | 	XtSetArg(args[num_args], XtNbottom, XtChainTop);	num_args++;
170  | 	XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
171  | 	XtSetArg(args[num_args], XtNright, XtChainLeft);	num_args++;
172  | 	XtSetArg(args[num_args], XtNresizable, True);		num_args++;
173  | 	XtSetArg(args[num_args], XtNaccelerators,
174  | 	     XtParseAcceleratorTable(cancel_accelerators));	num_args++;
175  | 	cancel = XtCreateManagedWidget("cancel", commandWidgetClass,
176  | 				       form, args, num_args);
177  | 	XtAddCallback(cancel, XtNcallback, cancel_callback, form);
178  | 	XtInstallAccelerators(response, cancel);
179  |     }
180  | 
181  |     XtInstallAccelerators(response, okay);
182  |     XtSetKeyboardFocus(form, response);
183  | 
184  |     return form;
185  | }
186  | 
187  | #if 0
188  | /* get the prompt from the dialog box.  Used a startup time to
189  |  * save away the initial prompt */
190  | String
191  | GetDialogPrompt(w)
192  |     Widget w;
193  | {
194  |     Arg args[1];
195  |     Widget label;
196  |     String s;
197  | 
198  |     label = XtNameToWidget(w, "prompt");
199  |     XtSetArg(args[0], XtNlabel, &s);
200  |     XtGetValues(label, args, ONE);
201  |     return XtNewString(s);
202  | }
203  | #endif
204  | 
205  | /* set the prompt.  This is used to put error information in the prompt */
206  | void
207  | SetDialogPrompt(w, newprompt)
208  |     Widget w;
209  |     String newprompt;
210  | {
211  |     Arg args[1];
212  |     Widget label;
213  | 
214  |     label = XtNameToWidget(w, "prompt");
215  |     XtSetArg(args[0], XtNlabel, newprompt);
216  |     XtSetValues(label, args, ONE);
217  | }
218  | 
219  | /* get what the user typed; caller must free the response */
220  | String
221  | GetDialogResponse(w)
222  |     Widget w;
223  | {
224  |     Arg args[1];
225  |     Widget response;
226  |     String s;
227  | 
228  |     response = XtNameToWidget(w, "response");
229  |     XtSetArg(args[0], XtNstring, &s);
230  |     XtGetValues(response, args, ONE);
231  |     return XtNewString(s);
232  | }
233  | 
234  | #define max(a,b) (((a) > (b)) ? (a) : (b))
235  | /* set the default reponse */
236  | void
237  | SetDialogResponse(w, s)
238  |     Widget w;
239  |     String s;
240  | {
241  |     Arg args[4];
242  |     Widget response;
243  |     XFontStruct *font;
244  |     Dimension width, nwidth, tmp, leftMargin, rightMargin;
245  | 
246  |     response = XtNameToWidget(w, "response");
247  |     XtSetArg(args[0], XtNfont, &font);
248  |     XtSetArg(args[1], XtNleftMargin, &leftMargin);
249  |     XtSetArg(args[2], XtNrightMargin, &rightMargin);
250  |     XtSetArg(args[3], XtNwidth, &width);
251  |     XtGetValues(response, args, FOUR);
252  |     nwidth = (font->max_bounds.width * strlen(s))+leftMargin+rightMargin;
253  |     tmp = width-(leftMargin+rightMargin);
254  |     if (nwidth < tmp)
255  | 	nwidth = tmp;
256  | 
257  |     XtSetArg(args[0], XtNstring, s);
258  |     XtSetArg(args[1], XtNwidth, nwidth);
259  |     XtSetValues(response, args, TWO);
260  |     XawTextSetInsertionPoint(response, strlen(s));
261  | }
262  | 
263  | #if 0
264  | /* clear the response */
265  | void
266  | ClearDialogResponse(w)
267  |     Widget w;
268  | {
269  |     Arg args[2];
270  |     Widget response;
271  | 
272  |     response = XtNameToWidget(w, "response");
273  |     XtSetArg(args[0], XtNstring, "");
274  |     XtSetArg(args[1], XtNwidth, 100);
275  |     XtSetValues(response, args, TWO);
276  | }
277  | #endif
278  | 
279  | 
280  | /* Not a part of the original dialogs.c from ghostview --------------------- */
281  | 
282  | /* position popup window under the cursor */
283  | void
284  | positionpopup(w, bottom)
285  |     Widget w;
286  |     boolean bottom;	/* position y on bottom? */
287  | {
288  |     Arg args[3];
289  |     Cardinal num_args;
290  |     Dimension width, height, b_width;
291  |     int x, y, max_x, max_y;
292  |     Window root, child;
293  |     XSizeHints *hints;
294  |     int dummyx, dummyy;
295  |     unsigned int dummymask;
296  |     extern Widget toplevel;
297  | 
298  |     /* following line deals with a race condition w/brain-damaged WM's -dlc */
299  |     XtUnrealizeWidget(w);
300  | 
301  |     XQueryPointer(XtDisplay(toplevel), XtWindow(toplevel), &root, &child,
302  | 		  &x, &y, &dummyx, &dummyy, &dummymask);
303  |     num_args = 0;
304  |     XtSetArg(args[num_args], XtNwidth, &width); num_args++;
305  |     XtSetArg(args[num_args], XtNheight, &height); num_args++;
306  |     XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
307  |     XtGetValues(w, args, num_args);
308  | 
309  |     /* position so that the cursor is center,center or center,bottom */
310  |     width += 2 * b_width;
311  |     x -= ( (Position) width/2 );
312  |     if (x < 0) x = 0;
313  |     if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
314  | 
315  |     if (bottom) {
316  | 	y -= (height+b_width-1);
317  | 	height += 2 * b_width;
318  |     } else {
319  | 	height += 2 * b_width;
320  | 	y -= ( (Position) height/2 );
321  |     }
322  |     if (y < 0) y = 0;
323  |     if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
324  | 
325  | 
326  |     num_args = 0;
327  |     XtSetArg(args[num_args], XtNx, x); num_args++;
328  |     XtSetArg(args[num_args], XtNy, y); num_args++;
329  |     XtSetValues(w, args, num_args);
330  | 
331  |     /* Some older window managers ignore XtN{x,y}; hint the same values */
332  |     /* The {x,y} are not used by newer window managers; older ones need them */
333  |     XtRealizeWidget(w);
334  |     hints = XAllocSizeHints();
335  |     hints->flags = USPosition;
336  |     hints->x = x;
337  |     hints->y = y;
338  |     XSetWMNormalHints(XtDisplay(w), XtWindow(w), hints);
339  |     XFree(hints);
340  | }