source: trunk/third/xmh/popup.c @ 9658

Revision 9658, 15.8 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9657, which included commits to RCS files with non-trunk default branches.
Line 
1/* $XConsortium: popup.c,v 2.36 91/07/23 17:43:02 converse Exp $
2 *
3 *
4 *                        COPYRIGHT 1989
5 *                 DIGITAL EQUIPMENT CORPORATION
6 *                     MAYNARD, MASSACHUSETTS
7 *                      ALL RIGHTS RESERVED.
8 *
9 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
10 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
11 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
12 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
13 *
14 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
15 * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
16 * ADDITION TO THAT SET FORTH ABOVE.
17 *
18 * Permission to use, copy, modify, and distribute this software and its
19 * documentation for any purpose and without fee is hereby granted, provided
20 * that the above copyright notice appear in all copies and that both that
21 * copyright notice and this permission notice appear in supporting
22 * documentation, and that the name of Digital Equipment Corporation not be
23 * used in advertising or publicity pertaining to distribution of the software
24 * without specific, written prior permission.
25 */
26
27/* popup.c -- Handle pop-up widgets. */
28
29#include "xmh.h"
30#include <X11/Xaw/Cardinals.h>
31
32typedef struct _PopupStatus {
33        Widget popup;           /* order of fields same as CommandStatusRec */
34        struct _LastInput lastInput;
35        char*  shell_command;   /* NULL, or contains sh -c command */
36} PopupStatusRec, *PopupStatus;
37
38/* these are just strings which are used more than one place in the code */
39static String XmhNconfirm = "confirm";
40static String XmhNdialog = "dialog";
41static String XmhNerror = "error";
42static String XmhNnotice = "notice";
43static String XmhNokay = "okay";
44static String XmhNprompt = "prompt";
45static String XmhNvalue = "value";
46   
47/* The popups were originally parented from toplevel and neglected the
48 * transientFor resource.  In order not to break existing user resource
49 * settings for the popups, transientFor is set independent of the parent,
50 * which remains the toplevel widget.
51 */
52
53static void DeterminePopupPosition(x_ptr, y_ptr, transFor_return)
54    Position    *x_ptr, *y_ptr;
55    Widget      *transFor_return; /* return a suitable top level shell */
56{
57    if (lastInput.win != -1) {
58        if (transFor_return) {
59            Widget      source;
60            source = XtWindowToWidget(XtDisplay(toplevel), lastInput.win);
61            while (source && !XtIsWMShell(source))
62                source = XtParent(source);
63            *transFor_return = source;
64        }
65        /* use the site of the last KeyPress or ButtonPress */
66        *x_ptr = lastInput.x;
67        *y_ptr = lastInput.y;
68    } else {
69        Widget  source;
70        int i = 0;
71        Dimension width, height;
72        Arg args[2];
73
74        /* %%% need to keep track of last screen */
75        /* guess which screen and use the the center of it */
76        while (i < numScrns && !scrnList[i]->mapped)
77            i++;
78        source = ((i < numScrns) ? scrnList[i]->parent : toplevel);
79        XtSetArg(args[0], XtNwidth, &width);
80        XtSetArg(args[1], XtNheight, &height);
81        XtGetValues(source, args, TWO);
82        XtTranslateCoords(source, (Position) (width / 2),
83                          (Position) (height / 2), x_ptr, y_ptr);
84        if (transFor_return) *transFor_return = source;
85    }
86}
87
88static Boolean PositionThePopup(popup, x, y)
89    Widget      popup;
90    Position    x, y;
91{
92    /* Hack.  Fix up the position of the popup.  The xmh app defaults file
93     * contains an Xmh*Geometry specification; the effects of that on
94     * popups, and the lack of any user-supplied geometry specification for
95     * popups, are mitigated here, by giving the popup shell a position.
96     * (Xmh*Geometry is needed in case there is no user-supplied default.)
97     * Returns True if an explicit geometry was inferred; false if the
98     * widget was repositioned to (x,y).
99     */
100
101    Arg         args[4];
102    String      top_geom, pop_geom;
103
104    XtSetArg( args[0], XtNgeometry, &top_geom );
105    XtGetValues( toplevel, args, ONE );
106    XtSetArg( args[0], XtNgeometry, &pop_geom );
107    XtGetValues( popup, args, ONE );
108
109    if (pop_geom == NULL || pop_geom == top_geom) {
110        /* if same db entry, then ... */
111        XtSetArg( args[0], XtNgeometry, (String) NULL);
112        XtSetArg( args[1], XtNx, x);
113        XtSetArg( args[2], XtNy, y);
114        XtSetArg( args[3], XtNwinGravity, SouthWestGravity);
115        XtSetValues( popup, args, FOUR);
116        return False;
117    }
118    return True;
119}
120
121
122static void CenterPopupPosition(widget, popup, px, py)
123    Widget      widget;
124    Widget      popup;
125    Position    px, py;
126{
127    Position    x, y;
128    Position    nx, ny;
129    Arg         args[3];
130
131    if (widget == NULL) return;
132    XtSetArg(args[0], XtNx, &x);
133    XtSetArg(args[1], XtNy, &y);
134    XtGetValues(popup, args, TWO);
135    if (x == px && y == py) {
136
137        /* Program sets geometry.  Correct our earlier calculations. */
138
139        nx = (GetWidth(widget) - GetWidth(popup)) / 2;
140        ny = (GetHeight(widget) - GetHeight(popup)) / 2;
141        if (nx < 0) nx = 0;
142        if (ny < 0) ny = 0;
143        XtTranslateCoords(widget, nx, ny, &x, &y);
144        XtSetArg(args[0], XtNx, x);
145        XtSetArg(args[1], XtNy, y);
146        XtSetArg(args[2], XtNwinGravity, CenterGravity);
147        XtSetValues(popup, args, THREE);
148    }
149}
150         
151
152/* Insure that the popup is wholly showing on the screen.
153   Optionally center the widget horizontally and/or vertically
154   on current position.
155 */
156
157static void InsureVisibility(popup, popup_child, x, y, centerX, centerY)
158    Widget      popup, popup_child;
159    Position    x, y;           /* assert: current position = (x,y) */
160    Boolean     centerX, centerY;
161{
162    Position    root_x, root_y;
163    Dimension   width, height, border;
164    Arg         args[3];
165
166
167    XtSetArg( args[0], XtNwidth, &width );
168    XtSetArg( args[1], XtNheight, &height );
169    XtSetArg( args[2], XtNborderWidth, &border );
170    XtGetValues( popup, args, THREE );
171
172    XtTranslateCoords(popup_child, (Position)0, (Position)0, &root_x, &root_y);
173    if (centerX) root_x -= width/2 + border;
174    if (centerY) root_y -= height/2 + border;
175    if (root_x < 0) root_x = 0;
176    if (root_y < 0) root_y = 0;
177    border <<= 1;
178
179    if ((int)(root_x + width + border) > WidthOfScreen(XtScreen(toplevel))) {
180        root_x = WidthOfScreen(XtScreen(toplevel)) - width - border;
181    }
182    if ((int)(root_y + height + border) > HeightOfScreen(XtScreen(toplevel))) {
183        root_y = HeightOfScreen(XtScreen(toplevel)) - height - border;
184    }
185
186    if (root_x != x || root_y != y) {
187        XtSetArg( args[0], XtNx, root_x );
188        XtSetArg( args[1], XtNy, root_y );
189        XtSetValues( popup, args, TWO );
190    }
191}
192
193
194/*ARGSUSED*/
195void DestroyPopup(widget, client_data, call_data)
196    Widget              widget;         /* unused */
197    XtPointer           client_data;
198    XtPointer           call_data;      /* unused */
199{
200    Widget              popup = (Widget) client_data;
201    XtPopdown(popup);
202    XtDestroyWidget(popup);
203}
204
205void WMDeletePopup(popup, event)
206    Widget      popup;  /* transient shell */
207    XEvent*     event;
208{
209    String      shellName;
210    String      buttonName;
211    Widget      button;
212
213    shellName = XtName(popup);
214    if (strcmp(shellName, XmhNconfirm) == 0)
215        buttonName = "*no";
216    else if (strcmp(shellName, XmhNprompt) == 0)
217        buttonName = "*cancel";
218    else if (strcmp(shellName, XmhNnotice) == 0)
219        buttonName = "*confirm";
220    else if (strcmp(shellName, XmhNerror) == 0)
221        buttonName = "*OK";
222    else
223        return;         /* WM may kill us */
224
225    button = XtNameToWidget(popup, buttonName);
226    if (! button) return;
227    XtCallActionProc(button, "set", event, (String*)NULL, ZERO);
228    XtCallActionProc(button, "notify", event, (String*)NULL, ZERO);
229    XtCallActionProc(button, "unset", event, (String*)NULL, ZERO);
230}
231
232static void TheUsual(popup)
233    Widget      popup;  /* shell */
234{
235    XtInstallAllAccelerators(popup, popup);
236    XtAugmentTranslations(popup, app_resources.wm_protocols_translations);
237    XtRealizeWidget(popup);
238    XDefineCursor(XtDisplay(popup), XtWindow(popup), app_resources.cursor);
239    (void) XSetWMProtocols(XtDisplay(popup), XtWindow(popup),
240                           protocolList, XtNumber(protocolList));
241}
242
243
244/*ARGSUSED*/
245void XmhPromptOkayAction(w, event, params, num_params)
246    Widget      w;              /* the "value" widget in the Dialog box */
247    XEvent      *event;         /* unused */
248    String      *params;        /* unused */
249    Cardinal    *num_params;    /* unused */
250{
251    XtCallCallbacks(XtNameToWidget(XtParent(w), XmhNokay), XtNcallback,
252                    (XtPointer)XtParent(w));
253}
254
255
256void PopupPrompt(transientFor, question, okayCallback)
257    Widget              transientFor;   /* required to be a top-level shell */
258    String              question;               /* the prompting string */
259    XtCallbackProc      okayCallback;           /* CreateFolder() */
260{
261    Widget              popup;
262    Widget              dialog;
263    Widget              value;
264    Position            x, y;
265    Boolean             positioned;
266    Arg                 args[3];
267    static XtTranslations PromptTextTranslations = NULL;
268
269    DeterminePopupPosition(&x, &y, (Widget*)NULL);
270    XtSetArg(args[0], XtNallowShellResize, True);
271    XtSetArg(args[1], XtNinput, True);
272    XtSetArg(args[2], XtNtransientFor, transientFor);
273    popup = XtCreatePopupShell(XmhNprompt, transientShellWidgetClass, toplevel,
274                               args, THREE);
275    positioned = PositionThePopup(popup, x, y);
276
277    XtSetArg(args[0], XtNlabel, question);
278    XtSetArg(args[1], XtNvalue, "");
279    dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, popup, args,
280                                   TWO);
281    XtSetArg(args[0], XtNresizable, True);
282    XtSetValues( XtNameToWidget(dialog, "label"), args, ONE);
283    value = XtNameToWidget(dialog, XmhNvalue);
284    XtSetValues( value, args, ONE);
285    if (! PromptTextTranslations)
286        PromptTextTranslations = XtParseTranslationTable
287            ("<Key>Return: XmhPromptOkayAction()\n\
288              Ctrl<Key>R:  no-op(RingBell)\n\
289              Ctrl<Key>S:  no-op(RingBell)\n");
290    XtOverrideTranslations(value, PromptTextTranslations);
291
292    XawDialogAddButton(dialog, XmhNokay, okayCallback, (XtPointer) dialog);
293    XawDialogAddButton(dialog, "cancel", DestroyPopup, (XtPointer) popup);
294    TheUsual(popup);
295    InsureVisibility(popup, dialog, x, y, !positioned, False);
296    XtPopup(popup, XtGrabNone);
297}
298
299
300/* ARGSUSED */
301static void FreePopupStatus( w, closure, call_data )
302    Widget w;                   /* unused */
303    XtPointer closure;
304    XtPointer call_data;        /* unused */
305{
306    PopupStatus popup = (PopupStatus)closure;
307    XtPopdown(popup->popup);
308    XtDestroyWidget(popup->popup);
309    if (popup->shell_command)
310        XtFree(popup->shell_command);
311    XtFree((char *) closure);
312}
313
314
315void PopupNotice(message, callback, closure)
316    String              message;
317    XtCallbackProc      callback;
318    XtPointer           closure;
319{
320    PopupStatus popup_status = (PopupStatus)closure;
321    Widget transientFor;
322    Widget dialog;
323    Widget value;
324    Position x, y;
325    Arg args[3];
326    char command[65], label[128];
327
328    if (popup_status == (PopupStatus)NULL) {
329        popup_status = XtNew(PopupStatusRec);
330        popup_status->lastInput = lastInput;
331        popup_status->shell_command = (char*)NULL;
332    }
333    if (! popup_status->shell_command) {
334        /* MH command */
335        if (sscanf( message, "%64s", command ) != 1)
336            (void) strcpy( command, "system" );
337        else {
338            int l = strlen(command);
339            if (l && command[--l] == ':')
340                command[l] = '\0';
341        }
342        (void) sprintf( label, "%.64s command returned:", command );
343    } else {
344        /* arbitrary shell command */
345        int len = strlen(popup_status->shell_command);
346        (void) sprintf(label, "%.88s %s\nshell command returned:",
347                       popup_status->shell_command,
348                       ((len > 88) ? "[truncated]" : ""));
349    }
350
351    DeterminePopupPosition(&x, &y, &transientFor);
352    XtSetArg( args[0], XtNallowShellResize, True );
353    XtSetArg( args[1], XtNinput, True );
354    XtSetArg( args[2], XtNtransientFor, transientFor);
355    popup_status->popup = XtCreatePopupShell(XmhNnotice,
356                             transientShellWidgetClass, toplevel, args, THREE);
357    PositionThePopup(popup_status->popup, x, y);
358
359    XtSetArg( args[0], XtNlabel, label );
360    XtSetArg( args[1], XtNvalue, message );
361    dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass,
362                                   popup_status->popup, args, TWO);
363
364    /* The text area of the dialog box will not be editable. */
365    value = XtNameToWidget(dialog, XmhNvalue);
366    XtSetArg( args[0], XtNeditType, XawtextRead);
367    XtSetArg( args[1], XtNdisplayCaret, False);
368    XtSetValues( value, args, TWO);
369    XtOverrideTranslations(value, NoTextSearchAndReplace);
370
371    XawDialogAddButton( dialog, XmhNconfirm,
372                       ((callback != (XtCallbackProc) NULL)
373                          ? callback : (XtCallbackProc) FreePopupStatus),
374                       (XtPointer) popup_status
375                      );
376
377    TheUsual(popup_status->popup);
378    InsureVisibility(popup_status->popup, dialog, x, y, False, False);
379    XtPopup(popup_status->popup, XtGrabNone);
380}
381
382
383void PopupConfirm(center_widget, question, affirm_callbacks, negate_callbacks)
384    Widget              center_widget;  /* where to center; may be NULL */
385    String              question;
386    XtCallbackList      affirm_callbacks;
387    XtCallbackList      negate_callbacks;
388{
389    Widget      popup;
390    Widget      dialog;
391    Widget      button;
392    Widget      transientFor;
393    Position    x, y;
394    Arg         args[3];
395    static XtCallbackRec callbacks[] = {
396        {DestroyPopup,          (XtPointer) NULL},
397        {(XtCallbackProc) NULL, (XtPointer) NULL}
398    };
399
400    DeterminePopupPosition(&x, &y, &transientFor);
401    XtSetArg(args[0], XtNinput, True);
402    XtSetArg(args[1], XtNallowShellResize, True);
403    XtSetArg(args[2], XtNtransientFor, transientFor);
404    popup = XtCreatePopupShell(XmhNconfirm, transientShellWidgetClass,
405                               toplevel, args, THREE);
406    PositionThePopup(popup, x, y);
407
408    XtSetArg(args[0], XtNlabel, question);
409    dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, popup, args,
410                                   ONE);
411   
412    callbacks[0].closure = (XtPointer) popup;
413    XtSetArg(args[0], XtNcallback, callbacks);
414    button = XtCreateManagedWidget("yes", commandWidgetClass, dialog,
415                                   args, ONE);
416    if (affirm_callbacks)
417        XtAddCallbacks(button, XtNcallback, affirm_callbacks);
418
419    button = XtCreateManagedWidget("no", commandWidgetClass, dialog,
420                                   args, ZERO);
421    XtAddCallback(button, XtNcallback, DestroyPopup, (XtPointer) popup);
422    if (negate_callbacks)
423        XtAddCallbacks(button, XtNcallback, negate_callbacks);
424
425    TheUsual(popup);
426    CenterPopupPosition(center_widget, popup, x, y);
427    InsureVisibility(popup, dialog, x, y, False, False);
428    XtPopup(popup, XtGrabNone);
429}
430
431
432void PopupError(widget, message)
433    Widget      widget; /* transient for this top-level shell, or NULL */
434    String      message;
435{
436    Widget      transFor, error_popup, dialog;
437    Position    x, y;
438    Boolean     positioned;
439    Arg         args[3];
440    static XtCallbackRec callbacks[] = {
441        {DestroyPopup,          (XtPointer) NULL},
442        {(XtCallbackProc) NULL, (XtPointer) NULL}
443    };
444
445    transFor = widget;
446    DeterminePopupPosition(&x, &y, transFor ? (Widget*)NULL : &transFor);
447
448    XtSetArg(args[0], XtNallowShellResize, True);
449    XtSetArg(args[1], XtNinput, True);
450    XtSetArg(args[2], XtNtransientFor, transFor);
451    error_popup = XtCreatePopupShell(XmhNerror, transientShellWidgetClass,
452                                     toplevel, args, THREE);
453    positioned = PositionThePopup(error_popup, x, y);
454
455    XtSetArg(args[0], XtNlabel, message);
456    dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, error_popup,
457                                   args, ONE);
458    callbacks[0].closure = (XtPointer) error_popup;
459    XtSetArg(args[0], XtNcallback, callbacks);
460    XawDialogAddButton(dialog, "OK", DestroyPopup, (XtPointer) error_popup);
461    TheUsual(error_popup);
462    InsureVisibility(error_popup, dialog, x, y, !positioned, !positioned);
463    XtPopup(error_popup, XtGrabNone);
464}
465
466/*ARGSUSED*/
467void PopupWarningHandler(name, type, class, msg, params, num)
468    String name;
469    String type;
470    String class;
471    String msg;
472    String *params;
473    Cardinal *num;
474{
475    char *ptr;
476    int i;
477    String par[10];
478    char message[500];
479    char buffer[500];
480    static Boolean allowPopup = True; /* protect against recursion */
481
482    XtGetErrorDatabaseText(name, type, class, msg, buffer, 500);
483
484    if (params && num && *num) {
485        i = (*num <= 10) ? *num : 10;
486        bcopy((char*)params, (char*)par, i * sizeof(String));
487        bzero( &par[i], (10-i) * sizeof(String));
488        if (*num > 10)
489            par[9] = "(truncated)";
490        (void) sprintf(message, buffer, par[0], par[1], par[2], par[3],
491                       par[4], par[5], par[6], par[7], par[8], par[9]);
492        ptr = message;
493    } else {
494        ptr = buffer;
495    }
496    if (allowPopup) {
497        allowPopup = False;
498        PopupError((Widget)NULL, ptr);
499        allowPopup = True;
500    } else {
501        fprintf(stderr, ptr);
502    }
503}
Note: See TracBrowser for help on using the repository browser.