summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:49:23 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:49:23 +0000
commite87b0d408c8bef387afb069e25028d9a52c58a62 (patch)
tree0603114002777b275caa6d51a17e09e2ce657b85
Initial revision
-rw-r--r--Tests15
-rw-r--r--Xmessage-color.ad44
-rw-r--r--Xmessage.ad6
-rw-r--r--makeform.c347
-rw-r--r--readfile.c134
-rw-r--r--xmessage.c355
-rw-r--r--xmessage.man178
7 files changed, 1079 insertions, 0 deletions
diff --git a/Tests b/Tests
new file mode 100644
index 0000000..296a1c1
--- /dev/null
+++ b/Tests
@@ -0,0 +1,15 @@
+#! /bin/sh -v
+# $XConsortium: Tests,v 1.3 94/06/03 15:58:32 gildea Exp $
+xmessage this is standard usage, message on the command line
+echo this is a message from standard input | xmessage -file -
+xmessage -file Imakefile -buttons print,me -print
+# a file so long it requires a scrollbar
+xmessage -file xmessage.c
+xmessage -buttons "" no buttons, use delete window from window manager
+xmessage -buttons default,other -default default Type Return for the default
+xmessage -buttons many,buttons,determining,the,size,of,the,window short msg
+xmessage -buttons 14:14,102,3:3,27:27,105 pick a number; echo you picked $?
+# fun with resources...
+xmessage -buttons "" -xrm '*message.borderWidth: 0' \
+ -xrm '*Translations: #override <BtnDown>: exit(0)' \
+ click here to dismiss
diff --git a/Xmessage-color.ad b/Xmessage-color.ad
new file mode 100644
index 0000000..e8a2e4c
--- /dev/null
+++ b/Xmessage-color.ad
@@ -0,0 +1,44 @@
+! $XFree86: xc/programs/xmessage/Xmessage-color.ad,v 1.1 2002/10/15 02:26:12 dawes Exp $
+
+#include "Xmessage"
+
+*background: gray85
+*foreground: gray15
+
+*Scrollbar.thumb: vlines2
+*Scrollbar.width: 14
+*Scrollbar.foreground: rgb:a/5/5
+*Scrollbar.borderWidth: 0
+*Scrollbar.displayList:\
+foreground gray90;\
+lines 1,-1,-1,-1,-1,1;\
+foreground gray60;\
+lines -1,0,0,0,0,-1
+
+*Text.?.cursorColor: rgb:d/5/5
+*Text.borderColor: gray80
+*Text*background: gray96
+*Text*Scrollbar.background: gray80
+*Text.displayList:\
+foreground gray90;\
+lines 1,-1,-1,-1,-1,1;\
+foreground gray60;\
+lines -1,0,0,0,0,-1
+
+*Command.highlightThickness: 2
+*Command.internalWidth: 5
+*Command.internalHeight: 3
+*Command.borderColor: gray40
+*Command.shapeStyle: Rectangle
+*Command.background: gray80
+*Command.displayList:\
+foreground gray60;\
+lines 1,-1,-1,-1,-1,1;\
+foreground gray90;\
+lines -1,0,0,0,0,-1
+
+*Form.displayList:\
+foreground gray60;\
+lines 1,-1,-1,-1,-1,1;\
+foreground gray90;\
+lines -1,0,0,0,0,-1
diff --git a/Xmessage.ad b/Xmessage.ad
new file mode 100644
index 0000000..1028ed2
--- /dev/null
+++ b/Xmessage.ad
@@ -0,0 +1,6 @@
+! $XConsortium: Xmessage.ad,v 1.3 94/07/26 20:23:17 gildea Exp $
+*baseTranslations: #override :<Key>Return: default-exit()
+*message.scrollVertical: Always
+*message.scrollHorizontal: Never
+*Command.shapeStyle: oval
+*Command.highlightThickness: 1
diff --git a/makeform.c b/makeform.c
new file mode 100644
index 0000000..3820ebb
--- /dev/null
+++ b/makeform.c
@@ -0,0 +1,347 @@
+/* $XConsortium: makeform.c,v 1.6 95/01/04 16:28:51 gildea Exp $ */
+/*
+
+Copyright (c) 1988, 1991 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+/* $XFree86: xc/programs/xmessage/makeform.c,v 1.6 2002/11/22 03:56:39 paulo Exp $ */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Scrollbar.h>
+
+extern const char *ProgramName;
+extern int default_exitstatus;
+
+typedef struct _ButtonRecord {
+ char *name;
+ int exitstatus;
+ Boolean print_value;
+ Widget widget;
+} ButtonRecord;
+
+static void unquote_pairs (br, n)
+ register ButtonRecord *br;
+ int n;
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ register char *dst, *src;
+ register int quoted = 0;
+
+ for (src = dst = br->name; *src; src++) {
+ if (quoted) {
+ *dst++ = *src;
+ quoted = 0;
+ } else if (src[0] == '\\') {
+ quoted = 1;
+ } else {
+ *dst++ = *src;
+ }
+ }
+ *dst = '\0';
+ }
+ return;
+}
+
+/*
+ * parses string of form "yes:11,no:12, ..."
+ * sets brptr to point to parsed table
+ * returns 0 if successful, -1 if not
+ */
+static int parse_name_and_exit_code_list (buttonlist, brptr)
+ char *buttonlist;
+ ButtonRecord **brptr;
+{
+ register char *cp;
+ int shouldfind = 0, npairs = 0;
+ int default_exitcode = 100;
+ int quoted = 0;
+ ButtonRecord *br;
+ int len;
+ char *copy;
+
+ if (!buttonlist) return 0;
+
+ /*
+ * Figure out how many matches we will find so that we can preallocate
+ * space for button structures. If you add stripping of white space,
+ * make sure that you update this as well as the walking algorithm below.
+ */
+ if (buttonlist[0]) shouldfind++;
+ for (cp = buttonlist; *cp; cp++) {
+ if (quoted == 1) quoted = 0;
+ else if (*cp == '\\') quoted = 1;
+ else if (*cp == ',') shouldfind++;
+ }
+ len = (cp - buttonlist);
+
+ /*
+ * allocate space for button record
+ */
+ br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind);
+ if (!br) return -1;
+
+ cp = malloc (len + 1);
+ if (!cp) {
+ (void) free ((char *) br);
+ return -1;
+ }
+ copy = cp;
+ strcpy (copy, buttonlist);
+
+
+ /*
+ * walk down list separating into name:exitcode pairs
+ */
+ while (*cp) {
+ char *start, *colon, *comma;
+ int exitcode;
+
+ start = cp;
+ colon = comma = NULL;
+ exitcode = ++default_exitcode;
+ quoted = 0;
+
+ /* find the next name and exit code */
+ for (; *cp; cp++) {
+ if (quoted) quoted = 0;
+ else if (*cp == '\\') quoted = 1;
+ else if (*cp == ':') colon = cp;
+ else if (*cp == ',') {
+ comma = cp;
+ break;
+ }
+ }
+
+ /*
+ * If comma is NULL then we are at the end of the string. If colon
+ * is NULL, then there was no exit code given, so default to zero.
+ */
+
+ if (comma) *comma = '\0';
+
+ if (colon) {
+ exitcode = atoi (colon+1);
+ *colon = '\0';
+ }
+
+ /*
+ * make sure that we aren't about to stomp on memory
+ */
+ if (npairs >= shouldfind) {
+ fprintf (stderr,
+ "%s: internal error, found extra pairs (should be %d)\n",
+ ProgramName, shouldfind);
+ (void) free ((char *) br);
+ (void) free (copy);
+ return -1;
+ }
+
+ /*
+ * got it! start and exitcode contain the right values
+ */
+ br[npairs].name = start;
+ br[npairs].exitstatus = exitcode;
+ npairs++;
+
+ if (comma) cp++;
+ }
+
+
+ if (npairs != shouldfind) {
+ fprintf (stderr, "%s: internal error found %d instead of %d pairs\n",
+ ProgramName, npairs, shouldfind);
+ (void) free ((char *) br);
+ (void) free (copy);
+ return -1;
+ }
+
+ /*
+ * now, strip any quoted characters
+ */
+ unquote_pairs (br, npairs);
+ *brptr = br;
+ return npairs;
+}
+
+/* ARGSUSED */
+static void handle_button (w, closure, client_data)
+ Widget w;
+ XtPointer closure;
+ XtPointer client_data;
+{
+ ButtonRecord *br = (ButtonRecord *) closure;
+
+ if (br->print_value)
+ puts (br->name);
+ exit (br->exitstatus);
+}
+
+Widget make_queryform(parent, msgstr, msglen,
+ button_list, print_value, default_button,
+ max_width, max_height)
+ Widget parent; /* into whom widget should be placed */
+ char *msgstr; /* message string */
+ int msglen; /* characters in msgstr */
+ char *button_list; /* list of button title:status */
+ Boolean print_value; /* print button string on stdout? */
+ char *default_button; /* button activated by Return */
+ Dimension max_width;
+ Dimension max_height;
+{
+ ButtonRecord *br;
+ int npairs, i;
+ Widget form, text, prev;
+ Arg args[10];
+ Cardinal n, thisn;
+ char *shell_geom;
+ int x, y, geom_flags;
+ unsigned int shell_w, shell_h;
+
+ npairs = parse_name_and_exit_code_list (button_list, &br);
+
+ form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0);
+
+ text = XtVaCreateManagedWidget
+ ("message", asciiTextWidgetClass, form,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainRight,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ XtNdisplayCaret, False,
+ XtNlength, msglen,
+ XtNstring, msgstr,
+ NULL);
+ /*
+ * Did the user specify our geometry?
+ * If so, don't bother computing it ourselves, since we will be overridden.
+ */
+ XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL);
+ geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h);
+ if (!(geom_flags & WidthValue && geom_flags & HeightValue)) {
+ Dimension width, height, height_addons = 0;
+ Dimension scroll_size, border_width;
+ Widget label, scroll;
+ Position left, right, top, bottom;
+ char *tmp;
+ /*
+ * A Text widget is used for the automatic scroll bars.
+ * But Text widget doesn't automatically compute its size.
+ * The Label widget does that nicely, so we create one and examine it.
+ * This widget is never visible.
+ */
+ XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom,
+ XtNleftMargin, &left, XtNrightMargin, &right, NULL);
+ label = XtVaCreateWidget("message", labelWidgetClass, form,
+ XtNlabel, msgstr,
+ XtNinternalWidth, (left+right+1)/2,
+ XtNinternalHeight, (top+bottom+1)/2,
+ NULL);
+ XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL);
+ XtDestroyWidget(label);
+ if (max_width == 0)
+ max_width = .7 * WidthOfScreen(XtScreen(text));
+ if (max_height == 0)
+ max_height = .7 * HeightOfScreen(XtScreen(text));
+ if (width > max_width) {
+ width = max_width;
+ /* add in the height of any horizontal scroll bar */
+ scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text,
+ XtNorientation, XtorientHorizontal,
+ NULL);
+ XtVaGetValues(scroll, XtNheight, &scroll_size,
+ XtNborderWidth, &border_width, NULL);
+ XtDestroyWidget(scroll);
+ height_addons = scroll_size + border_width;
+ }
+
+ /* This fixes the xmessage assumption that the label widget and the
+ * text widget have the same size. In Xaw 7, the text widget has
+ * one extra pixel between lines.
+ * Xmessage is not internationalized, so the code bellow is harmless.
+ */
+ tmp = msgstr;
+ while (tmp != NULL && *tmp) {
+ ++tmp;
+ ++height;
+ tmp = strchr(tmp, '\n');
+ }
+
+ if (height > max_height) {
+ height = max_height;
+ /* add in the width of any vertical scroll bar */
+ scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text,
+ XtNorientation, XtorientVertical, NULL);
+ XtVaGetValues(scroll, XtNwidth, &scroll_size,
+ XtNborderWidth, &border_width, NULL);
+ XtDestroyWidget(scroll);
+ width += scroll_size + border_width;
+ }
+ height += height_addons;
+ XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL);
+ }
+ /*
+ * Create the buttons
+ */
+ n = 0;
+ XtSetArg (args[n], XtNleft, XtChainLeft); n++;
+ XtSetArg (args[n], XtNright, XtChainLeft); n++;
+ XtSetArg (args[n], XtNtop, XtChainBottom); n++;
+ XtSetArg (args[n], XtNbottom, XtChainBottom); n++;
+ XtSetArg (args[n], XtNfromVert, text); n++;
+ XtSetArg (args[n], XtNvertDistance, 5); n++;
+
+ prev = NULL;
+ for (i = 0; i < npairs; i++) {
+ thisn = n;
+ XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++;
+ prev = XtCreateManagedWidget (br[i].name, commandWidgetClass,
+ form, args, thisn);
+ br[i].widget = prev;
+ br[i].print_value = print_value;
+ XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]);
+ if (default_button && !strcmp(default_button, br[i].name)) {
+ Dimension border;
+
+ default_exitstatus = br[i].exitstatus;
+ XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL);
+ border *= 2;
+ XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL);
+ }
+ }
+ return form;
+}
diff --git a/readfile.c b/readfile.c
new file mode 100644
index 0000000..f8683be
--- /dev/null
+++ b/readfile.c
@@ -0,0 +1,134 @@
+/* $XConsortium: readfile.c,v 1.5 94/12/11 14:25:48 gildea Exp $ */
+/*
+
+Copyright (c) 1988, 1991 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+/* $XFree86: xc/programs/xmessage/readfile.c,v 1.2 2000/02/14 19:21:04 dawes Exp $ */
+
+#include <X11/Xos.h> /* for types.h */
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * get_data_from_file - read data from a file into a single buffer; meant
+ * for small files containing messages.
+ */
+static char *get_data_from_file (filename, len_return)
+ char *filename;
+ int *len_return;
+{
+ FILE *fp;
+ struct stat statbuf;
+ char *cp;
+ int count;
+
+ if (stat (filename, &statbuf) != 0 || statbuf.st_size < 0) {
+ perror(filename);
+ return NULL;
+ }
+
+ cp = malloc (statbuf.st_size + 1);
+ if (!cp) {
+ fprintf(stderr, "cannot get memory for message file\n");
+ return NULL;
+ }
+
+ fp = fopen (filename, "r");
+ if (!fp) {
+ perror(filename);
+ (void) free (cp);
+ return NULL;
+ }
+
+ count = fread (cp, 1, statbuf.st_size, fp);
+ if (count == 0 && statbuf.st_size != 0) {
+ perror(filename);
+ (void) free (cp);
+ (void) fclose (fp);
+ return NULL;
+ }
+
+ cp[count] = '\0'; /* since we allocated one extra */
+ *len_return = count;
+ (void) fclose (fp);
+ return cp;
+}
+
+/*
+ * get_data_from_stdin - read data from stdin into a single buffer.
+ */
+static char *get_data_from_stdin (len_return)
+ int *len_return;
+{
+ char *cp;
+ int count;
+ int allocated;
+ int n;
+
+ allocated = BUFSIZ;
+ cp = malloc (allocated + 1);
+ if (!cp) {
+ fprintf(stderr, "cannot get memory for message file\n");
+ return NULL;
+ }
+ count = 0;
+
+ while ((n = fread (cp + count, 1, BUFSIZ, stdin)) > 0) {
+ count += n;
+ /* Here count <= allocated. Prepare for next round. */
+ if (count + BUFSIZ > allocated) {
+ allocated = 2 * allocated;
+ cp = realloc (cp, allocated + 1);
+ if (!cp) {
+ fprintf(stderr, "cannot get memory for message file\n");
+ return NULL;
+ }
+ }
+ }
+
+ cp[count] = '\0'; /* since we allocated one extra */
+ *len_return = count;
+ return cp;
+}
+
+
+/*
+ * read_file - read data from indicated file and return pointer to malloced
+ * buffer. Returns NULL on error or if no such file.
+ */
+char *read_file (filename, len)
+ char *filename;
+ int *len; /* returned */
+{
+ if (filename[0] == '-' && filename[1] == '\0') {
+ return (get_data_from_stdin (len));
+ } else {
+ return (get_data_from_file (filename, len));
+ }
+}
diff --git a/xmessage.c b/xmessage.c
new file mode 100644
index 0000000..c5f367c
--- /dev/null
+++ b/xmessage.c
@@ -0,0 +1,355 @@
+static char*id="$XConsortium: xmessage.c,v 1.6 95/01/04 16:29:54 gildea Exp $";
+/*
+
+Copyright (c) 1988, 1991, 1994 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+/* $XFree86: xc/programs/xmessage/xmessage.c,v 1.4 2000/02/17 16:53:03 dawes Exp $ */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern char *read_file();
+extern Widget make_queryform();
+
+/*
+ * data used by xmessage
+ */
+
+const char *ProgramName;
+
+static struct _QueryResources {
+ char *file;
+ char *button_list;
+ char *default_button;
+ Boolean print_value;
+ Boolean center;
+ Boolean nearmouse;
+ int timeout_secs;
+ Dimension maxHeight;
+ Dimension maxWidth;
+} qres; /* initialized by resources below */
+
+#define offset(field) XtOffsetOf(struct _QueryResources, field)
+static XtResource resources[] = {
+ { "file", "File", XtRString, sizeof (char *),
+ offset(file), XtRString, (XtPointer) NULL },
+ { "buttons", "Buttons", XtRString, sizeof (char *),
+ offset(button_list), XtRString, (XtPointer) "okay:0" },
+ { "defaultButton", "DefaultButton", XtRString, sizeof (char *),
+ offset(default_button), XtRString, (XtPointer) NULL },
+ { "printValue", "PrintValue", XtRBoolean, sizeof (Boolean),
+ offset(print_value), XtRString, "false" },
+ { "center", "Center", XtRBoolean, sizeof (Boolean),
+ offset(center), XtRString, "false" },
+ { "nearMouse", "NearMouse", XtRBoolean, sizeof (Boolean),
+ offset(nearmouse), XtRString, "false" },
+ { "timeout", "Timeout", XtRInt, sizeof (int),
+ offset(timeout_secs), XtRInt, 0 },
+ { "maxHeight", "Maximum", XtRDimension, sizeof (Dimension),
+ offset(maxHeight), XtRDimension, 0 },
+ { "maxWidth", "Maximum", XtRDimension, sizeof (Dimension),
+ offset(maxWidth), XtRDimension, 0 },
+};
+#undef offset
+
+static XrmOptionDescRec optionList[] = {
+ { "-file", ".file", XrmoptionSepArg, (XPointer) NULL },
+ { "-buttons", ".buttons", XrmoptionSepArg, (XPointer) NULL },
+ { "-default", ".defaultButton", XrmoptionSepArg, (XPointer) NULL },
+ { "-print", ".printValue", XrmoptionNoArg, (XPointer) "on" },
+ { "-center", ".center", XrmoptionNoArg, (XPointer) "on" },
+ { "-nearmouse", ".nearMouse", XrmoptionNoArg, (XPointer) "on" },
+ { "-timeout", ".timeout", XrmoptionSepArg, (XPointer) NULL },
+};
+
+static String fallback_resources[] = {
+ "*baseTranslations: #override :<Key>Return: default-exit()",
+ "*message.Scroll: whenNeeded",
+ NULL};
+
+
+/*
+ * usage
+ */
+
+static void usage (outf)
+ FILE *outf;
+{
+ static const char *options[] = {
+" -file filename file to read message from, \"-\" for stdin",
+" -buttons string comma-separated list of label:exitcode",
+" -default button button to activate if Return is pressed",
+" -print print the button label when selected",
+" -center pop up at center of screen",
+" -nearmouse pop up near the mouse cursor",
+" -timeout secs exit with status 0 after \"secs\" seconds",
+"",
+NULL};
+ const char **cpp;
+
+ fprintf (outf, "usage: %s [-options] [message ...]\n\n",
+ ProgramName);
+ fprintf (outf, "where options include:\n");
+ for (cpp = options; *cpp; cpp++)
+ fprintf (outf, "%s\n", *cpp);
+ fprintf (outf, "%s\n", id+1);
+}
+
+/*
+ * Action to implement ICCCM delete_window and other translations.
+ * Takes one argument, the exit status.
+ */
+static Atom wm_delete_window;
+/* ARGSUSED */
+static void
+exit_action(w, event, params, num_params)
+ Widget w; /* unused */
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ int exit_status = 0;
+
+ if(event->type == ClientMessage
+ && event->xclient.data.l[0] != wm_delete_window)
+ return;
+
+ if (*num_params == 1)
+ exit_status = atoi(params[0]);
+ exit(exit_status);
+}
+
+int default_exitstatus = -1; /* value of button named by -default */
+
+/* ARGSUSED */
+static void
+default_exit_action(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ if (default_exitstatus >= 0)
+ exit(default_exitstatus);
+}
+
+static XtActionsRec actions_list[] = {
+ {"exit", exit_action},
+ {"default-exit", default_exit_action},
+};
+
+static String top_trans =
+ "<ClientMessage>WM_PROTOCOLS: exit(1)\n";
+
+/* assumes shell widget has already been realized */
+
+static void
+position_near(shell, x, y)
+ Widget shell;
+ int x, y;
+{
+ int max_x, max_y;
+ Dimension width, height, border;
+ int gravity;
+
+ /* some of this is copied from CenterWidgetOnPoint in Xaw/TextPop.c */
+
+ XtVaGetValues(shell,
+ XtNwidth, &width,
+ XtNheight, &height,
+ XtNborderWidth, &border,
+ NULL);
+
+ width += 2 * border;
+ height += 2 * border;
+
+ max_x = WidthOfScreen(XtScreen(shell));
+ max_y = HeightOfScreen(XtScreen(shell));
+
+ /* set gravity hint based on position on screen */
+ gravity = 1;
+ if (x > max_x/3) gravity += 1;
+ if (x > max_x*2/3) gravity += 1;
+ if (y > max_y/3) gravity += 3;
+ if (y > max_y*2/3) gravity += 3;
+
+ max_x -= width;
+ max_y -= height;
+
+ x -= ( (Position) width/2 );
+ if (x < 0) x = 0;
+ if (x > max_x) x = max_x;
+
+ y -= ( (Position) height/2 );
+ if (y < 0) y = 0;
+ if ( y > max_y ) y = max_y;
+
+ XtVaSetValues(shell,
+ XtNx, (Position)x,
+ XtNy, (Position)y,
+ XtNwinGravity, gravity,
+ NULL);
+}
+
+static void
+position_near_mouse(shell)
+ Widget shell;
+{
+ int x, y;
+ Window root, child;
+ int winx, winy;
+ unsigned int mask;
+
+ XQueryPointer(XtDisplay(shell), XtWindow(shell),
+ &root, &child, &x, &y, &winx, &winy, &mask);
+ position_near(shell, x, y);
+}
+
+static void
+position_near_center(shell)
+ Widget shell;
+{
+ position_near(shell,
+ WidthOfScreen(XtScreen(shell))/2,
+ HeightOfScreen(XtScreen(shell))/2);
+}
+
+/* ARGSUSED */
+static void
+time_out(client_data, iid)
+ XtPointer client_data;
+ XtIntervalId *iid;
+{
+ exit(0);
+}
+
+/*
+ * xmessage main program - make sure that there is a message,
+ * then create the query box and go. Callbacks take care of exiting.
+ */
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ Widget top, queryform;
+ XtAppContext app_con;
+ char *message_str;
+ int message_len;
+
+ ProgramName = argv[0];
+
+ XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
+
+ top = XtAppInitialize (&app_con, "Xmessage",
+ optionList, XtNumber(optionList), &argc, argv,
+ fallback_resources, NULL, 0);
+
+ XtGetApplicationResources (top, (XtPointer) &qres, resources,
+ XtNumber(resources), NULL, 0);
+
+ if (argc > 1 && !strcmp(argv[1], "-help")) {
+ usage(stdout);
+ exit(0);
+ }
+ if (argc == 1 && qres.file != NULL) {
+ message_str = read_file (qres.file, &message_len);
+ if (message_str == NULL) {
+ fprintf (stderr, "%s: problems reading message file\n",
+ ProgramName);
+ exit (1);
+ }
+ } else if (argc > 1 && qres.file == NULL) {
+ int i, len;
+ char *cp;
+
+ len = argc - 1; /* spaces between words and final NULL */
+ for (i=1; i<argc; i++)
+ len += strlen(argv[i]);
+ message_str = malloc(len);
+ if (!message_str) {
+ fprintf (stderr, "%s: cannot get memory for message string\n",
+ ProgramName);
+ exit (1);
+ }
+ cp = message_str;
+ for (i=1; i<argc; i++) {
+ strcpy(cp, argv[i]);
+ cp += strlen(argv[i]);
+ if (i != argc-1)
+ *cp++ = ' ';
+ else
+ *cp = '\0';
+ }
+ message_len = len;
+ } else {
+ usage(stderr);
+ exit(1);
+ }
+
+ wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", False);
+ XtAppAddActions(app_con, actions_list, XtNumber(actions_list));
+ XtOverrideTranslations(top, XtParseTranslationTable(top_trans));
+
+ /*
+ * create the query form; this is where most of the real work is done
+ */
+ queryform = make_queryform (top, message_str, message_len,
+ qres.button_list,
+ qres.print_value, qres.default_button,
+ qres.maxWidth, qres.maxHeight);
+ if (!queryform) {
+ fprintf (stderr,
+ "%s: unable to create query form with buttons: %s\n",
+ ProgramName, qres.button_list);
+ exit (1);
+ }
+
+ XtSetMappedWhenManaged(top, FALSE);
+ XtRealizeWidget(top);
+
+ /* do WM_DELETE_WINDOW before map */
+ XSetWMProtocols(XtDisplay(top), XtWindow(top), &wm_delete_window, 1);
+
+ if (qres.center)
+ position_near_center(top);
+ else if (qres.nearmouse)
+ position_near_mouse(top);
+
+ XtMapWidget(top);
+
+ if (qres.timeout_secs)
+ XtAppAddTimeOut(app_con, 1000*qres.timeout_secs, time_out, NULL);
+
+ XtAppMainLoop(app_con);
+
+ exit (0);
+}
diff --git a/xmessage.man b/xmessage.man
new file mode 100644
index 0000000..728161d
--- /dev/null
+++ b/xmessage.man
@@ -0,0 +1,178 @@
+.\" $XConsortium: xmessage.man,v 1.8 95/03/08 22:28:48 gildea Exp $
+.\"
+.\" $XFree86: xc/programs/xmessage/xmessage.man,v 1.3 2001/01/27 18:21:19 dawes Exp $
+.\"
+.TH XMESSAGE 1 __xorgversion__
+.SH NAME
+xmessage \- display a message or query in a window (X-based /bin/echo)
+.SH SYNOPSIS
+.B xmessage
+[
+.B \-buttons
+.I label1\fR[\fP\fB:\fPvalue1\fR]\fP\fB,\fPlabel2\fR[\fP\fB:\fPvalue2\fR]\fP\fB,\fP
+\&\|.\|.\|.
+] [
+.I options
+]
+.B \-file
+.I filename
+.br
+.B xmessage
+[
+.B \-buttons
+.I label1\fR[\fP\fB:\fPvalue1\fR]\fP\fB,\fPlabel2\fR[\fP\fB:\fPvalue2\fR]\fP\fB,\fP
+\&\|.\|.\|.
+] [
+.I options
+]
+.I message
+\&.\|.\|.
+.SH DESCRIPTION
+The
+.I xmessage
+program
+displays a window containing a message from the command line, a file,
+or standard input.
+Along the lower edge of the message is row
+of buttons; clicking the left mouse button
+on any of these buttons will cause \fIxmessage\fP to exit.
+Which button was pressed is returned in the exit status and,
+optionally, by writing the label of the button to standard output.
+.PP
+The program
+is typically used by shell scripts to display information to the user
+or to ask the user to make a choice.
+.PP
+Unless a size is specified, \fIxmessage\fP
+sizes itself to fit the message, up to a maximum size.
+If the message is too big for the window, \fIxmessage\fP will display
+scroll bars.
+.SH OPTIONS
+These are the command line options that \fIxmessage\fP understands.
+.TP 8
+.B \-buttons \fIbutton,button,.\|.\|.\fP
+This option will cause \fIxmessage\fP to create one button for each
+comma-separated \fIbutton\fP argument.
+The corresponding resource is \fBbuttons\fP.
+Each \fIbutton\fP consists of a label optionally followed by a colon
+and an exit value.
+The label is the name of the Command button widget created and will be the
+default text displayed to the user. Since this is the name of the widget
+it may be used to change any of the resources associated with that button.
+The exit value will be returned by \fIxmessage\fP
+if that button is selected. The default exit value is 100 plus the
+button number. Buttons are numbered from the left starting with one.
+The default string if no \fB\-buttons\fP option is given is \fBokay:0\fP.
+.TP 8
+.B \-default \fIlabel\fP
+Defines the button with a matching \fIlabel\fP to be the default.
+If not specified there is no default.
+The corresponding resource is \fBdefaultButton\fP.
+Pressing Return anywhere in the \fIxmessage\fP window will activate
+the default button.
+The default button has a wider border than the others.
+.TP 8
+.B \-file \fIfilename\fP
+File to display.
+The corresponding resource is \fBfile\fP.
+A \fIfilename\fP of `\fB\-\fP' reads from standard input.
+If this option is not supplied, \fIxmessage\fP will
+display all non-option arguments in the style of \fIecho\fP.
+Either \fB\-file\fP or a message on the command line
+should be provided, but not both.
+.TP 8
+.B \-print
+This will cause the program to write the label of the button pressed to
+standard output. Equivalent to setting the \fBprintValue\fP resource
+to TRUE.
+This is one way to get feedback as to which button was pressed.
+.TP 8
+.B \-center
+Pop up the window at the center of the screen.
+Equivalent to setting the \fBcenter\fP resource to TRUE.
+.TP 8
+.B \-nearmouse
+Pop up the window near the mouse cursor.
+Equivalent to setting the \fBnearMouse\fP resource to TRUE.
+.TP 8
+.B \-timeout \fIsecs\fP
+Exit with status 0 after \fIsecs\fP seconds if the user has not
+clicked on a button yet.
+The corresponding resource is \fBtimeout\fP.
+.SH "WIDGET HIERARCHY"
+Knowing the name and position in the hierarchy of each widget is
+useful when specifying resources for them. In the following chart, the
+class and name of each widget is given.
+.LP
+.nf
+Xmessage (xmessage)
+ Form form
+ Text message
+ Command (label1)
+ Command (label2)
+ .
+ .
+ .
+.fi
+.SH RESOURCES
+The program has a few top-level application resources that allow
+customizations that are specific to \fIxmessage\fP.
+.TP 8
+.B file
+A String specifying the file to display.
+.TP 8
+.B buttons
+A String specifying the buttons to display.
+See the \fB\-buttons\fP command-line option.
+.TP 8
+.B defaultButton
+A String specifying a default button by label.
+.TP 8
+.B printValue
+A Boolean value specifying whether the label of the
+button pressed to exit the program is written to standard output.
+The default is FALSE.
+.TP 8
+.B center
+A Boolean value specifying whether to pop up the window at the center
+of the screen. The default is FALSE.
+.TP 8
+.B nearMouse
+A Boolean value specifying whether to pop up the window near the mouse
+cursor. The default is FALSE.
+.TP 8
+.B timeout
+The number of seconds after which to exit with
+status 0. The default is 0, which means never time out.
+.TP 8
+.B "maxHeight (\fPclass\fB Maximum)
+The maximum height of the text part of the window in pixels,
+used if no size was specified in the geometry.
+The default is 0, which means use 70% of the height of the screen.
+.TP 8
+.B "maxWidth (\fPclass\fB Maximum)
+The maximum width of the text part of the window in pixels,
+used if no size was specified in the geometry.
+The default is 0, which means use 70% of the width of the screen.
+.SH ACTIONS
+.TP 8
+.B exit(\fIvalue\fP)
+exit immediately with an exit status of \fIvalue\fP (default 0). This
+action can be used with translations to provide alternate ways of
+exiting \fIxmessage\fP.
+.TP 8
+.B default-exit()
+exit immediately with the exit status specified by the default button.
+If there is no default button, this action has no effect.
+.SH "EXIT STATUS"
+If it detects an error, \fIxmessage\fP returns 1, so this value should
+not be used with a button.
+.SH "SEE ALSO"
+.IR X (__miscmansuffix__),
+.IR echo (1),
+.IR cat (1)
+.br
+.SH AUTHORS
+Chris Peterson, MIT Project Athena
+.br
+Stephen Gildea, X Consortium