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
CreateDialog(parent,name,okay_callback,cancel_callback)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
SetDialogPrompt(w,newprompt)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
GetDialogResponse(w)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
SetDialogResponse(w,s)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, 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     /* width includes margins as per Xaw documentation */
253     nwidth = (font->max_bounds.width * strlen(s))+leftMargin+rightMargin;
254     if (nwidth < width)
255 	nwidth = width;
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
positionpopup(w,bottom)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 }
341