1 /****************************************************************************
2 **
3 *W  popdial.c			XGAP source	                 Frank Celler
4 **
5 **
6 *Y  Copyright 1995-1997,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
7 *Y  Copyright 1997,       Frank Celler,                 Huerth,       Germany
8 **
9 **  This  file  contains functions for popping up dialogs.  Two functions are
10 **  exported:
11 **
12 **  CreatePopupDialog( <app>, <top>, <name>, <bt>, <def>, <pix> )
13 **  -------------------------------------------------------------
14 **
15 **  'CreatePopupDialog'  creates a popup dialog  structure.  A popup shell of
16 **  type "transientShellWidgetClass" is created together with a dialog widget
17 **  and  buttons according to <bt>. None  of these widgets are realised, this
18 **  is  done by   calling 'PopupDialog'.  The  default   button  activated by
19 **  pressing "return" is <def>.
20 **
21 **  Possible buttons are: PD_YES, PD_NO, PD_OK, PD_CANCEL, PD_ABORT, PD_RETRY
22 **                        PD_APPEND, PD_OVERWRITE
23 **
24 **  PopupDialog( <dialog>, <message>, <deflt>, <result> )
25 **  -----------------------------------------------------
26 **
27 **  'PopupDialog' will pop up a dialog created  with 'CreatePopupDialog'.  It
28 **  then grabs  the keyboard  and  returns only if a   button or  "return" is
29 **  pressed.  A pointer to the result is stored in <result> and the number of
30 **  the button  pressed  is returned.  If  "return"  was hit by  the user the
31 **  button number is the number given as <def> in 'CreatePopupDialog'.
32 **
33 **  The layout of the popup dialog is basically:
34 **
35 **       +-----------------------------------------+
36 **       |                                         |
37 **       |  pixmap    some text <message>          |
38 **       |  <pix>                                  |
39 **       |                                         |
40 **       |  [[[ INPUT FIELD (default: <deflt>) ]]] |
41 **       |                                         |
42 **       |  Btn1  Btn2 ... BtnN                    |
43 **       |                                         |
44 **       +-----------------------------------------+
45 **
46 **  PopupDialogBrokenWM()
47 **  ---------------------
48 **
49 **  Some window  manager  don't handle transient shell widgets correctly.  In
50 **  this case  calling  'PopupDialogBrokenWM' will  toggle  a flag such  that
51 **  a override shell widet is used instead.
52 */
53 #include    "utils.h"
54 #include    "popdial.h"			/* this package */
55 
56 
57 /****************************************************************************
58 **
59 
60 *F  ButtonSelected( <w>, <cld>, <cd> )	. . . . . . callback for button click
61 */
62 static struct { String name;  Int flag; } buttons[] =
63 {
64     { "yes",	    PD_YES       },
65     { "no",         PD_NO        },
66     { "OK",         PD_OK        },
67     { "cancel",     PD_CANCEL    },
68     { "abort",      PD_ABORT     },
69     { "retry",      PD_RETRY     },
70     { "append",     PD_APPEND    },
71     { "overwrite",  PD_OVERWRITE }
72 };
73 
ButtonSelected(w,cld,cd)74 static void ButtonSelected ( w, cld, cd )
75     Widget	    w;
76     XtPointer       cld;
77     XtPointer       cd;
78 {
79     Int             i;
80     Int           * res = (int*) cld;
81     String          name;
82 
83     /* find name in <buttons> and set result */
84     XtVaGetValues( w, XtNlabel, (XtArgVal)&name, (String)NULL );
85     for ( i = 0;  i < XtNumber(buttons);  i++ )
86 	if ( ! strcmp( buttons[i].name, name ) )
87 	    (*res) |= buttons[i].flag;
88 }
89 
90 
91 /****************************************************************************
92 **
93 *F  CreatePopupDialog( <app>, <top>, <name>, <button>, <def>, <pix> )  create
94 */
95 #include "bitmaps/return.bm"
96 
97 static Boolean BrokenWM = False;
98 
CreatePopupDialog(app,top,name,bt,def,pix)99 TypePopupDialog CreatePopupDialog ( app, top, name, bt, def, pix )
100     XtAppContext        app;
101     Widget	        top;
102     String              name;
103     Int                 bt;
104     Int                 def;
105     Pixmap              pix;
106 {
107     Display           * dp;
108     TypePopupDialog     dialog;
109     Int                 i;
110     static Pixmap       symbol = 0;
111 
112 
113     /* create pixmap for default button */
114     if ( symbol == 0 )
115     {
116 	dp = XtDisplay(top);
117 	symbol = XCreateBitmapFromData( dp, DefaultRootWindow(dp),
118                      return_bits, return_width, return_height );
119     }
120 
121     /* create a new popup variable */
122     dialog = (TypePopupDialog) XtMalloc( sizeof( struct _popup_dialog ) );
123     dialog->topLevel   = top;
124 
125     if ( BrokenWM )
126         dialog->popupShell = XtVaCreatePopupShell(
127                                  name, overrideShellWidgetClass,  top,
128 		                 XtNallowShellResize, (XtArgVal)True,
129 			         (String)NULL );
130     else
131         dialog->popupShell = XtVaCreatePopupShell(
132 	    		         name, transientShellWidgetClass, top,
133 			         XtNallowShellResize, (XtArgVal)True,
134 			         XtNtransientFor,     (XtArgVal)top,
135 			         (String)NULL );
136     if ( pix == 0 )
137         dialog->dialog = XtVaCreateManagedWidget(
138                              "xgapDialog",  dialogWidgetClass,
139                              dialog->popupShell,
140                              (String)NULL );
141     else
142         dialog->dialog = XtVaCreateManagedWidget(
143                              "xgapDialog",  dialogWidgetClass,
144                              dialog->popupShell,
145                              XtNicon, (XtArgVal)pix,
146                              (String)NULL );
147     dialog->button        = bt;
148     dialog->context       = app;
149     dialog->defaultButton = def;
150 
151     /* add buttons to the dialog */
152     for ( i = 0;  i < XtNumber(buttons);  i++ )
153 	if ( bt & buttons[i].flag )
154 	{
155 	    if ( buttons[i].flag == def )
156 		dialog->buttons[i] = XtVaCreateManagedWidget(
157 			    buttons[i].name, commandWidgetClass,
158 			    dialog->dialog,
159 			    XtNleftBitmap, (XtArgVal)symbol,
160 			    (String)NULL );
161 	    else
162 		dialog->buttons[i] = XtVaCreateManagedWidget(
163 			    buttons[i].name, commandWidgetClass,
164 			    dialog->dialog,
165 			    (String)NULL );
166 	    XtAddCallback( dialog->buttons[i],
167 			   XtNcallback,
168 			   ButtonSelected,
169 			   &(dialog->result) );
170 	}
171 	else
172 	    dialog->buttons[i] = 0;
173     return dialog;
174 }
175 
176 
177 /****************************************************************************
178 **
179 *V  NormalFont  . . . . . . . . . . . . . . . . . normal font for text output
180 **
181 **  see xcmds.c, imported here by Max 11.3.1999, see below
182 */
183 extern XFontStruct * NormalFont;
184 
185 /****************************************************************************
186 **
187 *F  PopupDialogBrokenWM() . . . . . . . . . . . . . .  toggle <BrokenWM> flag
188 */
PopupDialogBrokenWM()189 void PopupDialogBrokenWM ( )
190 {
191     BrokenWM = ! BrokenWM;
192 }
193 
194 
195 /****************************************************************************
196 **
197 *F  PopupDialog( <dialog>, <message>, <deflt>, <result> ) . . . . . . . do it
198 */
199 static Cursor BlobCursor = 0;
200 
PopupDialog(dialog,message,deflt,result)201 Int PopupDialog ( dialog, message, deflt, result )
202     TypePopupDialog	dialog;
203     String              message;
204     String              deflt;
205     String *            result;
206 {
207     Display *           display;
208     Position            x1,  y1,  tmp;
209     Dimension           w1,  h1,  bw;
210     Window              root;
211     Window              child;
212     Int        	        x2,  y2,  x3,  y3;
213     UInt                bt;
214     Int                 i;
215     Int                 textlen, deflen;
216 
217     /* create font cursor */
218     display = XtDisplay(dialog->popupShell);
219     if ( BlobCursor == 0 )
220 	BlobCursor = XCreateFontCursor( display, XC_dot );
221 
222     /* set message and default answer in dialog */
223     /* Changes by Max: 11.3.1999:
224        XtVaSetValues( dialog->dialog,
225 		   XtNlabel, 	"            ",
226 		   XtNvalue,    "                      ",
227 		   0,           0 );*/
228     XtVaSetValues( dialog->dialog,
229 		   XtNlabel, 	(XtArgVal)message,
230 		   XtNvalue,    (XtArgVal)deflt,
231 		   (String)NULL );
232     /* get size of popup dialog */
233     XtVaGetValues( dialog->popupShell,
234 		   XtNwidth,       (XtArgVal)&w1,
235 		   (String)NULL );
236     textlen = strlen(message)*NormalFont->max_bounds.width + 80;
237     deflen = strlen(deflt)*NormalFont->max_bounds.width + 60;
238     if (textlen > deflen) {
239       if (textlen < w1)
240         textlen = w1;
241     } else {
242       if (deflen < w1)
243         textlen = w1;
244       else
245         textlen = deflen;
246     }
247     XtVaSetValues( dialog->dialog,
248                    XtNwidth,textlen,
249                    0,NULL );
250     /* End of changes by Max. */
251 
252     XtRealizeWidget( dialog->popupShell );
253 
254     /* get size of popup dialog */
255     XtVaGetValues( dialog->popupShell,
256 		   XtNwidth,       (XtArgVal)&w1,
257 		   XtNheight,      (XtArgVal)&h1,
258 		   XtNborderWidth, (XtArgVal)&bw,
259 		   (String)NULL );
260 
261     /* get position of the mouse pointer */
262     XQueryPointer( display, XtWindow(dialog->popupShell),
263 		   &root, &child, &x2, &y2, &x3, &y3, &bt );
264 
265     /* find a nice position for the dialog */
266     tmp = DisplayWidth( display, DefaultScreen(display) );
267     x1 = x2 - (bw+w1)/2;
268     if ( tmp-w1-2*bw < x1 )  x1 = tmp-w1-2*bw;
269     if ( x1 < 0 )  x1 = 0;
270     tmp = DisplayHeight( display, DefaultScreen(display) );
271     y1  = y2 - (bw+h1)/2;
272     if ( tmp-h1-2*bw < y1 )  y1 = tmp-h1-2*bw;
273     if ( y1 < 0 )  y1 = 0;
274 
275     /* move the popup dialog to this position */
276     XtVaSetValues( dialog->popupShell,
277 		   XtNx, (XtArgVal)x1,
278 		   XtNy, (XtArgVal)y1,
279 		   (String)NULL );
280 
281     /* pop up shell */
282     XtPopup( dialog->popupShell, XtGrabExclusive );
283     for ( i = 0;  i < XtNumber(buttons);  i++ )
284 	if ( dialog->buttons[i] )
285 	    XDefineCursor( display,
286 			   XtWindow(dialog->buttons[i]), BlobCursor );
287 
288 
289     /* and grab keyboard */
290     XGrabKeyboard( display, XtWindow(dialog->dialog), False,
291 		   GrabModeAsync, GrabModeAsync, CurrentTime );
292 
293     /* wait until at least one button is selected */
294     dialog->result = 0;
295     while ( ( dialog->result & dialog->button ) == 0 )
296     {
297 	XEvent	event;
298 	char    str[128];
299 	KeySym  keysym;
300 	Int     len;
301 
302 	/* get next application event */
303 	XtAppNextEvent(dialog->context, &event);
304 
305 	/* is the event a key event */
306 	if ( event.type == KeyPress )
307 	{
308 	    if ( dialog->defaultButton != 0 )
309 	    {
310 
311 		/* convert key event into text string and check for return */
312 		len = XLookupString((XKeyEvent*)&event,str,128,&keysym,0);
313 		if ( len != 0 && ( str[0] == '\n' || str[0] == '\r' ) )
314 		{
315 		    dialog->result |= dialog->defaultButton;
316 		    continue;
317 		}
318 	    }
319 	}
320 
321 	/* dipatch event normally */
322 	XtDispatchEvent(&event);
323     }
324 
325     /* return answer string in <result> */
326     if ( result )
327         *result = XawDialogGetValueString(dialog->dialog);
328 
329     /* remove pop up menu from screen */
330     XtPopdown(dialog->popupShell);
331     return dialog->result & dialog->button;
332 }
333 
334 
335 /****************************************************************************
336 **
337 
338 *E  popdial.c . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
339 */
340 
341